Merge tag 'powerpc-5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / arch / powerpc / kernel / irq.c
index 4788522..086b0a7 100644 (file)
@@ -181,13 +181,18 @@ void notrace restore_interrupts(void)
 
 void replay_soft_interrupts(void)
 {
+       struct pt_regs regs;
+
        /*
-        * We use local_paca rather than get_paca() to avoid all
-        * the debug_smp_processor_id() business in this low level
-        * function
+        * Be careful here, calling these interrupt handlers can cause
+        * softirqs to be raised, which they may run when calling irq_exit,
+        * which will cause local_irq_enable() to be run, which can then
+        * recurse into this function. Don't keep any state across
+        * interrupt handler calls which may change underneath us.
+        *
+        * We use local_paca rather than get_paca() to avoid all the
+        * debug_smp_processor_id() business in this low level function.
         */
-       unsigned char happened = local_paca->irq_happened;
-       struct pt_regs regs;
 
        ppc_save_regs(&regs);
        regs.softe = IRQS_ENABLED;
@@ -210,7 +215,7 @@ again:
         * This is a higher priority interrupt than the others, so
         * replay it first.
         */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) {
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) {
                local_paca->irq_happened &= ~PACA_IRQ_HMI;
                regs.trap = 0xe60;
                handle_hmi_exception(&regs);
@@ -218,7 +223,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (happened & PACA_IRQ_DEC) {
+       if (local_paca->irq_happened & PACA_IRQ_DEC) {
                local_paca->irq_happened &= ~PACA_IRQ_DEC;
                regs.trap = 0x900;
                timer_interrupt(&regs);
@@ -226,7 +231,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (happened & PACA_IRQ_EE) {
+       if (local_paca->irq_happened & PACA_IRQ_EE) {
                local_paca->irq_happened &= ~PACA_IRQ_EE;
                regs.trap = 0x500;
                do_IRQ(&regs);
@@ -234,7 +239,7 @@ again:
                        hard_irq_disable();
        }
 
-       if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) {
+       if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) {
                local_paca->irq_happened &= ~PACA_IRQ_DBELL;
                if (IS_ENABLED(CONFIG_PPC_BOOK3E))
                        regs.trap = 0x280;
@@ -246,7 +251,7 @@ again:
        }
 
        /* Book3E does not support soft-masking PMI interrupts */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) {
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) {
                local_paca->irq_happened &= ~PACA_IRQ_PMI;
                regs.trap = 0xf00;
                performance_monitor_exception(&regs);
@@ -254,8 +259,7 @@ again:
                        hard_irq_disable();
        }
 
-       happened = local_paca->irq_happened;
-       if (happened & ~PACA_IRQ_HARD_DIS) {
+       if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) {
                /*
                 * We are responding to the next interrupt, so interrupt-off
                 * latencies should be reset here.