MIPS: DECstation I/O ASIC DMA interrupt handling fix
authorMaciej W. Rozycki <macro@linux-mips.org>
Thu, 12 Sep 2013 11:14:31 +0000 (12:14 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 13 Sep 2013 09:57:40 +0000 (11:57 +0200)
This change complements commit d0da7c002f7b2a93582187a9e3f73891a01d8ee4
and brings clear_ioasic_irq back, renaming it to clear_ioasic_dma_irq at
the same time, to make I/O ASIC DMA interrupts functional.

Unlike ordinary I/O ASIC interrupts DMA interrupts need to be deasserted
by software by writing 0 to the respective bit in I/O ASIC's System
Interrupt Register (SIR), similarly to how CP0.Cause.IP0 and CP0.Cause.IP1
bits are handled in the CPU (the difference is SIR DMA interrupt bits are
R/W0C so there's no need for an RMW cycle).  Otherwise the handler is
reentered over and over again.

The only current user is the DEC LANCE Ethernet driver and its extremely
uncommon DMA memory error handler that does not care when exactly the
interrupt is cleared.  Anticipating the use of DMA interrupts by the Zilog
SCC driver this change however exports clear_ioasic_dma_irq for device
drivers to choose the right application-specific sequence to clear the
request explicitly rather than calling it implicitly in the .irq_eoi
handler of `struct irq_chip'.  Previously these interrupts were cleared in
the .end handler of the said structure, before it was removed.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/5826/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/dec/ioasic-irq.c
arch/mips/include/asm/dec/ioasic.h
drivers/net/ethernet/amd/declance.c

index 824e08c737981d8d9be039892b49f876b4c54bd0..4b3e3a4375a6756b2af743c3f163d50055fb2c45 100644 (file)
@@ -51,6 +51,14 @@ static struct irq_chip ioasic_irq_type = {
        .irq_unmask = unmask_ioasic_irq,
 };
 
+void clear_ioasic_dma_irq(unsigned int irq)
+{
+       u32 sir;
+
+       sir = ~(1 << (irq - ioasic_irq_base));
+       ioasic_write(IO_REG_SIR, sir);
+}
+
 static struct irq_chip ioasic_dma_irq_type = {
        .name = "IO-ASIC-DMA",
        .irq_ack = ack_ioasic_irq,
index be4d62a5a10ee203c8d2c9b16dc4ffda9551a493..a6e505a0e44b4b119a6967fd5f8938ffb211a73e 100644 (file)
@@ -31,6 +31,8 @@ static inline u32 ioasic_read(unsigned int reg)
        return ioasic_base[reg / 4];
 }
 
+extern void clear_ioasic_dma_irq(unsigned int irq);
+
 extern void init_ioasic_irqs(int base);
 
 extern int dec_ioasic_clocksource_init(void);
index 3d86ffeb4e15919b0b3efb21205b4195127ba79d..94edc9c6fbbf317765d41d8d4ba9cfc6b817ec20 100644 (file)
@@ -725,6 +725,7 @@ static irqreturn_t lance_dma_merr_int(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
 
+       clear_ioasic_dma_irq(irq);
        printk(KERN_ERR "%s: DMA error\n", dev->name);
        return IRQ_HANDLED;
 }