diff --git a/Documentation/platforms/risc-v/common/index.rst b/Documentation/platforms/risc-v/common/index.rst new file mode 100644 index 00000000000..76d3e749422 --- /dev/null +++ b/Documentation/platforms/risc-v/common/index.rst @@ -0,0 +1,151 @@ +=========================================================================== +RISC-V Specific Features +=========================================================================== + +RISC-V CLIC Interrupt Threshold Configuration +============================================== + +Overview +-------- + +The RISC-V Core-Level Interrupt Controller (CLIC) provides more flexible interrupt +control compared to the legacy CLINT. One key feature is the interrupt threshold +mechanism (INTTHRESH), which allows fine-grained control over which interrupts +are processed based on their priority levels. + +CLIC Interrupt Threshold Basics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The CLIC interrupt threshold works by: + +1. **Threshold Register**: Each privilege mode has its own interrupt threshold register: + - Machine mode: ``CSR_MINTTHRESH`` (0x347) + - Supervisor mode: ``CSR_SINTTHRESH`` (0x147) + +2. **Interrupt Filtering**: Only interrupts with priority levels above the current + threshold are delivered to the processor. + +3. **Context Preservation**: The threshold value must be saved and restored during + context switches to maintain proper interrupt priority handling. + +Configuration in Custom Chip Layer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Kconfig Configuration +""""""""""""""""""""" + +To enable CLIC interrupt threshold support in your custom chip, add the following +to your chip's Kconfig file: + +.. code-block:: kconfig + + config ARCH_CHIP_MYCUSTOM_CHIP + bool "My Custom RISC-V Chip" + select ARCH_RV32 # or ARCH_RV64 + select ARCH_RV_HAVE_CLIC + ---help--- + My custom RISC-V chip with CLIC support + +Required Definitions +"""""""""""""""""""" + +In your chip-specific header file (e.g., ``arch/risc-v/include/mycustom/irq.h``): + +.. code-block:: c + + /* Define maximum interrupt threshold value for your CLIC implementation */ + #define RISCV_MAX_INTTHRESH 255 /* Adjust based on your CLIC design */ + + /* Optional: Define interrupt priority levels */ + #define CLIC_PRIO_CRITICAL 200 + #define CLIC_PRIO_HIGH 150 + #define CLIC_PRIO_NORMAL 100 + #define CLIC_PRIO_LOW 50 + +.. note:: + If ``RISCV_MAX_INTTHRESH`` is not defined by the chip, NuttX will use a default + value of ``0xff`` (255). This default should work for most CLIC implementations + that support 8-bit interrupt threshold values. Chips with different threshold + widths should define their own maximum value accordingly. + +Implementation Details +^^^^^^^^^^^^^^^^^^^^^^ + +Interrupt Save/Restore Mechanism +""""""""""""""""""""""""""""""""" + +When ``ARCH_RV_HAVE_CLIC`` is enabled, NuttX automatically uses the +interrupt threshold register instead of the standard status register for +interrupt control. The CLIC implementation uses the ``SWAP_CSR()`` macro +for atomic read-modify-write operations on the threshold register: + +.. code-block:: c + + /* Standard RISC-V interrupt disable (without CLIC) */ + noinstrument_function static inline_function irqstate_t up_irq_save(void) + { + irqstate_t flags; + + /* Read mstatus & clear machine interrupt enable (MIE) in mstatus */ + + __asm__ __volatile__ + ( + "csrrc %0, " __XSTR(CSR_STATUS) ", %1\n" + : "=r" (flags) + : "r"(STATUS_IE) + : "memory" + ); + + return flags; + } + + /* CLIC interrupt threshold disable (with ARCH_RV_HAVE_CLIC) */ + noinstrument_function static inline_function irqstate_t up_irq_save(void) + { + /* Read current interrupt threshold and set to maximum to mask all */ + + return SWAP_CSR(CSR_INTTHRESH, RISCV_MAX_INTTHRESH); + } + +Context Switch Handling +""""""""""""""""""""""" + +The interrupt context register (``REG_INT_CTX``) stores different values +depending on CLIC configuration: + +.. code-block:: c + + /* + * Without CLIC (standard RISC-V): REG_INT_CTX stores CSR_MSTATUS or CSR_SSTATUS + * With CLIC (ARCH_RV_HAVE_CLIC): REG_INT_CTX stores CSR_MINTTHRESH or CSR_SINTTHRESH + * + * The interrupt context is automatically determined by the CONFIG_ARCH_RV_HAVE_CLIC + * configuration, eliminating the need for a separate threshold enable option. + */ + +CLIC Driver Implementation +"""""""""""""""""""""""""" + +To implement the CLIC driver with interrupt threshold support, you may need to configure +CLIC properly to handle priority management and threshold levels in your chip's +driver code. + +Integration Checklist +^^^^^^^^^^^^^^^^^^^^^^ + +When integrating CLIC interrupt threshold support: + +☐ Enable ``ARCH_RV_HAVE_CLIC`` in Kconfig +☐ Define ``RISCV_MAX_INTTHRESH`` for your chip (optional - defaults to 0xff/255) +☐ Implement CLIC driver with priority management +☐ Verify interrupt threshold save/restore in context switches +☐ Test interrupt priority levels and threshold functionality +☐ Add debug support for troubleshooting + +References +^^^^^^^^^^ + +* RISC-V CLIC Specification +* NuttX RISC-V Architecture Documentation +* ``arch/risc-v/include/irq.h`` - Core interrupt handling definitions +* ``arch/risc-v/src/common/riscv_exception_common.S`` - Assembly interrupt handling diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 8ca23643063..3e4eec577da 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -776,6 +776,15 @@ config ARCH_RV_HAVE_APLIC Controller (APLIC) to provide flexible interrupt control. This device is not backward compatible with PLIC. +config ARCH_RV_HAVE_CLIC + bool + default n + ---help--- + RISC-V defines Core-Level Interrupt Controller (CLIC) to provide + flexible interrupt control. When enabled, CLIC uses interrupt + threshold (MINTTHRESH/SINTTHRESH) CSRs for interrupt control + instead of the standard IE bit in STATUS register. + config ARCH_RV_EXT_AIA bool "Enable RISC-V SxAIA support" default n diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 77ef18eca07..9bf32c58b57 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -130,6 +130,14 @@ #define RISCV_IRQ_MASK (~RISCV_IRQ_BIT) +#ifndef RISCV_MAX_INTTHRESH +/* The maximum interrupt threshold value. This is the maximum value that + * can be set in the MINTTHRESH or SINTTHRESH CSR registers to mask all + * interrupts. + */ +# define RISCV_MAX_INTTHRESH (0xff) +#endif + /* Configuration ************************************************************/ /* Processor PC */ @@ -197,14 +205,47 @@ #define REG_X30_NDX 30 #define REG_X31_NDX 31 -/* Interrupt Context register */ +/* Interrupt Context register + * This register stores interrupt-related state that needs to be preserved + * across context switches and interrupt handling. + * + * If ARCH_RV_HAVE_CLIC is enabled: + * - Both machine mode and supervisor mode use CLIC to mask interrupts + * - Contains the value of CSR_MINTTHRESH (Machine Interrupt Threshold) + * in machine mode or CSR_SINTTHRESH (Supervisor Interrupt Threshold) + * in supervisor mode + * - CLIC (Core Local Interrupt Controller) extension allows setting a + * threshold level below which interrupts are masked + * - This threshold value must be saved/restored to maintain proper + * interrupt priority handling across context switches + * + * Otherwise (standard RISC-V interrupt handling): + * - Contains the value of CSR_MSTATUS (Machine Status Register) in + * machine mode or CSR_SSTATUS (Supervisor Status Register) in + * supervisor mode + * - Preserves critical status bits including: + * * MIE/SIE (Machine/Supervisor Interrupt Enable) + * * MPIE/SPIE (Machine/Supervisor Previous Interrupt Enable) + * * MPP/SPP (Machine/Supervisor Previous Privilege) + * * FS (Floating Point Status) - floating-point unit state + * - Essential for proper interrupt state restoration when returning + * from exceptions or switching between tasks + * + * This context preservation ensures that interrupt handling behavior + * remains consistent across task switches and nested interrupt scenarios. + */ -#define REG_INT_CTX_NDX 32 +#ifdef CONFIG_ARCH_RV_HAVE_CLIC +# define REG_INT_THRESH_NDX 32 +# define REG_INT_CTX_NDX 33 +#else +# define REG_INT_CTX_NDX 32 +#endif #ifdef CONFIG_ARCH_RISCV_INTXCPT_EXTREGS -# define INT_XCPT_REGS (33 + CONFIG_ARCH_RISCV_INTXCPT_EXTREGS) +# define INT_XCPT_REGS (REG_INT_CTX_NDX + 1 + CONFIG_ARCH_RISCV_INTXCPT_EXTREGS) #else -# define INT_XCPT_REGS 33 +# define INT_XCPT_REGS (REG_INT_CTX_NDX + 1) #endif #ifdef CONFIG_ARCH_RV32 @@ -346,6 +387,9 @@ # define REG_X29 (INT_REG_SIZE*REG_X29_NDX) # define REG_X30 (INT_REG_SIZE*REG_X30_NDX) # define REG_X31 (INT_REG_SIZE*REG_X31_NDX) +# ifdef CONFIG_ARCH_RV_HAVE_CLIC +# define REG_INT_THRESH (INT_REG_SIZE*REG_INT_THRESH_NDX) +# endif # define REG_INT_CTX (INT_REG_SIZE*REG_INT_CTX_NDX) #ifdef CONFIG_ARCH_FPU @@ -425,6 +469,9 @@ # define REG_X29 REG_X29_NDX # define REG_X30 REG_X30_NDX # define REG_X31 REG_X31_NDX +# ifdef CONFIG_ARCH_RV_HAVE_CLIC +# define REG_INT_THRESH REG_INT_THRESH_NDX +# endif # define REG_INT_CTX REG_INT_CTX_NDX #ifdef CONFIG_ARCH_FPU @@ -755,6 +802,42 @@ int up_this_cpu(void); * Inline Functions ****************************************************************************/ +#ifdef CONFIG_ARCH_RV_HAVE_CLIC + +/**************************************************************************** + * Name: up_irq_save + * + * Description: + * Disable interrupts by setting interrupt threshold to maximum and return + * the previous threshold value + * + ****************************************************************************/ + +noinstrument_function static inline_function irqstate_t up_irq_save(void) +{ + /* Read current interrupt threshold and set to maximum to mask all */ + + return SWAP_CSR(CSR_INTTHRESH, RISCV_MAX_INTTHRESH); +} + +/**************************************************************************** + * Name: up_irq_restore + * + * Description: + * Restore the value of the interrupt threshold register + * + ****************************************************************************/ + +noinstrument_function static inline_function +void up_irq_restore(irqstate_t flags) +{ + /* Restore the interrupt threshold value */ + + WRITE_CSR(CSR_INTTHRESH, flags); +} + +#else + /**************************************************************************** * Name: up_irq_save * @@ -804,6 +887,8 @@ void up_irq_restore(irqstate_t flags) ); } +#endif /* CONFIG_ARCH_RV_HAVE_CLIC */ + /**************************************************************************** * Name: up_set_interrupt_context * diff --git a/arch/risc-v/include/mode.h b/arch/risc-v/include/mode.h index c39523d4f24..2c81c008b65 100644 --- a/arch/risc-v/include/mode.h +++ b/arch/risc-v/include/mode.h @@ -53,6 +53,7 @@ # define CSR_IPH CSR_SIPH # define CSR_TOPEI CSR_STOPEI /* Top external interrupt register */ # define CSR_TOPI CSR_STOPI /* Top interrupt register */ +# define CSR_INTTHRESH CSR_SINTTHRESH /* Interrupt threshold register */ /* In status register */ @@ -102,6 +103,7 @@ # define CSR_IPH CSR_MIPH # define CSR_TOPEI CSR_MTOPEI /* Top external interrupt register */ # define CSR_TOPI CSR_MTOPI /* Top interrupt register */ +# define CSR_INTTHRESH CSR_MINTTHRESH /* Interrupt threshold register */ /* In status register */ diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 11570b3d69f..a98774ec2ae 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -147,6 +147,9 @@ exception_common: csrr s0, CSR_STATUS /* s0=status */ csrr s1, CSR_EPC /* s1=exception PC */ csrr s2, CSR_CAUSE /* s2=cause */ +#ifdef CONFIG_ARCH_RV_HAVE_CLIC + csrr s4, CSR_INTTHRESH /* s4=interrupt threshold */ +#endif #ifdef CONFIG_ARCH_KERNEL_STACK csrr s3, CSR_SCRATCH @@ -158,6 +161,9 @@ exception_common: REGSTORE s0, REG_INT_CTX(sp) REGSTORE s1, REG_EPC(sp) REGSTORE s3, REG_SP(sp) +#ifdef CONFIG_ARCH_RV_HAVE_CLIC + REGSTORE s4, REG_INT_THRESH(sp) +#endif #ifdef CONFIG_LIB_SYSCALL csrr tp, CSR_SCRATCH /* Load kernel TP */ @@ -281,6 +287,10 @@ return_from_exception: REGLOAD s0, REG_INT_CTX(sp) /* restore status */ csrw CSR_STATUS, s0 +#ifdef CONFIG_ARCH_RV_HAVE_CLIC + REGLOAD s0, REG_INT_THRESH(sp) /* restore interrupt threshold */ + csrw CSR_INTTHRESH, s0 +#endif #ifdef CONFIG_LIB_SYSCALL /* Store tcb to scratch register */