From ca26c0f4d11517a098ac3afb9138764f0f0fdae4 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 18 Oct 2024 10:19:18 +0300 Subject: [PATCH 1/3] mpfs_start: Initialize percpu as soon as possible Otherwise querying for hartid doesn't work. --- arch/risc-v/src/mpfs/mpfs_start.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_start.c b/arch/risc-v/src/mpfs/mpfs_start.c index 1b9282247212d..a7559da1056a4 100644 --- a/arch/risc-v/src/mpfs/mpfs_start.c +++ b/arch/risc-v/src/mpfs/mpfs_start.c @@ -49,10 +49,14 @@ # define showprogress(c) #endif -#if defined (CONFIG_BUILD_KERNEL) && !defined (CONFIG_ARCH_USE_S_MODE) +#if defined(CONFIG_BUILD_KERNEL) && !defined(CONFIG_ARCH_USE_S_MODE) # error "Target requires kernel in S-mode, enable CONFIG_ARCH_USE_S_MODE" #endif +#if defined(CONFIG_SMP) && !defined(CONFIG_RISCV_PERCPU_SCRATCH) +# error "Target requires CONFIG_RISCV_PERCPU_SCRATCH if CONFIG_SMP is set" +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -99,6 +103,15 @@ void __mpfs_start(uint64_t mhartid) *dest++ = *src++; } +#ifdef CONFIG_RISCV_PERCPU_SCRATCH + /* Initialize the per CPU areas */ + + if (mhartid != 0) + { + riscv_percpu_add_hart(mhartid); + } +#endif /* CONFIG_RISCV_PERCPU_SCRATCH */ + /* Setup PLL if not already provided */ #ifdef CONFIG_MPFS_BOOTLOADER @@ -137,15 +150,6 @@ void __mpfs_start(uint64_t mhartid) mpfs_boardinitialize(); -#ifdef CONFIG_RISCV_PERCPU_SCRATCH - /* Initialize the per CPU areas */ - - if (mhartid != 0) - { - riscv_percpu_add_hart(mhartid); - } -#endif /* CONFIG_RISCV_PERCPU_SCRATCH */ - /* Initialize the caches. Should only be executed from E51 (hart 0) to be * functional. Consider the caches already configured if running without * the CONFIG_MPFS_BOOTLOADER -option. From 54556b939324eb39bb0c5fe9cf93c0031853a90e Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 11 Oct 2024 13:21:59 +0300 Subject: [PATCH 2/3] riscv/mpfs: Add boilerplate code for SMP --- arch/risc-v/Kconfig | 1 + arch/risc-v/src/mpfs/hardware/mpfs_clint.h | 2 ++ arch/risc-v/src/mpfs/mpfs_head.S | 15 ++++++--------- arch/risc-v/src/mpfs/mpfs_irq.c | 10 ++++++++++ arch/risc-v/src/mpfs/mpfs_shead.S | 12 ++++++++++-- arch/risc-v/src/mpfs/mpfs_start.c | 13 +++++++++++++ 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 052954b6d0c65..538e90a13323e 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -203,6 +203,7 @@ config ARCH_CHIP_MPFS select ARCH_RV_ISA_C select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU + select ARCH_HAVE_MULTICPU select ARCH_HAVE_MPU select ARCH_MMU_TYPE_SV39 select ARCH_HAVE_ADDRENV diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h index a15d849267902..b83c14e0d7f74 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h @@ -39,4 +39,6 @@ #define MPFS_CLINT_MTIME (MPFS_CLINT_BASE + 0xbff8) +#define RISCV_IPI MPFS_CLINT_MSIP0 + #endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_CLINT_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_head.S b/arch/risc-v/src/mpfs/mpfs_head.S index b223c84ec7605..e691be33f56d9 100644 --- a/arch/risc-v/src/mpfs/mpfs_head.S +++ b/arch/risc-v/src/mpfs/mpfs_head.S @@ -29,6 +29,7 @@ #include "chip.h" #include "mpfs_memorymap.h" #include "riscv_internal.h" +#include "riscv_macros.S" /**************************************************************************** * Public Symbols @@ -183,21 +184,17 @@ __start: /* Set stack pointer to the idle thread stack */ +#ifdef CONFIG_SMP + addi a1, a0, -1 /* Only cores 1...3 can participate in SMP */ + riscv_set_inital_sp MPFS_IDLESTACK_BASE, SMP_STACK_SIZE, a1 +#else la sp, MPFS_IDLESTACK_TOP +#endif /* Jump to __mpfs_start with mhartid in a0 */ tail __mpfs_start - /* We shouldn't return from __mpfs_start - * in case of return, loop forever. nop's added so can be seen in debugger - */ - -1: - nop - nop - j 1b - .global _init .global _fini diff --git a/arch/risc-v/src/mpfs/mpfs_irq.c b/arch/risc-v/src/mpfs/mpfs_irq.c index 5ee1a744ed8b6..ff5cec7f3ff85 100644 --- a/arch/risc-v/src/mpfs/mpfs_irq.c +++ b/arch/risc-v/src/mpfs/mpfs_irq.c @@ -33,6 +33,8 @@ #include #include "riscv_internal.h" +#include "riscv_ipi.h" + #include "mpfs.h" #include "mpfs_plic.h" @@ -96,6 +98,14 @@ void up_irqinitialize(void) riscv_exception_attach(); +#ifdef CONFIG_SMP + /* Clear IPI for CPU0 */ + + riscv_ipi_clear(0); + + up_enable_irq(RISCV_IRQ_SOFT); +#endif + #ifndef CONFIG_SUPPRESS_INTERRUPTS /* And finally, enable interrupts */ diff --git a/arch/risc-v/src/mpfs/mpfs_shead.S b/arch/risc-v/src/mpfs/mpfs_shead.S index b73127f4373f8..bd6e479cf1098 100644 --- a/arch/risc-v/src/mpfs/mpfs_shead.S +++ b/arch/risc-v/src/mpfs/mpfs_shead.S @@ -95,5 +95,13 @@ __start: /* Set stack pointer and jump to start */ - la sp, MPFS_IDLESTACK_TOP - j __mpfs_start +#ifdef CONFIG_SMP + addi a1, a0, -1 /* Only cores 1...3 can participate in SMP */ + riscv_set_inital_sp MPFS_IDLESTACK_BASE, SMP_STACK_SIZE, a1 +#else + la sp, MPFS_IDLESTACK_TOP +#endif + + /* Jump to __mpfs_start with mhartid in a0 */ + + tail __mpfs_start diff --git a/arch/risc-v/src/mpfs/mpfs_start.c b/arch/risc-v/src/mpfs/mpfs_start.c index a7559da1056a4..3e18a4b96b503 100644 --- a/arch/risc-v/src/mpfs/mpfs_start.c +++ b/arch/risc-v/src/mpfs/mpfs_start.c @@ -81,6 +81,13 @@ void __mpfs_start(uint64_t mhartid) riscv_fpuconfig(); } + /* CPU 0 handles the boot, the rest wait */ + + if (riscv_hartid_to_cpuid(mhartid) != 0) + { + goto cpux; + } + /* Clear .bss. We'll do this inline (vs. calling memset) just to be * certain that there are no issues with the state of global variables. */ @@ -185,6 +192,12 @@ void __mpfs_start(uint64_t mhartid) showprogress('a'); +cpux: + +#ifdef CONFIG_SMP + riscv_cpu_boot(riscv_hartid_to_cpuid(mhartid)); +#endif + while (true) { asm("WFI"); From db5f25720d4ce4415669d9bbed0ad6be0a327a83 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 18 Oct 2024 11:24:15 +0300 Subject: [PATCH 3/3] mpfs/mpfs_plic: Add procedure to initialize per hart PLIC state MPFS implements external interrupt control on a per-hart basis i.e. there are PLIC control registers for each hart separately. This means we need a procedure to initialize such registers for each hart individually, instead of only for the boot hart like it is now. Fix this by implementing mpfs_plic_init_hart which can be called by each hart as needed. Note: it is not a good idea to initialize all harts from the boot hart, as the boot hart may not know which harts are used by NuttX in AMP configuration. It is better that the hart initializes itself. Note: The hartid must be provided as explicit parameter, as it cannot be queried via riscv_mhartid() yet; the per-cpu structure is initialized later on which means riscv_mhartid() would return 0 for all harts except the boot hart. --- arch/risc-v/src/mpfs/mpfs_irq.c | 35 +------ arch/risc-v/src/mpfs/mpfs_plic.c | 147 +++++++++++++++++++++++++----- arch/risc-v/src/mpfs/mpfs_plic.h | 16 ++++ arch/risc-v/src/mpfs/mpfs_start.c | 10 ++ 4 files changed, 153 insertions(+), 55 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_irq.c b/arch/risc-v/src/mpfs/mpfs_irq.c index ff5cec7f3ff85..b0b3e1bb4c597 100644 --- a/arch/risc-v/src/mpfs/mpfs_irq.c +++ b/arch/risc-v/src/mpfs/mpfs_irq.c @@ -52,28 +52,9 @@ void up_irqinitialize(void) up_irq_save(); - /* Complete possibly claimed IRQs in PLIC (for current hart) in case - * of warm reboot, e.g. after a crash in the middle of IRQ handler. - * This has no effect on non-claimed or disabled interrupts. - */ + /* Initialize PLIC for current hart */ - uintptr_t claim_address = mpfs_plic_get_claimbase(); - - for (int irq = MPFS_IRQ_EXT_START; irq < NR_IRQS; irq++) - { - putreg32(irq - MPFS_IRQ_EXT_START, claim_address); - } - - /* Disable all global interrupts for current hart */ - - uintptr_t iebase = mpfs_plic_get_iebase(); - - putreg32(0x0, iebase + 0); - putreg32(0x0, iebase + 4); - putreg32(0x0, iebase + 8); - putreg32(0x0, iebase + 12); - putreg32(0x0, iebase + 16); - putreg32(0x0, iebase + 20); + mpfs_plic_init_hart(riscv_mhartid()); /* Colorize the interrupt stack for debug purposes */ @@ -82,18 +63,6 @@ void up_irqinitialize(void) riscv_stack_color(g_intstackalloc, intstack_size); #endif - /* Set priority for all global interrupts to 1 (lowest) */ - - for (int id = 1; id <= NR_IRQS; id++) - { - putreg32(1, (uintptr_t)(MPFS_PLIC_PRIORITY + (4 * id))); - } - - /* Set irq threshold to 0 (permits all global interrupts) */ - - uintptr_t threshold_address = mpfs_plic_get_thresholdbase(); - putreg32(0, threshold_address); - /* Attach the common interrupt handler */ riscv_exception_attach(); diff --git a/arch/risc-v/src/mpfs/mpfs_plic.c b/arch/risc-v/src/mpfs/mpfs_plic.c index 3de194c2e1c35..8bd555d8e699b 100644 --- a/arch/risc-v/src/mpfs/mpfs_plic.c +++ b/arch/risc-v/src/mpfs/mpfs_plic.c @@ -52,84 +52,90 @@ #endif /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: mpfs_plic_get_iebase + * Name: get_iebase * * Description: - * Context aware way to query PLIC interrupt enable base address + * Get base address for interrupt enable bits for a specific hart. + * + * Input Parameters: + * hartid - Hart ID to query. * * Returned Value: - * Interrupt enable base address + * Interrupt enable base address. * ****************************************************************************/ -uintptr_t mpfs_plic_get_iebase(void) +static uintptr_t get_iebase(uintptr_t hartid) { uintptr_t iebase; - uintptr_t hart_id = riscv_mhartid(); - if (hart_id == 0) + if (hartid == 0) { iebase = MPFS_PLIC_H0_MIE0; } else { iebase = MPFS_PLIC_H1_MIE0 + MPFS_PLIC_IEPRIV_OFFSET + - (hart_id - 1) * MPFS_HART_MIE_OFFSET; + (hartid - 1) * MPFS_HART_MIE_OFFSET; } return iebase; } /**************************************************************************** - * Name: mpfs_plic_get_claimbase + * Name: get_claimbase * * Description: - * Context aware way to query PLIC interrupt claim base address + * Get base address for interrupt claim for a specific hart. + * + * Input Parameters: + * hartid - Hart ID to query. * * Returned Value: - * Interrupt enable claim address + * Interrupt enable claim address. * ****************************************************************************/ -uintptr_t mpfs_plic_get_claimbase(void) +uintptr_t get_claimbase(uintptr_t hartid) { uintptr_t claim_address; - uintptr_t hart_id = riscv_mhartid(); - if (hart_id == 0) + if (hartid == 0) { claim_address = MPFS_PLIC_H0_MCLAIM; } else { claim_address = MPFS_PLIC_H1_MCLAIM + MPFS_PLIC_CLAIMPRIV_OFFSET + - (hart_id - 1) * MPFS_PLIC_NEXTHART_OFFSET; + (hartid - 1) * MPFS_PLIC_NEXTHART_OFFSET; } return claim_address; } /**************************************************************************** - * Name: mpfs_plic_get_thresholdbase + * Name: get_thresholdbase * * Description: - * Context aware way to query PLIC interrupt threshold base address + * Get base address for interrupt threshold for a specific hart. + * + * Input Parameters: + * hartid - Hart ID to query. * * Returned Value: - * Interrupt enable threshold address + * Interrupt enable threshold address. * ****************************************************************************/ -uintptr_t mpfs_plic_get_thresholdbase(void) +uintptr_t get_thresholdbase(uintptr_t hartid) { uintptr_t threshold_address; - uintptr_t hart_id = riscv_mhartid(); - if (hart_id == 0) + if (hartid == 0) { threshold_address = MPFS_PLIC_H0_MTHRESHOLD; } @@ -137,8 +143,105 @@ uintptr_t mpfs_plic_get_thresholdbase(void) { threshold_address = MPFS_PLIC_H1_MTHRESHOLD + MPFS_PLIC_THRESHOLDPRIV_OFFSET + - (hart_id - 1) * MPFS_PLIC_NEXTHART_OFFSET; + (hartid - 1) * MPFS_PLIC_NEXTHART_OFFSET; } return threshold_address; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_plic_init_hart + * + * Description: + * Initialize current hart's PLIC. + * + * Input Parameters: + * hartid - Hart ID to init. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void mpfs_plic_init_hart(uintptr_t hartid) +{ + /* Disable all global interrupts for current hart */ + + uintptr_t iebase = get_iebase(hartid); + + putreg32(0x0, iebase + 0); + putreg32(0x0, iebase + 4); + putreg32(0x0, iebase + 8); + putreg32(0x0, iebase + 12); + putreg32(0x0, iebase + 16); + putreg32(0x0, iebase + 20); + + /* Complete possibly claimed IRQs in PLIC (for current hart) in case + * of warm reboot, e.g. after a crash in the middle of IRQ handler. + * This has no effect on non-claimed or disabled interrupts. + */ + + uintptr_t claim_address = get_claimbase(hartid); + + for (int irq = MPFS_IRQ_EXT_START; irq < NR_IRQS; irq++) + { + putreg32(irq - MPFS_IRQ_EXT_START, claim_address); + } + + /* Set irq threshold to 0 (permits all global interrupts) */ + + uintptr_t threshold_address = get_thresholdbase(hartid); + putreg32(0, threshold_address); +} + +/**************************************************************************** + * Name: mpfs_plic_get_iebase + * + * Description: + * Context aware way to query PLIC interrupt enable base address + * + * Returned Value: + * Interrupt enable base address + * + ****************************************************************************/ + +uintptr_t mpfs_plic_get_iebase(void) +{ + return get_iebase(riscv_mhartid()); +} + +/**************************************************************************** + * Name: mpfs_plic_get_claimbase + * + * Description: + * Context aware way to query PLIC interrupt claim base address + * + * Returned Value: + * Interrupt enable claim address + * + ****************************************************************************/ + +uintptr_t mpfs_plic_get_claimbase(void) +{ + return get_claimbase(riscv_mhartid()); +} + +/**************************************************************************** + * Name: mpfs_plic_get_thresholdbase + * + * Description: + * Context aware way to query PLIC interrupt threshold base address + * + * Returned Value: + * Interrupt enable threshold address + * + ****************************************************************************/ + +uintptr_t mpfs_plic_get_thresholdbase(void) +{ + return get_thresholdbase(riscv_mhartid()); +} diff --git a/arch/risc-v/src/mpfs/mpfs_plic.h b/arch/risc-v/src/mpfs/mpfs_plic.h index 76d1d38294b02..b7a0910da879a 100644 --- a/arch/risc-v/src/mpfs/mpfs_plic.h +++ b/arch/risc-v/src/mpfs/mpfs_plic.h @@ -31,6 +31,22 @@ * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: mpfs_plic_init_hart + * + * Description: + * Initialize current hart's PLIC. + * + * Input Parameters: + * hartid - Hart ID to init. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void mpfs_plic_init_hart(uintptr_t hartid); + /**************************************************************************** * Name: mpfs_plic_get_iebase * diff --git a/arch/risc-v/src/mpfs/mpfs_start.c b/arch/risc-v/src/mpfs/mpfs_start.c index 3e18a4b96b503..fb82c2af016c8 100644 --- a/arch/risc-v/src/mpfs/mpfs_start.c +++ b/arch/risc-v/src/mpfs/mpfs_start.c @@ -195,6 +195,16 @@ void __mpfs_start(uint64_t mhartid) cpux: #ifdef CONFIG_SMP + /* Disable local interrupts */ + + up_irq_save(); + + /* Initialize local PLIC */ + + mpfs_plic_init_hart(mhartid); + + /* Then wait for the boot core to start us */ + riscv_cpu_boot(riscv_hartid_to_cpuid(mhartid)); #endif