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.
This commit is contained in:
Ville Juven 2022-04-05 13:24:28 +03:00 committed by Xiang Xiao
parent bb6279fe60
commit d5ea259828
9 changed files with 192 additions and 86 deletions

View File

@ -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"

View File

@ -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

View File

@ -28,9 +28,14 @@
#include <arch/irq.h>
#include <arch/mode.h>
#include <sys/types.h>
#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

View File

@ -29,6 +29,11 @@
#include <arch/arch.h>
#include <arch/irq.h>
#include <sys/types.h>
#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 */

View File

@ -24,6 +24,7 @@
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <arch/barriers.h>
#include <arch/mode.h>
@ -31,6 +32,8 @@
#include <assert.h>
#include <stdint.h>
#include <queue.h>
#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;
}

View File

@ -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 */

View File

@ -27,6 +27,8 @@
#include <nuttx/config.h>
#include <arch/mode.h>
#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 */

View File

@ -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"

View File

@ -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 */