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

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

commit b35f7aed4891920a387bfdc3b8f3b9f5f60b5e55
Author: Inochi Amaoto <inochi...@outlook.com>
AuthorDate: Sun May 12 20:16:37 2024 +0800

    arch/risc-v: qemu: add AIA support
    
    Implement AIA support for qemu rv-virt.
    
    Signed-off-by: Inochi Amaoto <inochi...@outlook.com>
---
 .../risc-v/qemu-rv/boards/rv-virt/index.rst        |  16 +++-
 arch/risc-v/src/qemu-rv/chip.h                     |   1 +
 .../{qemu_rv_memorymap.h => qemu_rv_aplic.h}       |  20 ++--
 arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h   |   2 +
 .../src/qemu-rv/hardware/qemu_rv_memorymap.h       |   8 ++
 arch/risc-v/src/qemu-rv/qemu_rv_irq.c              |  99 +++++++++++++++++++-
 arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c     | 102 ++++++++++++++++-----
 7 files changed, 210 insertions(+), 38 deletions(-)

diff --git a/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst 
b/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst
index 9a17aae940..cc9b7aa0b9 100644
--- a/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst
+++ b/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst
@@ -34,7 +34,21 @@ Build and install ``qemu``::
   $ make
   $ sudo make install
 
-QEMU 7.2.9 or later and OpenSBI v1.1 or later (usually shipped with QEMU) is 
required, to support RISC-V "Sstc" Extension. It is also recommended to use the 
latest QEMU and OpenSBI.
+Minimum Requirement
+===================
+
+The table below lists all the minimum versions for QEMU and OpenSBI.
+For stability, it is also recommended to use the latest QEMU and OpenSBI.
+
++----------------------------+--------------+-----------------+
+| Extension                  | QEMU Version | OpenSBI Version |
++============================+==============+=================+
+| No extension               | 6.2.0        | v1.0            |
++----------------------------+--------------+-----------------+
+| SSTC                       | 7.2.9        | v1.1            |
++----------------------------+--------------+-----------------+
+| AIA                        | 8.2.0        | v1.2            |
++----------------------------+--------------+-----------------+
 
 For users who wish to use their own OpenSBI, please refer to `OpenSBI 
repository <https://github.com/riscv-software-src/opensbi>`_.
 
diff --git a/arch/risc-v/src/qemu-rv/chip.h b/arch/risc-v/src/qemu-rv/chip.h
index 604aca3c2f..005ce39459 100644
--- a/arch/risc-v/src/qemu-rv/chip.h
+++ b/arch/risc-v/src/qemu-rv/chip.h
@@ -34,6 +34,7 @@
 #include "hardware/qemu_rv_clint.h"
 #include "hardware/qemu_rv_memorymap.h"
 #include "hardware/qemu_rv_plic.h"
+#include "hardware/qemu_rv_aplic.h"
 
 #include "riscv_internal.h"
 #include "riscv_percpu.h"
diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h 
b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
similarity index 71%
copy from arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
copy to arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
index ce821fe32c..699757abaa 100644
--- a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
+++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
+ * arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,19 +18,19 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_MEMORYMAP_H
-#define __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_MEMORYMAP_H
+#ifndef __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H
+#define __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H
 
 /****************************************************************************
- * Pre-processor Definitions
+ * Included Files
  ****************************************************************************/
 
-/* Register Base Address ****************************************************/
+#include <nuttx/config.h>
 
-#define QEMU_RV_CLINT_BASE   0x02000000
-#define QEMU_RV_ACLINT_BASE  0x02f00000
-#define QEMU_RV_PLIC_BASE    0x0c000000
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
 
-#define QEMU_RV_RESET_BASE   0x100000
+#define QEMU_RV_APLIC_NR_IRQ      0x60
 
-#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_MEMORYMAP_H */
+#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H */
diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h 
b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h
index 65014cc26c..b385ebd08c 100644
--- a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h
+++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h
@@ -34,10 +34,12 @@
 #define RISCV_CLINT_MSIP        QEMU_RV_CLINT_MSIP
 #define RISCV_ACLINT_SSIP       QEMU_RV_ACLINT_SSIP
 
+#ifndef CONFIG_ARCH_RV_USE_IMSIC_IPI
 #ifdef CONFIG_ARCH_USE_S_MODE
 #  define RISCV_IPI             RISCV_ACLINT_SSIP
 #else
 #  define RISCV_IPI             RISCV_CLINT_MSIP
 #endif
+#endif
 
 #endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_CLINT_H */
diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h 
b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
index ce821fe32c..420cefefe9 100644
--- a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
+++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h
@@ -33,4 +33,12 @@
 
 #define QEMU_RV_RESET_BASE   0x100000
 
+#ifdef CONFIG_ARCH_USE_S_MODE
+#  define QEMU_RV_APLIC_BASE   0x0d000000
+#  define QEMU_RV_IMSIC_BASE   0x28000000
+#else
+#  define QEMU_RV_APLIC_BASE   0x0c000000
+#  define QEMU_RV_IMSIC_BASE   0x24000000
+#endif
+
 #endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_MEMORYMAP_H */
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c 
b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
index 202cedab44..145a56d591 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
@@ -34,6 +34,7 @@
 
 #include "riscv_internal.h"
 #include "riscv_ipi.h"
+#include "riscv_aia.h"
 #include "chip.h"
 
 /****************************************************************************
@@ -52,8 +53,12 @@ void up_irqinitialize(void)
 
   /* Disable all global interrupts */
 
+#ifndef CONFIG_ARCH_RV_HAVE_APLIC
   putreg32(0x0, QEMU_RV_PLIC_ENABLE1);
   putreg32(0x0, QEMU_RV_PLIC_ENABLE2);
+#else
+  riscv_aplic_disable_irqs(QEMU_RV_APLIC_BASE, QEMU_RV_APLIC_NR_IRQ);
+#endif
 
   /* Colorize the interrupt stack for debug purposes */
 
@@ -62,10 +67,31 @@ void up_irqinitialize(void)
   riscv_stack_color(g_intstackalloc, intstack_size);
 #endif
 
-  /* Set priority for all global interrupts to 1 (lowest) */
-
   int id;
 
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+  /* Set default IRQ target hart index to 0 and EIID */
+
+  for (id = 0; id < QEMU_RV_APLIC_NR_IRQ; id++)
+    {
+      riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, id + 1, 0, id + 1);
+    }
+
+  riscv_aplic_init_msi(QEMU_RV_APLIC_BASE, QEMU_RV_IMSIC_BASE, 0, 3, 0, 0);
+#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
+  /* Set default IRQ target hart index to 0 and priority */
+
+  for (id = 0; id < QEMU_RV_APLIC_NR_IRQ; id++)
+    {
+      riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, id + 1,
+                                RISCV_APLIC_DEFAULT_PRIORITY, 0);
+    }
+
+  riscv_aplic_init(QEMU_RV_APLIC_BASE, RISCV_APLIC_ENABLE_IDELIVERY,
+                                       RISCV_APLIC_ENABLE_ITHRESHOLD);
+#else
+  /* Set priority for all global interrupts to 1 (lowest) */
+
   for (id = 1; id <= 52; id++)
     {
       putreg32(1, (uintptr_t)(QEMU_RV_PLIC_PRIORITY + 4 * id));
@@ -74,6 +100,7 @@ void up_irqinitialize(void)
   /* Set irq threshold to 0 (permits all global interrupts) */
 
   putreg32(0, QEMU_RV_PLIC_THRESHOLD);
+#endif
 
   /* Attach the common interrupt handler */
 
@@ -84,8 +111,12 @@ void up_irqinitialize(void)
 
   riscv_ipi_clear(0);
 
+#ifdef CONFIG_ARCH_RV_USE_IMSIC_IPI
+  riscv_imsic_local_eie_enable(RISCV_IMSIC_IPI_ID);
+#else
   up_enable_irq(RISCV_IRQ_SOFT);
 #endif
+#endif
 
 #ifndef CONFIG_SUPPRESS_INTERRUPTS
 
@@ -119,6 +150,24 @@ void up_disable_irq(int irq)
 
       CLEAR_CSR(CSR_IE, IE_TIE);
     }
+  else if (irq == RISCV_IRQ_EXT)
+    {
+      /* Read m/sstatus & clear external interrupt enable in m/sie */
+
+      CLEAR_CSR(CSR_IE, IE_EIE);
+
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+      /* Set IMSIC irq threshold to 0 (permits all global interrupts) */
+
+      riscv_imsic_csr_write(ISELECT_EITHRESHOLD,
+                            RISCV_IMSIC_DISABLE_EITHRESHOLD);
+
+      /* Enable irq delivery for IMSIC */
+
+      riscv_imsic_csr_write(ISELECT_EIDELIVERY,
+                            RISCV_IMSIC_DISABLE_EIDELIVERY);
+#endif
+    }
   else if (irq > RISCV_IRQ_EXT)
     {
       extirq = irq - RISCV_IRQ_EXT;
@@ -127,8 +176,15 @@ void up_disable_irq(int irq)
 
       if (0 <= extirq && extirq <= 63)
         {
+#ifndef CONFIG_ARCH_RV_HAVE_APLIC
           modifyreg32(QEMU_RV_PLIC_ENABLE1 + (4 * (extirq / 32)),
                       1 << (extirq % 32), 0);
+#else
+          riscv_aplic_disable_irq(QEMU_RV_APLIC_BASE, extirq);
+#endif
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+          riscv_imsic_local_eie_disable(extirq);
+#endif
         }
       else
         {
@@ -161,6 +217,24 @@ void up_enable_irq(int irq)
 
       SET_CSR(CSR_IE, IE_TIE);
     }
+  else if (irq == RISCV_IRQ_EXT)
+    {
+      /* Read m/sstatus & set external interrupt enable in m/sie */
+
+      SET_CSR(CSR_IE, IE_EIE);
+
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+      /* Set IMSIC irq threshold to 0 (permits all global interrupts) */
+
+      riscv_imsic_csr_write(ISELECT_EITHRESHOLD,
+                            RISCV_IMSIC_ENABLE_EITHRESHOLD);
+
+      /* Enable irq delivery for IMSIC */
+
+      riscv_imsic_csr_write(ISELECT_EIDELIVERY,
+                            RISCV_IMSIC_ENABLE_EIDELIVERY);
+#endif
+    }
   else if (irq > RISCV_IRQ_EXT)
     {
       extirq = irq - RISCV_IRQ_EXT;
@@ -169,8 +243,18 @@ void up_enable_irq(int irq)
 
       if (0 <= extirq && extirq <= 63)
         {
+#ifndef CONFIG_ARCH_RV_HAVE_APLIC
           modifyreg32(QEMU_RV_PLIC_ENABLE1 + (4 * (extirq / 32)),
                       0, 1 << (extirq % 32));
+#else
+          riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, extirq,
+                                    RISCV_APLIC_SOURCECFG_SM_EDGE_RISE,
+                                    riscv_mhartid());
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+          riscv_imsic_local_eie_enable(extirq);
+#endif
+          riscv_aplic_enable_irq(QEMU_RV_APLIC_BASE, extirq);
+#endif
         }
       else
         {
@@ -185,11 +269,20 @@ irqstate_t up_irq_enable(void)
 
   /* Enable external interrupts (mie/sie) */
 
-  SET_CSR(CSR_IE, IE_EIE);
+  up_enable_irq(RISCV_IRQ_EXT);
 
   /* Read and enable global interrupts (M/SIE) in m/sstatus */
 
   oldstat = READ_AND_SET_CSR(CSR_STATUS, STATUS_IE);
 
+  /* Enable APLIC irq */
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+  modifyreg32(QEMU_RV_APLIC_BASE + RISCV_APLIC_DOMAINCFG, 0x0,
+              RISCV_APLIC_DOMAINCFG_IE | RISCV_APLIC_DOMAINCFG_DM);
+#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
+  modifyreg32(QEMU_RV_APLIC_BASE + RISCV_APLIC_DOMAINCFG, 0x0,
+              RISCV_APLIC_DOMAINCFG_IE);
+#endif
+
   return oldstat;
 }
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c 
b/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c
index e397d74223..1821a4cd5b 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 
 #include "riscv_internal.h"
+#include "riscv_aia.h"
 #include "hardware/qemu_rv_memorymap.h"
 #include "hardware/qemu_rv_plic.h"
 
@@ -39,49 +40,102 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#ifdef CONFIG_ARCH_RV32
-#  define RV_IRQ_MASK 27
-#else
-#  define RV_IRQ_MASK 59
-#endif
-
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
-/****************************************************************************
- * riscv_dispatch_irq
- ****************************************************************************/
-
-void *riscv_dispatch_irq(uintreg_t vector, uintreg_t *regs)
+#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
+static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
 {
-  int irq = (vector >> RV_IRQ_MASK) | (vector & 0xf);
+  int extirq;
 
-  /* Firstly, check if the irq is machine external interrupt */
+  while ((extirq = SWAP_CSR(CSR_TOPEI, 0)) != 0)
+    {
+      extirq = (extirq >> TOPI_IID_SHIFT) + irq;
+      regs = riscv_doirq(extirq, regs);
+    }
+
+  return regs;
+}
+#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
+static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
+{
+  int extirq;
+  int hartid = riscv_mhartid();
+  uintptr_t aplic_base = RISCV_APLIC_IDC(QEMU_RV_APLIC_BASE, hartid) +
+                            RISCV_APLIC_IDC_CLAIMI;
 
-  if (RISCV_IRQ_EXT == irq)
+  while ((extirq = getreg32(aplic_base)) != 0)
     {
-      uintptr_t val = getreg32(QEMU_RV_PLIC_CLAIM);
+      extirq = (extirq >> RISCV_APLIC_IDC_TOPI_ID_SHIFT) + irq;
+      regs = riscv_doirq(extirq, regs);
+    }
 
-      /* Add the value to nuttx irq which is offset to the mext */
+  return regs;
+}
+#else
+static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
+{
+  int extirq;
 
-      irq += val;
+  while ((extirq = getreg32(QEMU_RV_PLIC_CLAIM)) != 0)
+    {
+      regs = riscv_doirq(irq + extirq, regs);
+      putreg32(extirq, QEMU_RV_PLIC_CLAIM);
     }
 
-  /* EXT means no interrupt */
+  return regs;
+}
+#endif
 
-  if (RISCV_IRQ_EXT != irq)
+#ifdef CONFIG_ARCH_RV_EXT_AIA
+static void *riscv_dispatch_async_irq(uintreg_t irq, uintreg_t *regs)
+{
+  while ((irq = READ_CSR(CSR_TOPI)) != 0)
     {
-      /* Deliver the IRQ */
+      irq = (irq >> TOPI_IID_SHIFT) + RISCV_IRQ_ASYNC;
+
+      if (RISCV_IRQ_EXT == irq)
+        {
+          regs = riscv_dispatch_irq_ext(irq, regs);
+        }
+      else
+        {
+          regs = riscv_doirq(irq, regs);
+        }
+    }
 
+  return regs;
+}
+#else
+static void *riscv_dispatch_async_irq(uintreg_t irq, uintreg_t *regs)
+{
+  irq += RISCV_IRQ_ASYNC;
+
+  if (irq == RISCV_IRQ_EXT)
+    {
+      regs = riscv_dispatch_irq_ext(irq, regs);
+    }
+  else
+    {
       regs = riscv_doirq(irq, regs);
     }
 
-  if (RISCV_IRQ_EXT <= irq)
-    {
-      /* Then write PLIC_CLAIM to clear pending in PLIC */
+  return regs;
+}
+#endif
+
+void *riscv_dispatch_irq(uintreg_t vector, uintreg_t *regs)
+{
+  int irq = vector & (~RISCV_IRQ_BIT);
 
-      putreg32(irq - RISCV_IRQ_EXT, QEMU_RV_PLIC_CLAIM);
+  if ((vector & RISCV_IRQ_BIT) != 0)
+    {
+      regs = riscv_dispatch_async_irq(irq, regs);
+    }
+  else
+    {
+      regs = riscv_doirq(irq, regs);
     }
 
   return regs;

Reply via email to