From 121943c3c7f1ba61be7807d08bd7f15f08e9cfbd Mon Sep 17 00:00:00 2001 From: Sylvain Gauthier <sylvain.gauthier@data61.csiro.au> Date: Fri, 19 Jul 2019 14:14:24 +1000 Subject: [PATCH] [SMP] Added PPI support for gic_v2 Correctly defined the macros to translate between virtual and hardware IRQs such that PPIs can be properly handled on gic_v2. It is now possible to create a per-core handler for PPIs on platforms using this GIC. --- config.cmake | 20 +++++++++---- configs/seL4Config.cmake | 4 ++- include/arch/arm/arch/machine/gic_v2.h | 39 ++++++++++++++++++++++---- include/object/structures_32.bf | 8 ++++-- include/object/structures_64.bf | 4 +++ src/arch/arm/machine/gic_v2.c | 9 +++--- src/plat/allwinnerA20/config.cmake | 1 + src/plat/apq8064/config.cmake | 1 + src/plat/exynos4/config.cmake | 1 + src/plat/exynos5/config.cmake | 1 + src/plat/imx6/config.cmake | 1 + src/plat/imx7/config.cmake | 1 + src/plat/odroidc2/config.cmake | 1 + src/plat/tk1/config.cmake | 1 + src/plat/tx1/config.cmake | 1 + src/plat/tx2/config.cmake | 1 + src/plat/zynq7000/config.cmake | 1 + src/plat/zynqmp/config.cmake | 1 + 18 files changed, 78 insertions(+), 18 deletions(-) diff --git a/config.cmake b/config.cmake index 7d2c0bcbb..b6535fd5b 100644 --- a/config.cmake +++ b/config.cmake @@ -50,15 +50,25 @@ if(DEFINED CONFIGURE_MAX_IRQ) # calculate the irq cnode size based on MAX_IRQ if("${KernelArch}" STREQUAL "riscv") set(MAX_IRQ "${CONFIGURE_PLIC_MAX_NUM_INT}") - math(EXPR MAX_IRQ "${MAX_IRQ} + 2") + math(EXPR MAX_NUM_IRQ "${MAX_IRQ} + 2") else() - set(MAX_IRQ "${CONFIGURE_MAX_IRQ}") + if( + DEFINED KernelMaxNumNodes + AND CONFIGURE_NUM_PPI GREATER "0" + AND "${KernelArch}" STREQUAL "arm" + ) + math( + EXPR MAX_NUM_IRQ + "(${KernelMaxNumNodes}-1)*${CONFIGURE_NUM_PPI} + ${CONFIGURE_MAX_IRQ}" + ) + else() + set(MAX_NUM_IRQ "${CONFIGURE_MAX_IRQ}") + endif() endif() set(BITS "0") - set(MAX "${MAX_IRQ}") - while(MAX GREATER "0") + while(MAX_NUM_IRQ GREATER "0") math(EXPR BITS "${BITS} + 1") - math(EXPR MAX "${MAX} >> 1") + math(EXPR MAX_NUM_IRQ "${MAX_NUM_IRQ} >> 1") endwhile() math(EXPR SLOTS "1 << ${BITS}") if("${SLOTS}" LESS "${MAX_IRQ}") diff --git a/configs/seL4Config.cmake b/configs/seL4Config.cmake index f44db7bd4..0d8425be4 100644 --- a/configs/seL4Config.cmake +++ b/configs/seL4Config.cmake @@ -98,6 +98,7 @@ endmacro() unset(CONFIGURE_PLIC_MAX_NUM_INT CACHE) unset(CONFIGURE_TIMER_FREQUENCY CACHE) unset(CONFIGURE_MAX_IRQ CACHE) +unset(CONFIGURE_NUM_PPI CACHE) unset(CONFIGURE_INTERRUPT_CONTROLLER CACHE) unset(CONFIGURE_TIMER CACHE) unset(CONFIGURE_SMMU CACHE) @@ -107,11 +108,12 @@ function(declare_default_headers) 0 CONFIGURE "" - "TIMER_FREQUENCY;MAX_IRQ;PLIC_MAX_NUM_INT;INTERRUPT_CONTROLLER;TIMER;SMMU" + "TIMER_FREQUENCY;MAX_IRQ;NUM_PPI;PLIC_MAX_NUM_INT;INTERRUPT_CONTROLLER;TIMER;SMMU" "" ) set(CONFIGURE_TIMER_FREQUENCY "${CONFIGURE_TIMER_FREQUENCY}" CACHE INTERNAL "") set(CONFIGURE_MAX_IRQ "${CONFIGURE_MAX_IRQ}" CACHE INTERNAL "") + set(CONFIGURE_NUM_PPI "${CONFIGURE_NUM_PPI}" CACHE INTERNAL "") set(CONFIGURE_PLIC_MAX_NUM_INT "${CONFIGURE_PLIC_MAX_NUM_INT}" CACHE INTERNAL "") set(CONFIGURE_INTERRUPT_CONTROLLER "${CONFIGURE_INTERRUPT_CONTROLLER}" CACHE INTERNAL "") set(CONFIGURE_TIMER "${CONFIGURE_TIMER}" CACHE INTERNAL "") diff --git a/include/arch/arm/arch/machine/gic_v2.h b/include/arch/arm/arch/machine/gic_v2.h index c4ee50aed..489b0dcd1 100644 --- a/include/arch/arm/arch/machine/gic_v2.h +++ b/include/arch/arm/arch/machine/gic_v2.h @@ -42,6 +42,30 @@ #define IRQ_MASK MASK(10u) #define IS_IRQ_VALID(X) (((X) & IRQ_MASK) < SPECIAL_IRQ_START) +#define NUM_PPI 32 +#define HW_IRQ_IS_PPI(irq) ((irq) < NUM_PPI) +#define IRQ_IS_PPI(irq) ((irq) < NUM_PPI*CONFIG_MAX_NUM_NODES) + +#if defined ENABLE_SMP_SUPPORT +/* Takes a target core and an irq number and converts it to the intState index */ +#define CORE_IRQ_TO_IDX(tgt, irq) (HW_IRQ_IS_PPI(irq) ? \ + (tgt)*NUM_PPI + (irq) : \ + (CONFIG_MAX_NUM_NODES-1)*NUM_PPI + (irq)) + +/* Takes an intSate index and extracts the hardware irq number */ +#define IDX_TO_IRQ(idx) (IRQ_IS_PPI(idx) ? \ + (idx) - ((idx)/NUM_PPI)*NUM_PPI : \ + (idx) - (CONFIG_MAX_NUM_NODES-1)*NUM_PPI) + +/* Takes an intState index and extracts the target CPU number */ +#define IDX_TO_CORE(idx) (IRQ_IS_PPI(idx) ? \ + (idx) / NUM_PPI : 0) +#else +#define CORE_IRQ_TO_IDX(tgt, irq) ((irq_t) (irq)) +#define IDX_TO_IRQ(idx) (idx) +#define IDX_TO_CORE(idx) 0 +#endif + /* Helpers for VGIC */ #define VGIC_HCR_EOI_INVALID_COUNT(hcr) (((hcr) >> 27) & 0x1f) #define VGIC_HCR_VGRP1DIE (1U << 7) @@ -188,7 +212,7 @@ static inline interrupt_t getActiveIRQ(void) irq = irqInvalid; } - return irq; + return CORE_IRQ_TO_IDX(SMP_TERNARY(getCurrentCPUIndex(), 0), irq); } /* @@ -203,19 +227,22 @@ static inline bool_t isIRQPending(void) static inline void maskInterrupt(bool_t disable, interrupt_t irq) { +#if defined ENABLE_SMP_SUPPORT && defined CONFIG_ARCH_ARM + assert(!(IRQ_IS_PPI(irq)) || (IDX_TO_CORE(irq) == getCurrentCPUIndex())); +#endif if (disable) { - dist_enable_clr(irq); + dist_enable_clr(IDX_TO_IRQ(irq)); } else { - dist_enable_set(irq); + dist_enable_set(IDX_TO_IRQ(irq)); } } static inline void ackInterrupt(irq_t irq) { assert(IS_IRQ_VALID(active_irq[SMP_TERNARY(getCurrentCPUIndex(), 0)]) - && (active_irq[SMP_TERNARY(getCurrentCPUIndex(), 0)] & IRQ_MASK) == irq); - if (is_irq_edge_triggered(irq)) { - dist_pending_clr(irq); + && (active_irq[SMP_TERNARY(getCurrentCPUIndex(), 0)] & IRQ_MASK) == IDX_TO_IRQ(irq)); + if (is_irq_edge_triggered(IDX_TO_IRQ(irq))) { + dist_pending_clr(IDX_TO_IRQ(irq)); } gic_cpuiface->eoi = active_irq[SMP_TERNARY(getCurrentCPUIndex(), 0)]; active_irq[SMP_TERNARY(getCurrentCPUIndex(), 0)] = IRQ_NONE; diff --git a/include/object/structures_32.bf b/include/object/structures_32.bf index 694184680..77ad3b316 100644 --- a/include/object/structures_32.bf +++ b/include/object/structures_32.bf @@ -88,8 +88,12 @@ block irq_control_cap { } block irq_handler_cap { - padding 24 - field capIRQ 8 +#ifdef ENABLE_SMP_SUPPORT + field capIRQ 32 +#else + padding 24 + field capIRQ 8 +#endif padding 24 field capType 8 diff --git a/include/object/structures_64.bf b/include/object/structures_64.bf index a421b467a..d1de87c19 100644 --- a/include/object/structures_64.bf +++ b/include/object/structures_64.bf @@ -130,8 +130,12 @@ block irq_control_cap { } block irq_handler_cap { +#ifdef ENABLE_SMP_SUPPORT + field capIRQ 64 +#else padding 52 field capIRQ 12 +#endif field capType 5 padding 59 diff --git a/src/arch/arm/machine/gic_v2.c b/src/arch/arm/machine/gic_v2.c index 31f702df3..af084e409 100644 --- a/src/arch/arm/machine/gic_v2.c +++ b/src/arch/arm/machine/gic_v2.c @@ -156,8 +156,8 @@ void setIRQTrigger(irq_t irq, bool_t trigger) /* in the gic_config, there is a 2 bit field for each irq, * setting the most significant bit of this field makes the irq edge-triggered, * while 0 indicates that it is level-triggered */ - word_t index = irq / 16u; - word_t offset = (irq % 16u) * 2; + word_t index = IDX_TO_IRQ(irq) / 16u; + word_t offset = (IDX_TO_IRQ(irq) % 16u) * 2; if (trigger) { /* set the bit */ gic_dist->config[index] |= BIT(offset + 1); @@ -214,13 +214,14 @@ void setIRQTarget(irq_t irq, seL4_Word target) { uint8_t targetList = 1 << target; uint8_t *targets = (void *)(gic_dist->targets); + word_t hwIRQ = IDX_TO_IRQ(irq); /* Return early if PPI */ - if (irq < SPI_START) { + if (IRQ_IS_PPI(irq)) { fail("PPI can't have designated target core\n"); return; } - targets[irq] = targetList; + targets[hwIRQ] = targetList; } #endif /* ENABLE_SMP_SUPPORT */ diff --git a/src/plat/allwinnerA20/config.cmake b/src/plat/allwinnerA20/config.cmake index ac136b433..18300ebfb 100644 --- a/src/plat/allwinnerA20/config.cmake +++ b/src/plat/allwinnerA20/config.cmake @@ -25,6 +25,7 @@ if(KernelPlatformAllwinnerA20) declare_default_headers( TIMER_FREQUENCY 24000000llu MAX_IRQ 122 + NUM_PPI 32 TIMER drivers/timer/allwinner.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/apq8064/config.cmake b/src/plat/apq8064/config.cmake index e12f56be8..05cc96072 100644 --- a/src/plat/apq8064/config.cmake +++ b/src/plat/apq8064/config.cmake @@ -26,6 +26,7 @@ if(KernelPlatformAPQ8064) declare_default_headers( TIMER_FREQUENCY 7000000llu MAX_IRQ 283 + NUM_PPI 32 TIMER drivers/timer/arm_generic.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/exynos4/config.cmake b/src/plat/exynos4/config.cmake index de18486bb..ec5343fdb 100644 --- a/src/plat/exynos4/config.cmake +++ b/src/plat/exynos4/config.cmake @@ -25,6 +25,7 @@ if(KernelPlatformExynos4) declare_default_headers( TIMER_FREQUENCY 24000000llu MAX_IRQ 159 + NUM_PPI 32 TIMER drivers/timer/exynos4412-mct.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/exynos5/config.cmake b/src/plat/exynos5/config.cmake index edb242e11..cd8919366 100644 --- a/src/plat/exynos5/config.cmake +++ b/src/plat/exynos5/config.cmake @@ -70,6 +70,7 @@ if(KernelPlatExynos5) declare_default_headers( TIMER_FREQUENCY 24000000llu MAX_IRQ 232 + NUM_PPI 32 TIMER drivers/timer/arm_generic.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/imx6/config.cmake b/src/plat/imx6/config.cmake index b68aed0e6..74a209150 100644 --- a/src/plat/imx6/config.cmake +++ b/src/plat/imx6/config.cmake @@ -44,6 +44,7 @@ if(KernelPlatImx6) TIMER_FREQUENCY 400000000llu MAX_IRQ 159 INTERRUPT_CONTROLLER arch/machine/gic_v2.h + NUM_PPI 32 TIMER drivers/timer/arm_priv.h ) endif() diff --git a/src/plat/imx7/config.cmake b/src/plat/imx7/config.cmake index bb0676c19..0a2795130 100644 --- a/src/plat/imx7/config.cmake +++ b/src/plat/imx7/config.cmake @@ -25,6 +25,7 @@ if(KernelPlatImx7) declare_default_headers( TIMER_FREQUENCY 8000000llu MAX_IRQ 159 + NUM_PPI 32 TIMER drivers/timer/arm_generic.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/odroidc2/config.cmake b/src/plat/odroidc2/config.cmake index f1ad42263..39cef8254 100644 --- a/src/plat/odroidc2/config.cmake +++ b/src/plat/odroidc2/config.cmake @@ -24,6 +24,7 @@ if(KernelPlatformOdroidc2) declare_default_headers( TIMER_FREQUENCY 24000000llu MAX_IRQ 250 + NUM_PPI 32 TIMER drivers/timer/arm_generic.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/tk1/config.cmake b/src/plat/tk1/config.cmake index 5a089f236..daad60762 100644 --- a/src/plat/tk1/config.cmake +++ b/src/plat/tk1/config.cmake @@ -35,6 +35,7 @@ if(KernelPlatformTK1) TIMER_FREQUENCY 12000000llu MAX_IRQ 191 INTERRUPT_CONTROLLER arch/machine/gic_v2.h + NUM_PPI 32 TIMER drivers/timer/arm_generic.h SMMU plat/machine/smmu.h ) endif() diff --git a/src/plat/tx1/config.cmake b/src/plat/tx1/config.cmake index 0f7e59470..9fbed57b6 100644 --- a/src/plat/tx1/config.cmake +++ b/src/plat/tx1/config.cmake @@ -27,6 +27,7 @@ if(KernelPlatformTx1) TIMER_FREQUENCY 19200000llu MAX_IRQ 224 INTERRUPT_CONTROLLER arch/machine/gic_v2.h + NUM_PPI 32 TIMER drivers/timer/arm_generic.h ) endif() diff --git a/src/plat/tx2/config.cmake b/src/plat/tx2/config.cmake index 94abfe597..fe0e1d157 100644 --- a/src/plat/tx2/config.cmake +++ b/src/plat/tx2/config.cmake @@ -30,6 +30,7 @@ if(KernelPlatformTx2) TIMER_FREQUENCY 31250000llu MAX_IRQ 383 INTERRUPT_CONTROLLER arch/machine/gic_v2.h + NUM_PPI 32 TIMER drivers/timer/arm_generic.h ) endif() diff --git a/src/plat/zynq7000/config.cmake b/src/plat/zynq7000/config.cmake index 3c270b674..d16a4e4f6 100644 --- a/src/plat/zynq7000/config.cmake +++ b/src/plat/zynq7000/config.cmake @@ -24,6 +24,7 @@ if(KernelPlatformZynq7000) declare_default_headers( TIMER_FREQUENCY 400000000llu MAX_IRQ 92 + NUM_PPI 32 TIMER drivers/timer/arm_priv.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) diff --git a/src/plat/zynqmp/config.cmake b/src/plat/zynqmp/config.cmake index aff1e9afa..571e1c0ff 100644 --- a/src/plat/zynqmp/config.cmake +++ b/src/plat/zynqmp/config.cmake @@ -45,6 +45,7 @@ if(KernelPlatformZynqmp) declare_default_headers( TIMER_FREQUENCY 100000000llu MAX_IRQ 187 + NUM_PPI 32 TIMER drivers/timer/arm_generic.h INTERRUPT_CONTROLLER arch/machine/gic_v2.h ) -- GitLab