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/kernel | |
| 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/kernel')
| -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 |
