arch: riscv: handle interrupt level for CLIC
CLIC supports mintstatus.MIL (RO) and mcause.MPIL (RW) for the current interrupt level and the previous interrut level before a trap. Each ISR must execute MRET to set mcause.MPIL back to mintstatus.MIL. This commit introduces CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL to handle mcause.MPIL for interrupt preemption in nested ISR, and uses CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL to ensure ISR always switch out with MRET. e.g. With CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL=n, a context-switch in ISR may skip MRET in this flow: IRQ -> _isr_wrapper -> z_riscv_switch() -> retrun to arch_switch() Signed-off-by: Jimmy Zheng <jimmyzhe@andestech.com>
This commit is contained in:
parent
e783f69ebf
commit
3804387350
5 changed files with 37 additions and 0 deletions
|
@ -220,9 +220,20 @@ config RISCV_HAS_PLIC
|
|||
config RISCV_HAS_CLIC
|
||||
bool
|
||||
depends on RISCV_PRIVILEGED
|
||||
select RISCV_ALWAYS_SWITCH_THROUGH_ECALL if MULTITHREADING
|
||||
select CLIC_SUPPORT_INTERRUPT_LEVEL if !NRFX_CLIC
|
||||
help
|
||||
Does the SOC provide support for a Core-Local Interrupt Controller (CLIC).
|
||||
|
||||
config CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
bool
|
||||
depends on RISCV_HAS_CLIC
|
||||
help
|
||||
For CLIC implementations with extended interrupt level, where
|
||||
higher-numbered interrupt levels can preempt lower-numbered interrupt
|
||||
levels. This option handles interrupt level in ISR to ensure proper
|
||||
nested ISR exits.
|
||||
|
||||
config RISCV_SOC_EXCEPTION_FROM_IRQ
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -198,6 +198,12 @@ SECTION_FUNC(exception.entry, _isr_wrapper)
|
|||
sr s0, __struct_arch_esf_s0_OFFSET(sp)
|
||||
get_current_cpu s0
|
||||
|
||||
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
/* Save mcause register */
|
||||
csrr t0, mcause
|
||||
sr t0, __struct_arch_esf_mcause_OFFSET(sp)
|
||||
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||
|
||||
/* Save MEPC register */
|
||||
csrr t0, mepc
|
||||
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
||||
|
@ -737,6 +743,13 @@ fp_trap_exit:
|
|||
/* Restore MEPC and MSTATUS registers */
|
||||
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
||||
lr t2, __struct_arch_esf_mstatus_OFFSET(sp)
|
||||
|
||||
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
/* Restore MCAUSE register for previous interrupt level. */
|
||||
lr t1, __struct_arch_esf_mcause_OFFSET(sp)
|
||||
csrw mcause, t1
|
||||
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||
|
||||
csrw mepc, t0
|
||||
csrw mstatus, t2
|
||||
|
||||
|
|
|
@ -112,6 +112,10 @@ GEN_OFFSET_STRUCT(arch_esf, a7);
|
|||
GEN_OFFSET_STRUCT(arch_esf, mepc);
|
||||
GEN_OFFSET_STRUCT(arch_esf, mstatus);
|
||||
|
||||
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
GEN_OFFSET_STRUCT(arch_esf, mcause);
|
||||
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||
|
||||
GEN_OFFSET_STRUCT(arch_esf, s0);
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
|
|
|
@ -110,6 +110,11 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
|||
SOC_ISR_STACKING_ESR_INIT;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
/* Clear the previous interrupt level. */
|
||||
stack_init->mcause = 0;
|
||||
#endif
|
||||
|
||||
thread->callee_saved.sp = (unsigned long)stack_init;
|
||||
|
||||
/* where to go when returning from z_riscv_switch() */
|
||||
|
|
|
@ -78,6 +78,10 @@ struct arch_esf {
|
|||
unsigned long a7; /* function argument */
|
||||
#endif /* !CONFIG_RISCV_ISA_RV32E */
|
||||
|
||||
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||
unsigned long mcause; /* machine cause register */
|
||||
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||
|
||||
unsigned long mepc; /* machine exception program counter */
|
||||
unsigned long mstatus; /* machine status register */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue