Skip to content

Commit

Permalink
riscv: irq: Correct interrupt handling in clic non-vectored mode
Browse files Browse the repository at this point in the history
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.

(cherry picked from commit 08a2ca5)

Original-Signed-off-by: Greter Raffael <[email protected]>
GitOrigin-RevId: 08a2ca5
Change-Id: Ibaf8494660c6f2655cae88b2d68302eaa504c52c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/zephyr/+/5211285
Tested-by: Keith Short <[email protected]>
Commit-Queue: Keith Short <[email protected]>
Tested-by: ChromeOS Prod (Robot) <[email protected]>
Reviewed-by: Keith Short <[email protected]>
  • Loading branch information
raffi-g authored and Chromeos LUCI committed Jan 23, 2024
1 parent ec95b88 commit ad48680
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 0 deletions.
7 changes: 7 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ config RISCV_SOC_HAS_ISR_STACKING
saved on the stack by the hardware, and the registers saved by the
software macros. The structure must be called '__esf'.

config RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
bool
help
This allows the SoC to overwrite the irq handling. If enabled, the
function __soc_handle_all_irqs has to be implemented. It shall service
and clear all pending interrupts.

config RISCV_SOC_HAS_CUSTOM_IRQ_LOCK_OPS
bool
help
Expand Down
10 changes: 10 additions & 0 deletions arch/riscv/core/isr.S
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ GTEXT(sys_trace_isr_exit)
GDATA(_k_syscall_table)
#endif

#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
GTEXT(__soc_handle_all_irqs)
#endif

/* exports */
GTEXT(_isr_wrapper)

Expand Down Expand Up @@ -522,6 +526,10 @@ is_interrupt:

on_irq_stack:

#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING
call __soc_handle_all_irqs
#else

#ifdef CONFIG_TRACING_ISR
call sys_trace_isr_enter
#endif
Expand Down Expand Up @@ -558,6 +566,8 @@ on_irq_stack:
call sys_trace_isr_exit
#endif

#endif

irq_done:
/* Decrement _current_cpu->nested */
lw t2, ___cpu_t_nested_OFFSET(s0)
Expand Down
1 change: 1 addition & 0 deletions drivers/interrupt_controller/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c)
zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c)
zephyr_library_sources_ifdef(CONFIG_VIM intc_vim.c)
zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c)
zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.S)
zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c)
zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c)
zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c)
Expand Down
1 change: 1 addition & 0 deletions drivers/interrupt_controller/Kconfig.clic
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ config NUCLEI_ECLIC
default y
depends on DT_HAS_NUCLEI_ECLIC_ENABLED
select MULTI_LEVEL_INTERRUPTS
select RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING if !RISCV_VECTORED_MODE
help
Interrupt controller for Nuclei SoC core.

Expand Down
79 changes: 79 additions & 0 deletions drivers/interrupt_controller/intc_nuclei_eclic.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 Baumer Electric AG
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @brief Assembler-hooks specific to Nuclei's Extended Core Interrupt Controller
*/

#include <zephyr/arch/cpu.h>


GTEXT(__soc_handle_irq)
/*
* In an ECLIC, pending interrupts don't have to be cleared by hand.
* In vectored mode, interrupts are cleared automatically.
* In non-vectored mode, interrupts are cleared when writing the mnxti register (done in
* __soc_handle_all_irqs).
* Thus this function can directly return.
*/
SECTION_FUNC(exception.other, __soc_handle_irq)
ret

#if !defined(CONFIG_RISCV_VECTORED_MODE)

GTEXT(__soc_handle_all_irqs)

#ifdef CONFIG_TRACING
/* imports */
GTEXT(sys_trace_isr_enter)
GTEXT(sys_trace_isr_exit)
#endif

/*
* This function services and clears all pending interrupts for an ECLIC in non-vectored mode.
*/
SECTION_FUNC(exception.other, __soc_handle_all_irqs)
mv t2, ra

/* Read and clear mnxti to get highest current interrupt and enable interrupts. Will return
* original interrupt if no others appear. */
csrrci a0, 0x345, MSTATUS_IEN
beqz a0, irq_done /* Check if original interrupt vanished. */

irq_loop:

#ifdef CONFIG_TRACING_ISR
call sys_trace_isr_enter
#endif

/* Call corresponding registered function in _sw_isr_table. a0 is offset in words, table is
* 2-word wide -> shift by one */
la t0, _sw_isr_table
slli a0, a0, (1)
add t0, t0, a0

/* Load argument in a0 register */
lw a0, 0(t0)

/* Load ISR function address in register t1 */
lw t1, RV_REGSIZE(t0)

/* Call ISR function */
jalr ra, t1, 0

/* Read and clear mnxti to get highest current interrupt and enable interrupts. */
csrrci a0, 0x345, MSTATUS_IEN

#ifdef CONFIG_TRACING_ISR
call sys_trace_isr_exit
#endif

bnez a0, irq_loop

irq_done:
mv ra, t2
ret
#endif

0 comments on commit ad48680

Please sign in to comment.