diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-05-07 23:31:59 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-05-08 19:42:21 -0400 |
commit | 56dfa7fa19e36db352a94be022243ed461710119 (patch) | |
tree | 37ea957522aa18a2d3f4fb62629e9e4ca0e7f38c /arch | |
parent | 810b4de25e53459323ff48957b0162b48d6cbd57 (diff) |
powerpc/irq: Fix bug with new lazy IRQ handling code
We had a case where we could turn on hard interrupts while
leaving the PACA_IRQ_HARD_DIS bit set in the PACA. This can
in turn cause a BUG_ON() to hit in __check_irq_replay() due
to interrupt state getting out of sync.
The assembly code was also way too convoluted. Instead, we
now leave it to the C code to do the right thing which ends
up being smaller and more readable.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 18 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 8 |
2 files changed, 7 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index f8a7a1a1a9f4..fc6015027a86 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -767,16 +767,6 @@ do_work: | |||
767 | SOFT_DISABLE_INTS(r3,r4) | 767 | SOFT_DISABLE_INTS(r3,r4) |
768 | 1: bl .preempt_schedule_irq | 768 | 1: bl .preempt_schedule_irq |
769 | 769 | ||
770 | /* Hard-disable interrupts again (and update PACA) */ | ||
771 | #ifdef CONFIG_PPC_BOOK3E | ||
772 | wrteei 0 | ||
773 | #else | ||
774 | ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ | ||
775 | mtmsrd r10,1 | ||
776 | #endif /* CONFIG_PPC_BOOK3E */ | ||
777 | li r0,PACA_IRQ_HARD_DIS | ||
778 | stb r0,PACAIRQHAPPENED(r13) | ||
779 | |||
780 | /* Re-test flags and eventually loop */ | 770 | /* Re-test flags and eventually loop */ |
781 | clrrdi r9,r1,THREAD_SHIFT | 771 | clrrdi r9,r1,THREAD_SHIFT |
782 | ld r4,TI_FLAGS(r9) | 772 | ld r4,TI_FLAGS(r9) |
@@ -787,14 +777,6 @@ do_work: | |||
787 | user_work: | 777 | user_work: |
788 | #endif /* CONFIG_PREEMPT */ | 778 | #endif /* CONFIG_PREEMPT */ |
789 | 779 | ||
790 | /* Enable interrupts */ | ||
791 | #ifdef CONFIG_PPC_BOOK3E | ||
792 | wrteei 1 | ||
793 | #else | ||
794 | ori r10,r10,MSR_EE | ||
795 | mtmsrd r10,1 | ||
796 | #endif /* CONFIG_PPC_BOOK3E */ | ||
797 | |||
798 | andi. r0,r4,_TIF_NEED_RESCHED | 780 | andi. r0,r4,_TIF_NEED_RESCHED |
799 | beq 1f | 781 | beq 1f |
800 | bl .restore_interrupts | 782 | bl .restore_interrupts |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 43eb74fcedde..c6c6f3b7f8cd 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -260,11 +260,17 @@ EXPORT_SYMBOL(arch_local_irq_restore); | |||
260 | * if they are currently disabled. This is typically called before | 260 | * if they are currently disabled. This is typically called before |
261 | * schedule() or do_signal() when returning to userspace. We do it | 261 | * schedule() or do_signal() when returning to userspace. We do it |
262 | * in C to avoid the burden of dealing with lockdep etc... | 262 | * in C to avoid the burden of dealing with lockdep etc... |
263 | * | ||
264 | * NOTE: This is called with interrupts hard disabled but not marked | ||
265 | * as such in paca->irq_happened, so we need to resync this. | ||
263 | */ | 266 | */ |
264 | void restore_interrupts(void) | 267 | void restore_interrupts(void) |
265 | { | 268 | { |
266 | if (irqs_disabled()) | 269 | if (irqs_disabled()) { |
270 | local_paca->irq_happened |= PACA_IRQ_HARD_DIS; | ||
267 | local_irq_enable(); | 271 | local_irq_enable(); |
272 | } else | ||
273 | __hard_irq_enable(); | ||
268 | } | 274 | } |
269 | 275 | ||
270 | #endif /* CONFIG_PPC64 */ | 276 | #endif /* CONFIG_PPC64 */ |