From 3f8e4d7400f5c7f813423be866bfb34cd7f3349f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 24 Mar 2025 15:03:36 -0700 Subject: [PATCH] xtensa: rework IRQ masking during IRQ entrance Before cross stack call is setup correctly, we cannot allow interrupts to be triggered or it may interfere with register window spilling since we are clobbering registers needed for that to work. However, there was a brief period where higher level interrupts could fire due to code writing to PS with lowered interrupt mask before raising it again. So rework that part to avoid writing PS with intermediate value, and now we mask interrupt until everything is setup correctly before interrupt is enabled again. Signed-off-by: Daniel Leung --- arch/xtensa/include/xtensa_asm2_s.h | 49 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 40b61c2013d..a6c57cd1e03 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -373,6 +373,23 @@ _xstack_returned_\@: wur.THREADPTR a0 #endif /* XCHAL_HAVE_THREADPTR && CONFIG_USERSPACE */ + /* Setting up the cross stack call below has states where the + * resulting frames are invalid/non-reentrant, so we can't + * allow nested interrupts. But we do need EXCM unmasked, as + * we use CALL/ENTRY instructions in the process and need to + * handle exceptions to spill caller/interruptee frames. Use + * PS.INTLEVEL at maximum to mask all interrupts and stash the + * current value in our designated EPS register (which is + * guaranteed unused across the call) + */ + rsil a0, 0xf + + /* Since we are unmasking EXCM, we need to set RING bits to kernel + * mode, otherwise we won't be able to run the exception handler in C. + */ + movi a3, ~(PS_EXCM_MASK) & ~(PS_RING_MASK) + and a0, a0, a3 + #ifdef CONFIG_XTENSA_INTERRUPT_NONPREEMPTABLE /* Setting the interrupt mask to the max non-debug level @@ -380,12 +397,11 @@ _xstack_returned_\@: * high level interrupts until processing of that lower level * interrupt has completed. */ - rsr.ps a0 movi a3, ~(PS_INTLEVEL_MASK) and a0, a0, a3 movi a3, PS_INTLEVEL(ZSR_RFI_LEVEL) or a0, a0, a3 - wsr.ps a0 + wsr.ZSR_EPS a0 #else @@ -401,35 +417,20 @@ _xstack_returned_\@: * argument and expand two versions of this handler. An * optimization FIXME, I guess. */ - rsr.ps a0 movi a3, PS_INTLEVEL_MASK - and a0, a0, a3 - bnez a0, _not_l1 - rsr.ps a0 + and a3, a0, a3 + bnez a3, _not_l1 + + /* interrupt masking is zero, so no need to zero it before OR-ing. */ movi a3, PS_INTLEVEL(1) or a0, a0, a3 - wsr.ps a0 _not_l1: + wsr.ZSR_EPS a0 #endif /* CONFIG_XTENSA_INTERRUPT_NONPREEMPTABLE */ - /* Setting up the cross stack call below has states where the - * resulting frames are invalid/non-reentrant, so we can't - * allow nested interrupts. But we do need EXCM unmasked, as - * we use CALL/ENTRY instructions in the process and need to - * handle exceptions to spill caller/interruptee frames. Use - * PS.INTLEVEL at maximum to mask all interrupts and stash the - * current value in our designated EPS register (which is - * guaranteed unused across the call) - */ - rsil a0, 0xf - - /* Since we are unmasking EXCM, we need to set RING bits to kernel - * mode, otherwise we won't be able to run the exception handler in C. - */ - movi a3, ~(PS_EXCM_MASK) & ~(PS_RING_MASK) - and a0, a0, a3 - wsr.ZSR_EPS a0 + movi a3, PS_INTLEVEL(0xf) + or a0, a0, a3 wsr.ps a0 rsync