arch/risc-v: Add CLIC interrupt threshold support
Some checks are pending
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions

and documentation it

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
This commit is contained in:
Huang Qi 2025-06-11 10:38:59 +08:00 committed by Alan C. Assis
parent 0577a674e7
commit 4e196729e7
5 changed files with 261 additions and 4 deletions

View file

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

View file

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

View file

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

View file

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

View file

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