drivers: intc: plic: fix IRQ on every hart regardless of mapping
Allow IRQs to work on every hart regardless of the mapping of the contexts. Add a test to validate the hart-context mapping. Signed-off-by: Yong Cong Sin <ycsin@meta.com> Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
This commit is contained in:
parent
8b066bcfe7
commit
475ff826d6
5 changed files with 93 additions and 24 deletions
|
|
@ -64,9 +64,11 @@
|
|||
|
||||
#ifdef CONFIG_TEST_INTC_PLIC
|
||||
#define INTC_PLIC_STATIC
|
||||
#define INTC_PLIC_STATIC_INLINE
|
||||
#else
|
||||
#define INTC_PLIC_STATIC static inline
|
||||
#endif
|
||||
#define INTC_PLIC_STATIC static
|
||||
#define INTC_PLIC_STATIC_INLINE static inline
|
||||
#endif /* CONFIG_TEST_INTC_PLIC */
|
||||
|
||||
typedef void (*riscv_plic_irq_config_func_t)(void);
|
||||
struct plic_config {
|
||||
|
|
@ -78,6 +80,7 @@ struct plic_config {
|
|||
uint32_t num_irqs;
|
||||
riscv_plic_irq_config_func_t irq_config_func;
|
||||
struct _isr_table_entry *isr_table;
|
||||
const uint32_t *const hart_context;
|
||||
};
|
||||
|
||||
struct plic_stats {
|
||||
|
|
@ -92,12 +95,12 @@ struct plic_data {
|
|||
static uint32_t save_irq;
|
||||
static const struct device *save_dev;
|
||||
|
||||
INTC_PLIC_STATIC uint32_t local_irq_to_reg_index(uint32_t local_irq)
|
||||
INTC_PLIC_STATIC_INLINE uint32_t local_irq_to_reg_index(uint32_t local_irq)
|
||||
{
|
||||
return local_irq >> LOG2(PLIC_REG_SIZE);
|
||||
}
|
||||
|
||||
INTC_PLIC_STATIC uint32_t local_irq_to_reg_offset(uint32_t local_irq)
|
||||
INTC_PLIC_STATIC_INLINE uint32_t local_irq_to_reg_offset(uint32_t local_irq)
|
||||
{
|
||||
return local_irq_to_reg_index(local_irq) * sizeof(uint32_t);
|
||||
}
|
||||
|
|
@ -109,9 +112,11 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev)
|
|||
return local_irq_to_reg_index(config->num_irqs) + 1;
|
||||
}
|
||||
|
||||
static inline uint32_t get_first_context(uint32_t hartid)
|
||||
static ALWAYS_INLINE uint32_t get_hart_context(const struct device *dev, uint32_t hartid)
|
||||
{
|
||||
return hartid == 0 ? 0 : (hartid * 2) - 1;
|
||||
const struct plic_config *config = dev->config;
|
||||
|
||||
return config->hart_context[hartid];
|
||||
}
|
||||
|
||||
static inline mem_addr_t get_context_en_addr(const struct device *dev, uint32_t cpu_num)
|
||||
|
|
@ -120,17 +125,13 @@ static inline mem_addr_t get_context_en_addr(const struct device *dev, uint32_t
|
|||
uint32_t hartid;
|
||||
/*
|
||||
* We want to return the irq_en address for the context of given hart.
|
||||
* If hartid is 0, we return the devices irq_en property, job done. If it is
|
||||
* greater than zero, we assume that there are two context's associated with
|
||||
* each hart: M mode enable, followed by S mode enable. We return the M mode
|
||||
* enable address.
|
||||
*/
|
||||
#if CONFIG_SMP
|
||||
hartid = _kernel.cpus[cpu_num].arch.hartid;
|
||||
#else
|
||||
hartid = arch_proc_id();
|
||||
#endif
|
||||
return config->irq_en + get_first_context(hartid) * CONTEXT_ENABLE_SIZE;
|
||||
return config->irq_en + get_hart_context(dev, hartid) * CONTEXT_ENABLE_SIZE;
|
||||
}
|
||||
|
||||
static inline mem_addr_t get_claim_complete_addr(const struct device *dev)
|
||||
|
|
@ -139,14 +140,9 @@ static inline mem_addr_t get_claim_complete_addr(const struct device *dev)
|
|||
|
||||
/*
|
||||
* We want to return the claim complete addr for the hart's context.
|
||||
* We are making a few assumptions here:
|
||||
* 1. for hart 0, return the first context claim complete.
|
||||
* 2. for any other hart, we assume they have two privileged mode contexts
|
||||
* which are contiguous, where the m mode context is first.
|
||||
* We return the m mode context.
|
||||
*/
|
||||
|
||||
return config->reg + get_first_context(arch_proc_id()) * CONTEXT_SIZE +
|
||||
return config->reg + get_hart_context(dev, arch_proc_id()) * CONTEXT_SIZE +
|
||||
CONTEXT_CLAIM;
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +158,7 @@ static inline mem_addr_t get_threshold_priority_addr(const struct device *dev, u
|
|||
hartid = arch_proc_id();
|
||||
#endif
|
||||
|
||||
return config->reg + (get_first_context(hartid) * CONTEXT_SIZE);
|
||||
return config->reg + (get_hart_context(dev, hartid) * CONTEXT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -571,8 +567,14 @@ SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands",
|
|||
irq_enable(DT_INST_IRQN(n)); \
|
||||
}
|
||||
|
||||
#define HART_CONTEXTS(i, n) IF_ENABLED(IS_EQ(DT_INST_IRQN_BY_IDX(n, i), DT_INST_IRQN(n)), (i,))
|
||||
#define PLIC_HART_CONTEXT_DECLARE(n) \
|
||||
INTC_PLIC_STATIC const uint32_t plic_hart_contexts_##n[DT_CHILD_NUM(DT_PATH(cpus))] = { \
|
||||
LISTIFY(DT_INST_NUM_IRQS(n), HART_CONTEXTS, (), n)}
|
||||
|
||||
#define PLIC_INTC_CONFIG_INIT(n) \
|
||||
PLIC_INTC_IRQ_FUNC_DECLARE(n); \
|
||||
PLIC_HART_CONTEXT_DECLARE(n); \
|
||||
static const struct plic_config plic_config_##n = { \
|
||||
.prio = PLIC_BASE_ADDR(n), \
|
||||
.irq_en = PLIC_BASE_ADDR(n) + CONTEXT_ENABLE_BASE, \
|
||||
|
|
@ -583,6 +585,7 @@ SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands",
|
|||
.num_irqs = DT_INST_PROP(n, riscv_ndev), \
|
||||
.irq_config_func = plic_irq_config_func_##n, \
|
||||
.isr_table = &_sw_isr_table[INTC_INST_ISR_TBL_OFFSET(n)], \
|
||||
.hart_context = plic_hart_contexts_##n, \
|
||||
}; \
|
||||
PLIC_INTC_IRQ_FUNC_DEFINE(n)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,4 +7,7 @@ config TEST_INTC_PLIC
|
|||
help
|
||||
Declare some intc_plic.c functions in the global scope for verification.
|
||||
|
||||
config TEST_INTC_PLIC_ALT_MAPPING
|
||||
bool "Test alternate hartid - context mapping"
|
||||
|
||||
source "Kconfig"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Meta Platforms
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/{
|
||||
soc {
|
||||
plic: interrupt-controller@c000000 {
|
||||
riscv,max-priority = <7>;
|
||||
riscv,ndev = < 1024 >;
|
||||
reg = <0x0c000000 0x04000000>;
|
||||
interrupts-extended = <
|
||||
&hlic0 0x0b
|
||||
&hlic1 0x0b &hlic1 0x09
|
||||
&hlic2 0x0b &hlic2 0x09
|
||||
&hlic3 0x0b &hlic3 0x09
|
||||
&hlic4 0x0b &hlic4 0x09
|
||||
&hlic5 0x0b &hlic5 0x09
|
||||
&hlic6 0x0b &hlic6 0x09
|
||||
&hlic7 0x0b &hlic7 0x09
|
||||
>;
|
||||
interrupt-controller;
|
||||
compatible = "sifive,plic-1.0.0";
|
||||
#address-cells = < 0x00 >;
|
||||
#interrupt-cells = < 0x02 >;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -29,3 +29,30 @@ ZTEST(intc_plic, test_local_irq_to_reg_offset)
|
|||
zassert_equal(4, local_irq_to_reg_offset(0x3f));
|
||||
zassert_equal(8, local_irq_to_reg_offset(0x40));
|
||||
}
|
||||
|
||||
ZTEST(intc_plic, test_hart_context_mapping)
|
||||
{
|
||||
extern const uint32_t plic_hart_contexts_0[];
|
||||
|
||||
if (!IS_ENABLED(CONFIG_TEST_INTC_PLIC_ALT_MAPPING)) {
|
||||
/* Based on the default qemu_riscv64 devicetree */
|
||||
zassert_equal(plic_hart_contexts_0[0], 0);
|
||||
zassert_equal(plic_hart_contexts_0[1], 2);
|
||||
zassert_equal(plic_hart_contexts_0[2], 4);
|
||||
zassert_equal(plic_hart_contexts_0[3], 6);
|
||||
zassert_equal(plic_hart_contexts_0[4], 8);
|
||||
zassert_equal(plic_hart_contexts_0[5], 10);
|
||||
zassert_equal(plic_hart_contexts_0[6], 12);
|
||||
zassert_equal(plic_hart_contexts_0[7], 14);
|
||||
} else {
|
||||
/* Based on the definition in the `alt_mapping.overlay` */
|
||||
zassert_equal(plic_hart_contexts_0[0], 0);
|
||||
zassert_equal(plic_hart_contexts_0[1], 1);
|
||||
zassert_equal(plic_hart_contexts_0[2], 3);
|
||||
zassert_equal(plic_hart_contexts_0[3], 5);
|
||||
zassert_equal(plic_hart_contexts_0[4], 7);
|
||||
zassert_equal(plic_hart_contexts_0[5], 9);
|
||||
zassert_equal(plic_hart_contexts_0[6], 11);
|
||||
zassert_equal(plic_hart_contexts_0[7], 13);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
common:
|
||||
platform_allow: qemu_riscv64
|
||||
tags:
|
||||
- drivers
|
||||
- interrupt
|
||||
- plic
|
||||
|
||||
tests:
|
||||
drivers.interrupt_controller.intc_plic:
|
||||
tags:
|
||||
- drivers
|
||||
- interrupt
|
||||
- plic
|
||||
platform_allow: qemu_riscv64
|
||||
drivers.interrupt_controller.intc_plic: {}
|
||||
drivers.interrupt_controller.intc_plic.alt_mapping:
|
||||
extra_args:
|
||||
DTC_OVERLAY_FILE="./alt_mapping.overlay"
|
||||
extra_configs:
|
||||
- CONFIG_TEST_INTC_PLIC_ALT_MAPPING=y
|
||||
|
|
|
|||
Loading…
Reference in a new issue