You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/04/11 17:59:41 UTC

[incubator-nuttx] 01/03: RISC-V: Combine 3 variables that depend on CPU amount into one

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit d5ea2598282fce6da8eafe4398cb03ad1719d759
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Tue Apr 5 13:24:28 2022 +0300

    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 --
 arch/risc-v/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 ++++++----
 .../src/common/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 <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
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 <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 */
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 <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;
+
+  /* Make sure we are initialized */
+
+  riscv_percpu_init();
 
-  DEBUGASSERT(hartid < HART_CNT);
+  /* 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 <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 */
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 */