aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-05-07 23:31:59 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-05-08 19:42:21 -0400
commit56dfa7fa19e36db352a94be022243ed461710119 (patch)
tree37ea957522aa18a2d3f4fb62629e9e4ca0e7f38c /arch
parent810b4de25e53459323ff48957b0162b48d6cbd57 (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.S18
-rw-r--r--arch/powerpc/kernel/irq.c8
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)
7681: bl .preempt_schedule_irq 7681: 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:
787user_work: 777user_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 */
264void restore_interrupts(void) 267void 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 */