diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2013-03-25 18:51:43 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2013-05-09 04:07:11 -0400 |
commit | 895666a9920f19bc256340aaf58d01da6e677a16 (patch) | |
tree | ff0b0fc50790d6ae5a37c5317e67523985f87bbd /arch/xtensa | |
parent | 8f371c7521545ee120364466514a4a2fc156c64f (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.S | 52 | ||||
-rw-r--r-- | arch/xtensa/kernel/traps.c | 18 | ||||
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 13 |
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: | |||
444 | 1: l32i a3, a1, PT_PS | 444 | 1: 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 | ||
695 | 1: | ||
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 | 698 | 1: wsr a0, depc |
718 | 2: | ||
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 | ||
733 | ENDPROC(kernel_exception) | 703 | ENDPROC(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 | ||
202 | extern void do_IRQ(int, struct pt_regs *); | 201 | extern 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" |
388 | ENTRY(_Level\level\()InterruptVector) | 388 | ENTRY(_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 |