aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2013-03-25 18:51:43 -0400
committerChris Zankel <chris@zankel.net>2013-05-09 04:07:11 -0400
commit895666a9920f19bc256340aaf58d01da6e677a16 (patch)
treeff0b0fc50790d6ae5a37c5317e67523985f87bbd /arch/xtensa
parent8f371c7521545ee120364466514a4a2fc156c64f (diff)
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>
Diffstat (limited to 'arch/xtensa')
-rw-r--r--arch/xtensa/kernel/entry.S52
-rw-r--r--arch/xtensa/kernel/traps.c18
-rw-r--r--arch/xtensa/kernel/vectors.S13
3 files changed, 28 insertions, 55 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 3729b48d798d..5082507d5631 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -354,16 +354,16 @@ common_exception:
354 * so we can allow exceptions and interrupts (*) again. 354 * so we can allow exceptions and interrupts (*) again.
355 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) 355 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
356 * 356 *
357 * (*) We only allow interrupts of higher priority than current IRQ 357 * (*) We only allow interrupts if they were previously enabled and
358 * we're not handling an IRQ
358 */ 359 */
359 360
360 rsr a3, ps 361 rsr a3, ps
361 addi a0, a0, -4 362 addi a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT
362 movi a2, 1 363 movi a2, LOCKLEVEL
363 extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH 364 extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
364 # a3 = PS.INTLEVEL 365 # a3 = PS.INTLEVEL
365 movnez a2, a3, a3 # a2 = 1: level-1, > 1: high priority 366 moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt
366 moveqz a3, a2, a0 # a3 = IRQ level iff interrupt
367 movi a2, 1 << PS_WOE_BIT 367 movi a2, 1 << PS_WOE_BIT
368 or a3, a3, a2 368 or a3, a3, a2
369 rsr a0, exccause 369 rsr a0, exccause
@@ -444,6 +444,8 @@ common_exception_return:
4441: l32i a3, a1, PT_PS 4441: l32i a3, a1, PT_PS
445 _bbci.l a3, PS_UM_BIT, 4f 445 _bbci.l a3, PS_UM_BIT, 4f
446 446
447 rsil a2, 0
448
447 /* Specific to a user exception exit: 449 /* Specific to a user exception exit:
448 * We need to check some flags for signal handling and rescheduling, 450 * We need to check some flags for signal handling and rescheduling,
449 * and have to restore WB and WS, extra states, and all registers 451 * and have to restore WB and WS, extra states, and all registers
@@ -684,51 +686,19 @@ common_exception_exit:
684 686
685 l32i a0, a1, PT_DEPC 687 l32i a0, a1, PT_DEPC
686 l32i a3, a1, PT_AREG3 688 l32i a3, a1, PT_AREG3
687 _bltui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
688
689 wsr a0, depc
690 l32i a2, a1, PT_AREG2 689 l32i a2, a1, PT_AREG2
691 l32i a0, a1, PT_AREG0 690 _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
692 l32i a1, a1, PT_AREG1
693 rfde
694 691
6951:
696 /* Restore a0...a3 and return */ 692 /* Restore a0...a3 and return */
697 693
698 rsr a0, ps
699 extui a2, a0, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
700 movi a0, 2f
701 slli a2, a2, 4
702 add a0, a2, a0
703 l32i a2, a1, PT_AREG2
704 jx a0
705
706 .macro irq_exit_level level
707 .align 16
708 .if XCHAL_EXCM_LEVEL >= \level
709 l32i a0, a1, PT_PC
710 wsr a0, epc\level
711 l32i a0, a1, PT_AREG0 694 l32i a0, a1, PT_AREG0
712 l32i a1, a1, PT_AREG1 695 l32i a1, a1, PT_AREG1
713 rfi \level 696 rfe
714 .endif
715 .endm
716 697
717 .align 16 6981: wsr a0, depc
7182:
719 l32i a0, a1, PT_AREG0 699 l32i a0, a1, PT_AREG0
720 l32i a1, a1, PT_AREG1 700 l32i a1, a1, PT_AREG1
721 rfe 701 rfde
722
723 .align 16
724 /* no rfi for level-1 irq, handled by rfe above*/
725 nop
726
727 irq_exit_level 2
728 irq_exit_level 3
729 irq_exit_level 4
730 irq_exit_level 5
731 irq_exit_level 6
732 702
733ENDPROC(kernel_exception) 703ENDPROC(kernel_exception)
734 704
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index cf065e165ceb..30e53e609104 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -196,7 +196,6 @@ void do_multihit(struct pt_regs *regs, unsigned long exccause)
196 196
197/* 197/*
198 * IRQ handler. 198 * IRQ handler.
199 * PS.INTLEVEL is the current IRQ priority level.
200 */ 199 */
201 200
202extern void do_IRQ(int, struct pt_regs *); 201extern void do_IRQ(int, struct pt_regs *);
@@ -213,18 +212,21 @@ void do_interrupt(struct pt_regs *regs)
213 XCHAL_INTLEVEL6_MASK, 212 XCHAL_INTLEVEL6_MASK,
214 XCHAL_INTLEVEL7_MASK, 213 XCHAL_INTLEVEL7_MASK,
215 }; 214 };
216 unsigned level = get_sr(ps) & PS_INTLEVEL_MASK;
217
218 if (WARN_ON_ONCE(level >= ARRAY_SIZE(int_level_mask)))
219 return;
220 215
221 for (;;) { 216 for (;;) {
222 unsigned intread = get_sr(interrupt); 217 unsigned intread = get_sr(interrupt);
223 unsigned intenable = get_sr(intenable); 218 unsigned intenable = get_sr(intenable);
224 unsigned int_at_level = intread & intenable & 219 unsigned int_at_level = intread & intenable;
225 int_level_mask[level]; 220 unsigned level;
221
222 for (level = LOCKLEVEL; level > 0; --level) {
223 if (int_at_level & int_level_mask[level]) {
224 int_at_level &= int_level_mask[level];
225 break;
226 }
227 }
226 228
227 if (!int_at_level) 229 if (level == 0)
228 return; 230 return;
229 231
230 /* 232 /*
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
index a7e1d0834c68..f9e175382aa9 100644
--- a/arch/xtensa/kernel/vectors.S
+++ b/arch/xtensa/kernel/vectors.S
@@ -386,9 +386,12 @@ ENDPROC(_DebugInterruptVector)
386 .if XCHAL_EXCM_LEVEL >= \level 386 .if XCHAL_EXCM_LEVEL >= \level
387 .section .Level\level\()InterruptVector.text, "ax" 387 .section .Level\level\()InterruptVector.text, "ax"
388ENTRY(_Level\level\()InterruptVector) 388ENTRY(_Level\level\()InterruptVector)
389 wsr a0, epc1 389 wsr a0, excsave2
390 rsr a0, epc\level 390 rsr a0, epc\level
391 xsr a0, epc1 391 wsr a0, epc1
392 movi a0, EXCCAUSE_LEVEL1_INTERRUPT
393 wsr a0, exccause
394 rsr a0, eps\level
392 # branch to user or kernel vector 395 # branch to user or kernel vector
393 j _SimulateUserKernelVectorException 396 j _SimulateUserKernelVectorException
394 .endif 397 .endif
@@ -440,10 +443,8 @@ ENDPROC(_WindowOverflow4)
440 */ 443 */
441 .align 4 444 .align 4
442_SimulateUserKernelVectorException: 445_SimulateUserKernelVectorException:
443 wsr a0, excsave2 446 addi a0, a0, (1 << PS_EXCM_BIT)
444 movi a0, 4 # LEVEL1_INTERRUPT cause 447 wsr a0, ps
445 wsr a0, exccause
446 rsr a0, ps
447 bbsi.l a0, PS_UM_BIT, 1f # branch if user mode 448 bbsi.l a0, PS_UM_BIT, 1f # branch if user mode
448 rsr a0, excsave2 # restore a0 449 rsr a0, excsave2 # restore a0
449 j _KernelExceptionVector # simulate kernel vector exception 450 j _KernelExceptionVector # simulate kernel vector exception