Skip to content

Commit 08a2ca5

Browse files
raffi-gcarlescufi
authored andcommitted
riscv: irq: Correct interrupt handling in clic non-vectored mode
According to the clic specification (https://github.com/riscv/riscv-fast-interrupt), the mnxti register has be written, in order to clear the pending bit for non-vectored interrupts. For vectored interrupts, this is automatically done. From the spec: "If the pending interrupt is edge-triggered, hardware will automatically clear the corresponding pending bit when the CSR instruction that accesses xnxti includes a write." I added a kconfig `RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING` to allow custom irq handling. If enabled, `__soc_handle_all_irqs` has to be implemented. For clic, non-vectored mode, I added a `__soc_handle_all_irqs`, that handles the pending interrupts according to the pseudo code in the spec. Signed-off-by: Greter Raffael <[email protected]>
1 parent 9c955ce commit 08a2ca5

File tree

5 files changed

+98
-0
lines changed

5 files changed

+98
-0
lines changed

arch/riscv/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ config RISCV_SOC_HAS_ISR_STACKING
8484
saved on the stack by the hardware, and the registers saved by the
8585
software macros. The structure must be called '__esf'.
8686

87+
config RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
88+
bool
89+
help
90+
This allows the SoC to overwrite the irq handling. If enabled, the
91+
function __soc_handle_all_irqs has to be implemented. It shall service
92+
and clear all pending interrupts.
93+
8794
config RISCV_SOC_HAS_CUSTOM_IRQ_LOCK_OPS
8895
bool
8996
help

arch/riscv/core/isr.S

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ GTEXT(sys_trace_isr_exit)
7373
GDATA(_k_syscall_table)
7474
#endif
7575

76+
#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
77+
GTEXT(__soc_handle_all_irqs)
78+
#endif
79+
7680
/* exports */
7781
GTEXT(_isr_wrapper)
7882

@@ -522,6 +526,10 @@ is_interrupt:
522526

523527
on_irq_stack:
524528

529+
#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
530+
call __soc_handle_all_irqs
531+
#else
532+
525533
#ifdef CONFIG_TRACING_ISR
526534
call sys_trace_isr_enter
527535
#endif
@@ -558,6 +566,8 @@ on_irq_stack:
558566
call sys_trace_isr_exit
559567
#endif
560568

569+
#endif
570+
561571
irq_done:
562572
/* Decrement _current_cpu->nested */
563573
lw t2, ___cpu_t_nested_OFFSET(s0)

drivers/interrupt_controller/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c)
3232
zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c)
3333
zephyr_library_sources_ifdef(CONFIG_VIM intc_vim.c)
3434
zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c)
35+
zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.S)
3536
zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c)
3637
zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c)
3738
zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c)

drivers/interrupt_controller/Kconfig.clic

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ config NUCLEI_ECLIC
66
default y
77
depends on DT_HAS_NUCLEI_ECLIC_ENABLED
88
select MULTI_LEVEL_INTERRUPTS
9+
select RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING if !RISCV_VECTORED_MODE
910
help
1011
Interrupt controller for Nuclei SoC core.
1112

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2024 Baumer Electric AG
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @brief Assembler-hooks specific to Nuclei's Extended Core Interrupt Controller
9+
*/
10+
11+
#include <zephyr/arch/cpu.h>
12+
13+
14+
GTEXT(__soc_handle_irq)
15+
/*
16+
* In an ECLIC, pending interrupts don't have to be cleared by hand.
17+
* In vectored mode, interrupts are cleared automatically.
18+
* In non-vectored mode, interrupts are cleared when writing the mnxti register (done in
19+
* __soc_handle_all_irqs).
20+
* Thus this function can directly return.
21+
*/
22+
SECTION_FUNC(exception.other, __soc_handle_irq)
23+
ret
24+
25+
#if !defined(CONFIG_RISCV_VECTORED_MODE)
26+
27+
GTEXT(__soc_handle_all_irqs)
28+
29+
#ifdef CONFIG_TRACING
30+
/* imports */
31+
GTEXT(sys_trace_isr_enter)
32+
GTEXT(sys_trace_isr_exit)
33+
#endif
34+
35+
/*
36+
* This function services and clears all pending interrupts for an ECLIC in non-vectored mode.
37+
*/
38+
SECTION_FUNC(exception.other, __soc_handle_all_irqs)
39+
mv t2, ra
40+
41+
/* Read and clear mnxti to get highest current interrupt and enable interrupts. Will return
42+
* original interrupt if no others appear. */
43+
csrrci a0, 0x345, MSTATUS_IEN
44+
beqz a0, irq_done /* Check if original interrupt vanished. */
45+
46+
irq_loop:
47+
48+
#ifdef CONFIG_TRACING_ISR
49+
call sys_trace_isr_enter
50+
#endif
51+
52+
/* Call corresponding registered function in _sw_isr_table. a0 is offset in words, table is
53+
* 2-word wide -> shift by one */
54+
la t0, _sw_isr_table
55+
slli a0, a0, (1)
56+
add t0, t0, a0
57+
58+
/* Load argument in a0 register */
59+
lw a0, 0(t0)
60+
61+
/* Load ISR function address in register t1 */
62+
lw t1, RV_REGSIZE(t0)
63+
64+
/* Call ISR function */
65+
jalr ra, t1, 0
66+
67+
/* Read and clear mnxti to get highest current interrupt and enable interrupts. */
68+
csrrci a0, 0x345, MSTATUS_IEN
69+
70+
#ifdef CONFIG_TRACING_ISR
71+
call sys_trace_isr_exit
72+
#endif
73+
74+
bnez a0, irq_loop
75+
76+
irq_done:
77+
mv ra, t2
78+
ret
79+
#endif

0 commit comments

Comments
 (0)