diff options
| -rw-r--r-- | arch/powerpc/kernel/entry_64.S | 44 | ||||
| -rw-r--r-- | arch/powerpc/kernel/irq.c | 13 |
2 files changed, 44 insertions, 13 deletions
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index fc6015027a86..ef2074c3e906 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
| @@ -588,23 +588,19 @@ _GLOBAL(ret_from_except_lite) | |||
| 588 | fast_exc_return_irq: | 588 | fast_exc_return_irq: |
| 589 | restore: | 589 | restore: |
| 590 | /* | 590 | /* |
| 591 | * This is the main kernel exit path, we first check if we | 591 | * This is the main kernel exit path. First we check if we |
| 592 | * have to change our interrupt state. | 592 | * are about to re-enable interrupts |
| 593 | */ | 593 | */ |
| 594 | ld r5,SOFTE(r1) | 594 | ld r5,SOFTE(r1) |
| 595 | lbz r6,PACASOFTIRQEN(r13) | 595 | lbz r6,PACASOFTIRQEN(r13) |
| 596 | cmpwi cr1,r5,0 | 596 | cmpwi cr0,r5,0 |
| 597 | cmpw cr0,r5,r6 | 597 | beq restore_irq_off |
| 598 | beq cr0,4f | ||
| 599 | 598 | ||
| 600 | /* We do, handle disable first, which is easy */ | 599 | /* We are enabling, were we already enabled ? Yes, just return */ |
| 601 | bne cr1,3f; | 600 | cmpwi cr0,r6,1 |
| 602 | li r0,0 | 601 | beq cr0,do_restore |
| 603 | stb r0,PACASOFTIRQEN(r13); | ||
| 604 | TRACE_DISABLE_INTS | ||
| 605 | b 4f | ||
| 606 | 602 | ||
| 607 | 3: /* | 603 | /* |
| 608 | * We are about to soft-enable interrupts (we are hard disabled | 604 | * We are about to soft-enable interrupts (we are hard disabled |
| 609 | * at this point). We check if there's anything that needs to | 605 | * at this point). We check if there's anything that needs to |
| 610 | * be replayed first. | 606 | * be replayed first. |
| @@ -626,7 +622,7 @@ restore_no_replay: | |||
| 626 | /* | 622 | /* |
| 627 | * Final return path. BookE is handled in a different file | 623 | * Final return path. BookE is handled in a different file |
| 628 | */ | 624 | */ |
| 629 | 4: | 625 | do_restore: |
| 630 | #ifdef CONFIG_PPC_BOOK3E | 626 | #ifdef CONFIG_PPC_BOOK3E |
| 631 | b .exception_return_book3e | 627 | b .exception_return_book3e |
| 632 | #else | 628 | #else |
| @@ -700,6 +696,25 @@ fast_exception_return: | |||
| 700 | #endif /* CONFIG_PPC_BOOK3E */ | 696 | #endif /* CONFIG_PPC_BOOK3E */ |
| 701 | 697 | ||
| 702 | /* | 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 | |||
| 717 | /* | ||
| 703 | * Something did happen, check if a re-emit is needed | 718 | * Something did happen, check if a re-emit is needed |
| 704 | * (this also clears paca->irq_happened) | 719 | * (this also clears paca->irq_happened) |
| 705 | */ | 720 | */ |
| @@ -748,6 +763,9 @@ restore_check_irq_replay: | |||
| 748 | #endif /* CONFIG_PPC_BOOK3E */ | 763 | #endif /* CONFIG_PPC_BOOK3E */ |
| 749 | 1: b .ret_from_except /* What else to do here ? */ | 764 | 1: b .ret_from_except /* What else to do here ? */ |
| 750 | 765 | ||
| 766 | |||
| 767 | |||
| 768 | 3: | ||
| 751 | do_work: | 769 | do_work: |
| 752 | #ifdef CONFIG_PREEMPT | 770 | #ifdef CONFIG_PREEMPT |
| 753 | andi. r0,r3,MSR_PR /* Returning to user mode? */ | 771 | andi. r0,r3,MSR_PR /* Returning to user mode? */ |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c6c6f3b7f8cd..641da9e868ce 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
| @@ -229,6 +229,19 @@ notrace void arch_local_irq_restore(unsigned long en) | |||
| 229 | */ | 229 | */ |
| 230 | if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) | 230 | if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) |
| 231 | __hard_irq_disable(); | 231 | __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 | |||
| 232 | set_soft_enabled(0); | 245 | set_soft_enabled(0); |
| 233 | 246 | ||
| 234 | /* | 247 | /* |
