From 8ff5b85252dbb8421cf7af169fe5003fd9e32ce9 Mon Sep 17 00:00:00 2001 From: Alvin Chang Date: Mon, 24 Jul 2023 15:52:16 +0800 Subject: [PATCH] drivers: plic: Refine interrupt targets from hartid to context The PLIC specification says the interrupt targets are usually hart contexts, where a hart context is a given privilege mode on a given hart. Therefore, PLIC driver should not only consider the HART ID, but also current privilege mode. Refine it by introducing the function called plic_get_context(), which translates the current HART ID into the PLIC context ID. We assume that each hart has M-mode and S-mode, therefore M-mode occupies even-numbered context ID, while S-mode occupies odd-numbered context ID. The translation can be extended by parsing device tree, submitted in future commits. Signed-off-by: Alvin Chang --- core/drivers/plic.c | 57 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/core/drivers/plic.c b/core/drivers/plic.c index 38f8a47b407..2e24a536495 100644 --- a/core/drivers/plic.c +++ b/core/drivers/plic.c @@ -35,23 +35,38 @@ ((base) + PLIC_PENDING_OFFSET + \ (4 * ((source) / 32)) \ ) -#define PLIC_ENABLE(base, source, hart) \ +#define PLIC_ENABLE(base, source, context) \ ((base) + PLIC_ENABLE_OFFSET + \ - SHIFT_U32(hart, PLIC_ENABLE_SHIFT_PER_TARGET) +\ + SHIFT_U32(context, PLIC_ENABLE_SHIFT_PER_TARGET) +\ (4 * ((source) / 32)) \ ) -#define PLIC_THRESHOLD(base, hart) \ +#define PLIC_THRESHOLD(base, context) \ ((base) + PLIC_THRESHOLD_OFFSET + \ - SHIFT_U32(hart, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ + SHIFT_U32(context, PLIC_THRESHOLD_SHIFT_PER_TARGET) \ ) -#define PLIC_COMPLETE(base, hart) \ +#define PLIC_COMPLETE(base, context) \ ((base) + PLIC_CLAIM_OFFSET + \ - SHIFT_U32(hart, PLIC_CLAIM_SHIFT_PER_TARGET) \ + SHIFT_U32(context, PLIC_CLAIM_SHIFT_PER_TARGET) \ ) -#define PLIC_CLAIM(base, hart) PLIC_COMPLETE(base, hart) +#define PLIC_CLAIM(base, context) PLIC_COMPLETE(base, context) register_phys_mem_pgdir(MEM_AREA_IO_SEC, PLIC_BASE, PLIC_REG_SIZE); +/* + * We assume that each hart has M-mode and S-mode, so the contexts look like: + * PLIC context 0 is hart 0 M-mode + * PLIC context 1 is hart 0 S-mode + * PLIC context 2 is hart 1 M-mode + * PLIC context 3 is hart 1 S-mode + * ... + */ +static uint32_t plic_get_context(size_t hartid) +{ + bool smode = IS_ENABLED(CFG_RISCV_S_MODE) ? true : false; + + return hartid * 2 + smode; +} + static bool __maybe_unused plic_is_pending(struct plic_data *pd, uint32_t source) { @@ -66,31 +81,41 @@ static void plic_set_pending(struct plic_data *pd, uint32_t source) static void plic_enable_interrupt(struct plic_data *pd, uint32_t source) { - io_setbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()), + uint32_t context = plic_get_context(get_core_pos()); + + io_setbits32(PLIC_ENABLE(pd->plic_base, source, context), BIT(source & 0x1f)); } static uint32_t __maybe_unused plic_get_interrupt_enable(struct plic_data *pd, uint32_t source) { - return io_read32(PLIC_ENABLE(pd->plic_base, source, get_core_pos())) & + uint32_t context = plic_get_context(get_core_pos()); + + return io_read32(PLIC_ENABLE(pd->plic_base, source, context)) & BIT(source & 0x1f); } static void plic_disable_interrupt(struct plic_data *pd, uint32_t source) { - io_clrbits32(PLIC_ENABLE(pd->plic_base, source, get_core_pos()), + uint32_t context = plic_get_context(get_core_pos()); + + io_clrbits32(PLIC_ENABLE(pd->plic_base, source, context), BIT(source & 0x1f)); } static uint32_t __maybe_unused plic_get_threshold(struct plic_data *pd) { - return io_read32(PLIC_THRESHOLD(pd->plic_base, get_core_pos())); + uint32_t context = plic_get_context(get_core_pos()); + + return io_read32(PLIC_THRESHOLD(pd->plic_base, context)); } static void plic_set_threshold(struct plic_data *pd, uint32_t threshold) { - io_write32(PLIC_THRESHOLD(pd->plic_base, get_core_pos()), threshold); + uint32_t context = plic_get_context(get_core_pos()); + + io_write32(PLIC_THRESHOLD(pd->plic_base, context), threshold); } static uint32_t __maybe_unused @@ -107,12 +132,16 @@ static void plic_set_priority(struct plic_data *pd, uint32_t source, static uint32_t plic_claim_interrupt(struct plic_data *pd) { - return io_read32(PLIC_CLAIM(pd->plic_base, get_core_pos())); + uint32_t context = plic_get_context(get_core_pos()); + + return io_read32(PLIC_CLAIM(pd->plic_base, context)); } static void plic_complete_interrupt(struct plic_data *pd, uint32_t source) { - io_write32(PLIC_CLAIM(pd->plic_base, get_core_pos()), source); + uint32_t context = plic_get_context(get_core_pos()); + + io_write32(PLIC_CLAIM(pd->plic_base, context), source); } static void plic_op_add(struct itr_chip *chip, size_t it,