Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport v3.7-branch] drivers: intc: plic: fix IRQ on every hart regardless of mapping #78467

Merged
merged 1 commit into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 21 additions & 18 deletions drivers/interrupt_controller/intc_plic.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,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 {
Expand All @@ -77,6 +79,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 {
Expand All @@ -91,12 +94,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);
}
Expand All @@ -108,9 +111,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)
Expand All @@ -119,17 +124,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)
Expand All @@ -138,14 +139,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;
}

Expand All @@ -161,7 +157,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);
}

/**
Expand Down Expand Up @@ -556,8 +552,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, \
Expand All @@ -568,6 +570,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)

Expand Down
3 changes: 3 additions & 0 deletions tests/drivers/interrupt_controller/intc_plic/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
29 changes: 29 additions & 0 deletions tests/drivers/interrupt_controller/intc_plic/alt_mapping.overlay
Original file line number Diff line number Diff line change
@@ -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 >;
};
};
};
27 changes: 27 additions & 0 deletions tests/drivers/interrupt_controller/intc_plic/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
19 changes: 13 additions & 6 deletions tests/drivers/interrupt_controller/intc_plic/testcase.yaml
Original file line number Diff line number Diff line change
@@ -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