From d5ea2598282fce6da8eafe4398cb03ad1719d759 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 5 Apr 2022 13:24:28 +0300 Subject: [PATCH] RISC-V: Combine 3 variables that depend on CPU amount into one IRQ_NSTACKS, ARCH_CPU_COUNT, CONFIG_SMP_NCPUS all relate to each other. However, a bit of clean up can be done and everything can be merged into SMP_NCPUS. The MPFS bootloader case works also as it requires only 1 IRQ stack for the hart that executes as bootloader. --- arch/risc-v/Kconfig | 4 - arch/risc-v/include/irq.h | 10 -- .../src/common/riscv_exception_common.S | 33 +++--- arch/risc-v/src/common/riscv_macros.S | 24 +++++ arch/risc-v/src/common/riscv_percpu.c | 102 +++++++++++++++--- arch/risc-v/src/common/riscv_percpu.h | 49 ++++++--- .../supervisor/riscv_dispatch_syscall.S | 14 +-- arch/risc-v/src/mpfs/Kconfig | 15 +-- arch/risc-v/src/mpfs/chip.h | 27 +++++ 9 files changed, 192 insertions(+), 86 deletions(-) diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 7eef93dd00..97c66bd56d 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -234,10 +234,6 @@ config ARCH_MPU_HAS_NAPOT bool "PMP supports NAPOT" default y if !PMP_HAS_LIMITED_FEATURES -config ARCH_CPU_COUNT - int "Amount of CPUs in SoC" - default 5 if ARCH_CHIP_MPFS - source "arch/risc-v/src/opensbi/Kconfig" source "arch/risc-v/src/common/Kconfig" diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 78799adae6..34f49dc00c 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -98,16 +98,6 @@ # define CONFIG_SYS_NNEST 2 #endif -/* Amount of interrupt stacks (amount of harts) */ - -#ifdef CONFIG_IRQ_NSTACKS -# define IRQ_NSTACKS CONFIG_IRQ_NSTACKS -#elif defined CONFIG_SMP -# define IRQ_NSTACKS CONFIG_SMP_NCPUS -#else -# define IRQ_NSTACKS 1 -#endif - /* Processor PC */ #define REG_EPC_NDX 0 diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 664c235770..a088b66c41 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -28,9 +28,14 @@ #include #include +#include + #include "chip.h" + #include "riscv_macros.S" +#include "riscv_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -99,27 +104,9 @@ exception_common: #if CONFIG_ARCH_INTERRUPTSTACK > 15 - /* Offset to hartid */ - - mv s0, a0 /* save cause */ -#ifdef CONFIG_SMP - jal x1, riscv_mhartid /* get hartid */ -#else - li a0, 0 -#endif - /* Switch to interrupt stack */ -#if IRQ_NSTACKS > 1 - li t0, (CONFIG_ARCH_INTERRUPTSTACK & ~15) - mul t0, a0, t0 - la a0, g_intstacktop - sub sp, a0, t0 -#else - la sp, g_intstacktop -#endif - - mv a0, s0 /* restore cause */ + setintstack t0, t1 /* Call interrupt handler in C */ @@ -165,6 +152,10 @@ exception_common: * Name: g_intstackalloc and g_intstacktop ****************************************************************************/ +/* Total required interrupt stack size */ + +#define STACK_ALLOC_SIZE (CONFIG_ARCH_INTERRUPTSTACK * CONFIG_SMP_NCPUS) + #if CONFIG_ARCH_INTERRUPTSTACK > 15 .bss .balign 16 @@ -173,8 +164,8 @@ exception_common: .type g_intstackalloc, object .type g_intstacktop, object g_intstackalloc: - .skip (((CONFIG_ARCH_INTERRUPTSTACK * IRQ_NSTACKS) + 8) & ~15) + .skip STACK_ALIGN_UP(STACK_ALLOC_SIZE) g_intstacktop: .size g_intstacktop, 0 - .size g_intstackalloc, ((CONFIG_ARCH_INTERRUPTSTACK * IRQ_NSTACKS) & ~15) + .size g_intstackalloc, STACK_ALIGN_DOWN(STACK_ALLOC_SIZE) #endif diff --git a/arch/risc-v/src/common/riscv_macros.S b/arch/risc-v/src/common/riscv_macros.S index 2243698690..7a675ab262 100644 --- a/arch/risc-v/src/common/riscv_macros.S +++ b/arch/risc-v/src/common/riscv_macros.S @@ -29,6 +29,11 @@ #include #include +#include + +#include "riscv_internal.h" +#include "riscv_percpu.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -128,3 +133,22 @@ REGLOAD x31, REG_X31(\out) /* t6 */ .endm + +/**************************************************************************** + * Name: setintstack + * + * Description: + * Set the current stack pointer to the "top" the interrupt stack. Works + * for single CPU case in flat mode. + * Must be provided by MCU-specific logic in the SMP case, or the kernel + * runs in supervisor mode (S-mode). + * + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 +#if !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) +.macro setintstack tmp0, tmp1 + la sp, g_intstacktop +.endm +#endif /* !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) */ +#endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ diff --git a/arch/risc-v/src/common/riscv_percpu.c b/arch/risc-v/src/common/riscv_percpu.c index 2b2b04d942..82c6fb0333 100644 --- a/arch/risc-v/src/common/riscv_percpu.c +++ b/arch/risc-v/src/common/riscv_percpu.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -31,6 +32,8 @@ #include #include +#include + #include "riscv_internal.h" #include "riscv_percpu.h" @@ -38,41 +41,75 @@ * Pre-processor Definitions ****************************************************************************/ -#define HART_CNT (CONFIG_ARCH_CPU_COUNT) +#define HART_CNT (CONFIG_SMP_NCPUS) +#define STACK_SIZE (STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK)) -static_assert(RISCV_PERCPU_HARTID_OFFSET == - offsetof(struct riscv_percpu_s, hartid), - "RISCV_PERCPU_HARTID_OFFSET with a wrong value"); +static_assert(RISCV_PERCPU_HARTID == offsetof(riscv_percpu_t, hartid), + "RISCV_PERCPU_HARTID offset is wrong"); +static_assert(RISCV_PERCPU_IRQSTACK == offsetof(riscv_percpu_t, irq_stack), + "RISCV_PERCPU_IRQSTACK offset is wrong"); /**************************************************************************** * Private Data ****************************************************************************/ -static struct riscv_percpu_s g_percpu[HART_CNT]; +static riscv_percpu_t g_percpu[HART_CNT]; +static sq_queue_t g_freelist; +static uintptr_t g_initialized; /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** * Name: riscv_percpu_init * * Description: - * Initialize the per CPU structures, should only be done on the boot - * hart. + * Initialize the per CPU structures, the first to get here does the init. * ****************************************************************************/ -void riscv_percpu_init(void) +static void riscv_percpu_init(void) { - uintptr_t i; + uintptr_t i; + uintptr_t initialized; + irqstate_t flags; + + /* Need to lock access during configuration */ + + flags = spin_lock_irqsave(NULL); + + /* Initialize if not done so already */ + + initialized = g_initialized; + g_initialized = 1; + + if (initialized == 1) + { + goto out_with_lock; + } + + sq_init(&g_freelist); for (i = 0; i < HART_CNT; i++) { - g_percpu[i].hartid = i; + /* Set interrupt stack (if any) */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + g_percpu[i].irq_stack = (uintptr_t)&g_intstacktop - i * STACK_SIZE; +#endif + + sq_addlast((struct sq_entry_s *) &g_percpu[i], &g_freelist); } + +out_with_lock: + spin_unlock_irqrestore(NULL, flags); } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /**************************************************************************** * Name: riscv_percpu_add_hart * @@ -86,13 +123,27 @@ void riscv_percpu_init(void) void riscv_percpu_add_hart(uintptr_t hartid) { - /* Hart IDs go from 0...4 */ + riscv_percpu_t *percpu; + irqstate_t flags; - DEBUGASSERT(hartid < HART_CNT); + /* Make sure we are initialized */ + + riscv_percpu_init(); + + /* Get free entry for this hart, this must not fail */ + + flags = spin_lock_irqsave(NULL); + percpu = (riscv_percpu_t *)sq_remfirst(&g_freelist); + spin_unlock_irqrestore(NULL, flags); + DEBUGASSERT(percpu); + + /* Assign hartid, stack has already been assigned */ + + percpu->hartid = hartid; /* Set the scratch register value to point to the scratch area */ - WRITE_CSR(CSR_SCRATCH, &g_percpu[hartid]); + WRITE_CSR(CSR_SCRATCH, percpu); /* Make sure it sticks */ @@ -118,5 +169,26 @@ uintptr_t riscv_percpu_get_hartid(void) DEBUGASSERT(scratch >= (uintptr_t) &g_percpu && scratch < (uintptr_t) &g_percpu + sizeof(g_percpu)); - return ((struct riscv_percpu_s *)scratch)->hartid; + return ((riscv_percpu_t *)scratch)->hartid; +} + +/**************************************************************************** + * Name: riscv_percpu_get_irqstack + * + * Description: + * Get harts own IRQ stack by reading it from the per CPU area. + * + * Returned Value: + * IRQ stack, or 0 if no IRQ stack is assigned + * + ****************************************************************************/ + +uintptr_t riscv_percpu_get_irqstack(void) +{ + uintptr_t scratch = READ_CSR(CSR_SCRATCH); + + DEBUGASSERT(scratch >= (uintptr_t) &g_percpu && + scratch < (uintptr_t) &g_percpu + sizeof(g_percpu)); + + return ((riscv_percpu_t *)scratch)->irq_stack; } diff --git a/arch/risc-v/src/common/riscv_percpu.h b/arch/risc-v/src/common/riscv_percpu.h index 76edfe6941..61e1ea66b1 100644 --- a/arch/risc-v/src/common/riscv_percpu.h +++ b/arch/risc-v/src/common/riscv_percpu.h @@ -38,7 +38,18 @@ * Pre-processor Definitions ****************************************************************************/ -#define RISCV_PERCPU_HARTID_OFFSET (0 * INT_REG_SIZE) +/* Can be used by assembly code to access the structure, example: + * + * Get percpu structure: + * 1: csrr a0, CSR_SCRATCH + * + * Get hartid: + * 2: REGLOAD a0, RISCV_PERCPU_HARTID(a0) + */ + +#define RISCV_PERCPU_LIST (0 * INT_REG_SIZE) +#define RISCV_PERCPU_HARTID (1 * INT_REG_SIZE) +#define RISCV_PERCPU_IRQSTACK (2 * INT_REG_SIZE) #ifndef __ASSEMBLY__ @@ -46,32 +57,25 @@ * Public Types ****************************************************************************/ -/* Per CPU save area. Access to this structure can be gained via the - * supervisor scratch (sscratch) register. Prior to this, every CPU that +/* Per CPU save area. Access to this structure can be gained via the scratch + * ([m/s]scratch) register. Prior to this, every CPU that * wishes to access this information must call riscv_percpu_add_hart() which - * will set up sscratch to point to the CPUs own area + * will set up [m/s]scratch to point to the CPUs own area */ struct riscv_percpu_s { - uintptr_t hartid; /* Hart ID */ + struct riscv_percpu_s *next; /* For sl list linkage */ + uintptr_t hartid; /* Hart ID */ + uintptr_t irq_stack; /* Interrupt stack */ }; +typedef struct riscv_percpu_s riscv_percpu_t; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ -/**************************************************************************** - * Name: riscv_percpu_init - * - * Description: - * Initialize the per CPU structures, should only be done on the boot - * hart. - * - ****************************************************************************/ - -void riscv_percpu_init(void); - /**************************************************************************** * Name: riscv_percpu_add_hart * @@ -99,5 +103,18 @@ void riscv_percpu_add_hart(uintptr_t hartid); uintptr_t riscv_percpu_get_hartid(void); +/**************************************************************************** + * Name: riscv_percpu_get_irqstack + * + * Description: + * Get harts own IRQ stack by reading it from the per CPU area. + * + * Returned Value: + * IRQ stack, or 0 if no IRQ stack is assigned + * + ****************************************************************************/ + +uintptr_t riscv_percpu_get_irqstack(void); + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H */ diff --git a/arch/risc-v/src/common/supervisor/riscv_dispatch_syscall.S b/arch/risc-v/src/common/supervisor/riscv_dispatch_syscall.S index 791048e3be..d4322eed40 100644 --- a/arch/risc-v/src/common/supervisor/riscv_dispatch_syscall.S +++ b/arch/risc-v/src/common/supervisor/riscv_dispatch_syscall.S @@ -27,6 +27,8 @@ #include #include +#include "chip.h" + #include "riscv_macros.S" /**************************************************************************** @@ -96,18 +98,10 @@ riscv_dispatch_syscall: mv a0, sp /* a0 = context */ +#if CONFIG_ARCH_INTERRUPTSTACK > 15 /* Switch to interrupt stack */ -#if CONFIG_ARCH_INTERRUPTSTACK > 15 -#if IRQ_NSTACKS > 1 - jal x1, riscv_mhartid /* get hartid */ - li t0, (CONFIG_ARCH_INTERRUPTSTACK & ~15) - mul t0, a0, t0 - la a0, g_intstacktop - sub sp, a0, t0 -#else - la sp, g_intstacktop -#endif + setintstack t0, t1 #endif /* Run the handler */ diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 14898d3045..d269a8b828 100755 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -46,17 +46,12 @@ config MPFS_BOOTLOADER ---help--- This NuttX image is used as a bootloader, which will boot only on one hart, putting the others in WFI -config IRQ_NSTACKS - int - depends on MPFS_BOOTLOADER - default 5 - config MPFS_OPENSBI - bool "Use OpenSBI" - depends on MPFS_BOOTLOADER && OPENSBI - default n - ---help--- - This uses a ld-envm-opensbi.script linker script and the mpfs_opensbi.c code to use external OpenSBI. + bool "Use OpenSBI" + depends on MPFS_BOOTLOADER && OPENSBI + default n + ---help--- + This uses a ld-envm-opensbi.script linker script and the mpfs_opensbi.c code to use external OpenSBI. config MPFS_HART0_SBI bool "HART0 boots via SBI" diff --git a/arch/risc-v/src/mpfs/chip.h b/arch/risc-v/src/mpfs/chip.h index 960c76b8f2..6c9d32e1ff 100755 --- a/arch/risc-v/src/mpfs/chip.h +++ b/arch/risc-v/src/mpfs/chip.h @@ -29,4 +29,31 @@ #include "mpfs_memorymap.h" +#include "riscv_percpu.h" + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#ifdef __ASSEMBLY__ + +/**************************************************************************** + * Name: setintstack + * + * Description: + * Set the current stack pointer to the "top" the correct interrupt stack + * for the current CPU. + * + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 +#if defined(CONFIG_SMP) || defined(CONFIG_ARCH_USE_S_MODE) +.macro setintstack tmp0, tmp1 + csrr \tmp0, CSR_SCRATCH + REGLOAD sp, RISCV_PERCPU_IRQSTACK(\tmp0) +.endm +#endif /* defined(CONFIG_SMP) || defined(CONFIG_ARCH_USE_S_MODE) */ +#endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ + +#endif /* __ASSEMBLY__ */ #endif /* __ARCH_RISCV_SRC_MPFS_CHIP_H */