]> git.hungrycats.org Git - linux/commitdiff
[PATCH] ppc32: Fix problem with spurrious edge interrupts on old
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 2 Aug 2004 17:50:08 +0000 (10:50 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 2 Aug 2004 17:50:08 +0000 (10:50 -0700)
On old powermacs, it's possible that we get a stale edge interrupt when
doing request_irq(), that typically happens with the DBDMA controller
interrupts when the device was used by the firmware for booting.

I just tracked down a nasty memory corruption problem where that was
causing the bmac driver to try to process packets before the driver
internal data structures were properly initialized.

While I agree that the driver should (and will) be made more robust to
such things, Paulus and I decided that it makes little sense to keep
track of an "old" edge interrupt that happens before a driver does
request_irq.  (On those powermacs, those are only the DBDMA interrupts
anyway, and none of the DBDMA users will care).

This patch implements a "startup" handler for the old Apple PIC that
will "ack" pending edge interrupts before unmasking, thus preventing
those stale interrupts to be delivered.

It also "fixes" the ppc32 irq core to call the startup() callback when
available instead of just calling enable().

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc/kernel/irq.c
arch/ppc/platforms/pmac_pic.c

index 6bb1fcc04c2c8ab3c85a6cf4eefb756da7939cef..2ac2e4b55225909210c45e64286d5a625b6bd9da 100644 (file)
@@ -171,7 +171,12 @@ setup_irq(unsigned int irq, struct irqaction * new)
        if (!shared) {
                desc->depth = 0;
                desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
-               unmask_irq(irq);
+               if (desc->handler) {
+                       if (desc->handler->startup)
+                               desc->handler->startup(irq);
+                       else if (desc->handler->enable)
+                               desc->handler->enable(irq);
+               }
        }
        spin_unlock_irqrestore(&desc->lock,flags);
 
index 5566d7bc96852a27dd08ebf817b618069e3d18c0..bebba87931eeb81d95408433fe4d80e9a0330c92 100644 (file)
@@ -144,6 +144,22 @@ static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
        spin_unlock_irqrestore(&pmac_pic_lock, flags);
 }
 
+/* When an irq gets requested for the first client, if it's an
+ * edge interrupt, we clear any previous one on the controller
+ */
+static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+       if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+               out_le32(&pmac_irq_hw[i]->ack, bit);
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+
+       return 0;
+}
+
 static void __pmac pmac_mask_irq(unsigned int irq_nr)
 {
         clear_bit(irq_nr, ppc_cached_irq_mask);
@@ -168,25 +184,21 @@ static void __pmac pmac_end_irq(unsigned int irq_nr)
 
 
 struct hw_interrupt_type pmac_pic = {
-        " PMAC-PIC ",
-        NULL,
-        NULL,
-        pmac_unmask_irq,
-        pmac_mask_irq,
-        pmac_mask_and_ack_irq,
-        pmac_end_irq,
-        NULL
+       .typename       = " PMAC-PIC ",
+       .startup        = pmac_startup_irq,
+       .enable         = pmac_unmask_irq,
+       .disable        = pmac_mask_irq,
+       .ack            = pmac_mask_and_ack_irq,
+       .end            = pmac_end_irq,
 };
 
 struct hw_interrupt_type gatwick_pic = {
-       " GATWICK  ",
-       NULL,
-       NULL,
-       pmac_unmask_irq,
-       pmac_mask_irq,
-       pmac_mask_and_ack_irq,
-       pmac_end_irq,
-       NULL
+       .typename       = " GATWICK  ",
+       .startup        = pmac_startup_irq,
+       .enable         = pmac_unmask_irq,
+       .disable        = pmac_mask_irq,
+       .ack            = pmac_mask_and_ack_irq,
+       .end            = pmac_end_irq,
 };
 
 static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)