Home Home > GIT Browse > openSUSE-15.1
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2004-08-02 10:50:08 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-08-02 10:50:08 -0700
commit7588ab9742b3ae0ecebcb32fca1374deda97e73f (patch)
treedce5d47bc706bd7f39a9e854ad1ca6c15e304122
parent1737ddec952b0b386276516573baff59f58cc6f9 (diff)
[PATCH] ppc32: Fix problem with spurrious edge interrupts on old
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>
-rw-r--r--arch/ppc/kernel/irq.c7
-rw-r--r--arch/ppc/platforms/pmac_pic.c44
2 files changed, 34 insertions, 17 deletions
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 6bb1fcc04c2c..2ac2e4b55225 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -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);
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
index 5566d7bc9685..bebba87931ee 100644
--- a/arch/ppc/platforms/pmac_pic.c
+++ b/arch/ppc/platforms/pmac_pic.c
@@ -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)