xtensa: disable IRQs while IRQ handler is running
IRQ handlers are expected to run with IRQs disabled.
See e.g. http://lwn.net/Articles/380931/ for a longer story.
This was overlooked in the commit
2d1c645
xtensa: dispatch medium-priority interrupts
Revert to old behavior and simplify interrupt entry and exit code.
Interrupt handler still honours IRQ priority.
do_notify_resume/schedule must be called with interrupts enabled, enable
interrupts if we return from user exception.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Chris Zankel <chris@zankel.net>
This commit is contained in:
parent
8f371c7521
commit
895666a992
|
@ -354,16 +354,16 @@ common_exception:
|
||||||
* so we can allow exceptions and interrupts (*) again.
|
* so we can allow exceptions and interrupts (*) again.
|
||||||
* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
|
* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
|
||||||
*
|
*
|
||||||
* (*) We only allow interrupts of higher priority than current IRQ
|
* (*) We only allow interrupts if they were previously enabled and
|
||||||
|
* we're not handling an IRQ
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rsr a3, ps
|
rsr a3, ps
|
||||||
addi a0, a0, -4
|
addi a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT
|
||||||
movi a2, 1
|
movi a2, LOCKLEVEL
|
||||||
extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
|
extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
|
||||||
# a3 = PS.INTLEVEL
|
# a3 = PS.INTLEVEL
|
||||||
movnez a2, a3, a3 # a2 = 1: level-1, > 1: high priority
|
moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt
|
||||||
moveqz a3, a2, a0 # a3 = IRQ level iff interrupt
|
|
||||||
movi a2, 1 << PS_WOE_BIT
|
movi a2, 1 << PS_WOE_BIT
|
||||||
or a3, a3, a2
|
or a3, a3, a2
|
||||||
rsr a0, exccause
|
rsr a0, exccause
|
||||||
|
@ -444,6 +444,8 @@ common_exception_return:
|
||||||
1: l32i a3, a1, PT_PS
|
1: l32i a3, a1, PT_PS
|
||||||
_bbci.l a3, PS_UM_BIT, 4f
|
_bbci.l a3, PS_UM_BIT, 4f
|
||||||
|
|
||||||
|
rsil a2, 0
|
||||||
|
|
||||||
/* Specific to a user exception exit:
|
/* Specific to a user exception exit:
|
||||||
* We need to check some flags for signal handling and rescheduling,
|
* We need to check some flags for signal handling and rescheduling,
|
||||||
* and have to restore WB and WS, extra states, and all registers
|
* and have to restore WB and WS, extra states, and all registers
|
||||||
|
@ -684,51 +686,19 @@ common_exception_exit:
|
||||||
|
|
||||||
l32i a0, a1, PT_DEPC
|
l32i a0, a1, PT_DEPC
|
||||||
l32i a3, a1, PT_AREG3
|
l32i a3, a1, PT_AREG3
|
||||||
_bltui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
|
|
||||||
|
|
||||||
wsr a0, depc
|
|
||||||
l32i a2, a1, PT_AREG2
|
l32i a2, a1, PT_AREG2
|
||||||
l32i a0, a1, PT_AREG0
|
_bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
|
||||||
l32i a1, a1, PT_AREG1
|
|
||||||
rfde
|
|
||||||
|
|
||||||
1:
|
|
||||||
/* Restore a0...a3 and return */
|
/* Restore a0...a3 and return */
|
||||||
|
|
||||||
rsr a0, ps
|
|
||||||
extui a2, a0, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
|
|
||||||
movi a0, 2f
|
|
||||||
slli a2, a2, 4
|
|
||||||
add a0, a2, a0
|
|
||||||
l32i a2, a1, PT_AREG2
|
|
||||||
jx a0
|
|
||||||
|
|
||||||
.macro irq_exit_level level
|
|
||||||
.align 16
|
|
||||||
.if XCHAL_EXCM_LEVEL >= \level
|
|
||||||
l32i a0, a1, PT_PC
|
|
||||||
wsr a0, epc\level
|
|
||||||
l32i a0, a1, PT_AREG0
|
|
||||||
l32i a1, a1, PT_AREG1
|
|
||||||
rfi \level
|
|
||||||
.endif
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
2:
|
|
||||||
l32i a0, a1, PT_AREG0
|
l32i a0, a1, PT_AREG0
|
||||||
l32i a1, a1, PT_AREG1
|
l32i a1, a1, PT_AREG1
|
||||||
rfe
|
rfe
|
||||||
|
|
||||||
.align 16
|
1: wsr a0, depc
|
||||||
/* no rfi for level-1 irq, handled by rfe above*/
|
l32i a0, a1, PT_AREG0
|
||||||
nop
|
l32i a1, a1, PT_AREG1
|
||||||
|
rfde
|
||||||
irq_exit_level 2
|
|
||||||
irq_exit_level 3
|
|
||||||
irq_exit_level 4
|
|
||||||
irq_exit_level 5
|
|
||||||
irq_exit_level 6
|
|
||||||
|
|
||||||
ENDPROC(kernel_exception)
|
ENDPROC(kernel_exception)
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,6 @@ void do_multihit(struct pt_regs *regs, unsigned long exccause)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IRQ handler.
|
* IRQ handler.
|
||||||
* PS.INTLEVEL is the current IRQ priority level.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void do_IRQ(int, struct pt_regs *);
|
extern void do_IRQ(int, struct pt_regs *);
|
||||||
|
@ -213,18 +212,21 @@ void do_interrupt(struct pt_regs *regs)
|
||||||
XCHAL_INTLEVEL6_MASK,
|
XCHAL_INTLEVEL6_MASK,
|
||||||
XCHAL_INTLEVEL7_MASK,
|
XCHAL_INTLEVEL7_MASK,
|
||||||
};
|
};
|
||||||
unsigned level = get_sr(ps) & PS_INTLEVEL_MASK;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(level >= ARRAY_SIZE(int_level_mask)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
unsigned intread = get_sr(interrupt);
|
unsigned intread = get_sr(interrupt);
|
||||||
unsigned intenable = get_sr(intenable);
|
unsigned intenable = get_sr(intenable);
|
||||||
unsigned int_at_level = intread & intenable &
|
unsigned int_at_level = intread & intenable;
|
||||||
int_level_mask[level];
|
unsigned level;
|
||||||
|
|
||||||
if (!int_at_level)
|
for (level = LOCKLEVEL; level > 0; --level) {
|
||||||
|
if (int_at_level & int_level_mask[level]) {
|
||||||
|
int_at_level &= int_level_mask[level];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -386,9 +386,12 @@ ENDPROC(_DebugInterruptVector)
|
||||||
.if XCHAL_EXCM_LEVEL >= \level
|
.if XCHAL_EXCM_LEVEL >= \level
|
||||||
.section .Level\level\()InterruptVector.text, "ax"
|
.section .Level\level\()InterruptVector.text, "ax"
|
||||||
ENTRY(_Level\level\()InterruptVector)
|
ENTRY(_Level\level\()InterruptVector)
|
||||||
wsr a0, epc1
|
wsr a0, excsave2
|
||||||
rsr a0, epc\level
|
rsr a0, epc\level
|
||||||
xsr a0, epc1
|
wsr a0, epc1
|
||||||
|
movi a0, EXCCAUSE_LEVEL1_INTERRUPT
|
||||||
|
wsr a0, exccause
|
||||||
|
rsr a0, eps\level
|
||||||
# branch to user or kernel vector
|
# branch to user or kernel vector
|
||||||
j _SimulateUserKernelVectorException
|
j _SimulateUserKernelVectorException
|
||||||
.endif
|
.endif
|
||||||
|
@ -440,10 +443,8 @@ ENDPROC(_WindowOverflow4)
|
||||||
*/
|
*/
|
||||||
.align 4
|
.align 4
|
||||||
_SimulateUserKernelVectorException:
|
_SimulateUserKernelVectorException:
|
||||||
wsr a0, excsave2
|
addi a0, a0, (1 << PS_EXCM_BIT)
|
||||||
movi a0, 4 # LEVEL1_INTERRUPT cause
|
wsr a0, ps
|
||||||
wsr a0, exccause
|
|
||||||
rsr a0, ps
|
|
||||||
bbsi.l a0, PS_UM_BIT, 1f # branch if user mode
|
bbsi.l a0, PS_UM_BIT, 1f # branch if user mode
|
||||||
rsr a0, excsave2 # restore a0
|
rsr a0, excsave2 # restore a0
|
||||||
j _KernelExceptionVector # simulate kernel vector exception
|
j _KernelExceptionVector # simulate kernel vector exception
|
||||||
|
|
Loading…
Reference in New Issue