[MIPS] irq_cpu: use handle_percpu_irq handler to avoid dropping interrupts.
authorRalf Baechle <ralf@linux-mips.org>
Thu, 15 Nov 2007 19:37:15 +0000 (19:37 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 15 Nov 2007 23:21:52 +0000 (23:21 +0000)
This matters to any sort of device that is wired to one of the CPU
interrupt pins on an SMP system.  Typically the scenario is most easily
triggered with the count/compare timer interrupt where the same interrupt
number and thus irq_desc is used on each processor.

   CPU A CPU B

   do_IRQ()
   generic_handle_irq()
   handle_level_irq()
   spin_lock(desc_lock)
   set IRQ_INPROGRESS
   spin_unlock(desc_lock)
do_IRQ()
generic_handle_irq()
handle_level_irq()
spin_lock(desc_lock)
IRQ_INPROGRESS set => bail out
   spin_lock(desc_lock)
   clear IRQ_INPROGRESS
   spin_unlock(desc_lock)

In case of the cp0 compare interrupt this means the interrupt will be
acked and not handled or re-armed on CPU b, so there won't be any timer
interrupt until the count register wraps around.

With kernels 2.6.20 ... 2.6.23 we usually were lucky that things were just
working right on VSMP because the count registers are synchronized on
bootup so it takes something that disables interrupts for a long time on
one processor to trigger this one.

For scenarios where an interrupt is multicasted or broadcasted over several
CPUs the existing code was safe and the fix will break it.  There is no
way to know in the interrupt controller code because it is abstracted from
the platform code.  I think we do not have such a setup currently, so this
should be ok.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq_cpu.c

index 2507328834886e7f6151799713cb1de5ae505fef..971adf6ef4f4d527b94c94dbff5edab0e57f78b1 100644 (file)
@@ -44,5 +44,5 @@ void __init rm7k_cpu_irq_init(void)
 
        for (i = base; i < base + 4; i++)
                set_irq_chip_and_handler(i, &rm7k_irq_controller,
 
        for (i = base; i < base + 4; i++)
                set_irq_chip_and_handler(i, &rm7k_irq_controller,
-                                        handle_level_irq);
+                                        handle_percpu_irq);
 }
 }
index ae83d2df6f31d51dc47a223b45622add5633bd76..7b04583bd800410a5a0d24e92865d0640c081b8d 100644 (file)
@@ -104,5 +104,5 @@ void __init rm9k_cpu_irq_init(void)
 
        rm9000_perfcount_irq = base + 1;
        set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
 
        rm9000_perfcount_irq = base + 1;
        set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
-                                handle_level_irq);
+                                handle_percpu_irq);
 }
 }
index 7b66e03b58994e1e7f3daf6f88ead0628a1a4e12..0ee2567b780d4c4d6496eab4ff043a19bc1f3397 100644 (file)
@@ -116,5 +116,5 @@ void __init mips_cpu_irq_init(void)
 
        for (i = irq_base + 2; i < irq_base + 8; i++)
                set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
 
        for (i = irq_base + 2; i < irq_base + 8; i++)
                set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
-                                        handle_level_irq);
+                                        handle_percpu_irq);
 }
 }