Skip to content

Commit ec53646

Browse files
committed
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull another powerpc irq fix from Benjamin Herrenschmidt: "It looks like my previous fix for the lazy irq masking problem wasn't quite enough. There was another problem related to performance monitor interrupts acting as NMIs leaving the flags in an incorrect state. Here's a fix that finally seems to make perf solid again." * 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: powerpc/irq: Fix another case of lazy IRQ state getting out of sync
2 parents 04e5335 + 7c0482e commit ec53646

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

arch/powerpc/kernel/entry_64.S

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -588,23 +588,19 @@ _GLOBAL(ret_from_except_lite)
588588
fast_exc_return_irq:
589589
restore:
590590
/*
591-
* This is the main kernel exit path, we first check if we
592-
* have to change our interrupt state.
591+
* This is the main kernel exit path. First we check if we
592+
* are about to re-enable interrupts
593593
*/
594594
ld r5,SOFTE(r1)
595595
lbz r6,PACASOFTIRQEN(r13)
596-
cmpwi cr1,r5,0
597-
cmpw cr0,r5,r6
598-
beq cr0,4f
596+
cmpwi cr0,r5,0
597+
beq restore_irq_off
599598

600-
/* We do, handle disable first, which is easy */
601-
bne cr1,3f;
602-
li r0,0
603-
stb r0,PACASOFTIRQEN(r13);
604-
TRACE_DISABLE_INTS
605-
b 4f
599+
/* We are enabling, were we already enabled ? Yes, just return */
600+
cmpwi cr0,r6,1
601+
beq cr0,do_restore
606602

607-
3: /*
603+
/*
608604
* We are about to soft-enable interrupts (we are hard disabled
609605
* at this point). We check if there's anything that needs to
610606
* be replayed first.
@@ -626,7 +622,7 @@ restore_no_replay:
626622
/*
627623
* Final return path. BookE is handled in a different file
628624
*/
629-
4:
625+
do_restore:
630626
#ifdef CONFIG_PPC_BOOK3E
631627
b .exception_return_book3e
632628
#else
@@ -699,6 +695,25 @@ fast_exception_return:
699695

700696
#endif /* CONFIG_PPC_BOOK3E */
701697

698+
/*
699+
* We are returning to a context with interrupts soft disabled.
700+
*
701+
* However, we may also about to hard enable, so we need to
702+
* make sure that in this case, we also clear PACA_IRQ_HARD_DIS
703+
* or that bit can get out of sync and bad things will happen
704+
*/
705+
restore_irq_off:
706+
ld r3,_MSR(r1)
707+
lbz r7,PACAIRQHAPPENED(r13)
708+
andi. r0,r3,MSR_EE
709+
beq 1f
710+
rlwinm r7,r7,0,~PACA_IRQ_HARD_DIS
711+
stb r7,PACAIRQHAPPENED(r13)
712+
1: li r0,0
713+
stb r0,PACASOFTIRQEN(r13);
714+
TRACE_DISABLE_INTS
715+
b do_restore
716+
702717
/*
703718
* Something did happen, check if a re-emit is needed
704719
* (this also clears paca->irq_happened)
@@ -748,6 +763,9 @@ restore_check_irq_replay:
748763
#endif /* CONFIG_PPC_BOOK3E */
749764
1: b .ret_from_except /* What else to do here ? */
750765

766+
767+
768+
3:
751769
do_work:
752770
#ifdef CONFIG_PREEMPT
753771
andi. r0,r3,MSR_PR /* Returning to user mode? */

arch/powerpc/kernel/irq.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,19 @@ notrace void arch_local_irq_restore(unsigned long en)
229229
*/
230230
if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
231231
__hard_irq_disable();
232+
#ifdef CONFIG_TRACE_IRQFLAG
233+
else {
234+
/*
235+
* We should already be hard disabled here. We had bugs
236+
* where that wasn't the case so let's dbl check it and
237+
* warn if we are wrong. Only do that when IRQ tracing
238+
* is enabled as mfmsr() can be costly.
239+
*/
240+
if (WARN_ON(mfmsr() & MSR_EE))
241+
__hard_irq_disable();
242+
}
243+
#endif /* CONFIG_TRACE_IRQFLAG */
244+
232245
set_soft_enabled(0);
233246

234247
/*

0 commit comments

Comments
 (0)