Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: DECstation I/O ASIC DMA interrupt classes

This change complements commits d0da7c002f7b2a93582187a9e3f73891a01d8ee4
[MIPS: DEC: Convert to new irq_chip functions] and
5359b938c088423a28c41499f183cd10824c1816 [MIPS: DECstation I/O ASIC DMA
interrupt handling fix] and implements automatic handling of the two
classes of DMA interrupts the I/O ASIC implements, informational and
errors.

Informational DMA interrupts do not stop the transfer and use the
`handle_edge_irq' handler that clears the request right away so that
another request may be recorded while the previous is being handled.

DMA error interrupts stop the transfer and require a corrective action
before DMA can be reenabled. Therefore they use the `handle_fasteoi_irq'
handler that only clears the request on the way out. Because MIPS
processor interrupt inputs, one of which the I/O ASIC's interrupt
controller is cascaded to, are level-triggered it is recommended that
error DMA interrupt action handlers are registered with the IRQF_ONESHOT
flag set so that they are run with the interrupt line masked.

This change removes the export of clear_ioasic_dma_irq that now does not
have to be called by device drivers to clear interrupts explicitly
anymore. Originally these interrupts were cleared in the .end handler of
the `irq_chip' 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/5874/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Maciej W. Rozycki and committed by
Ralf Baechle
0fabe102 4e7f7266

+38 -10
+37 -6
arch/mips/dec/ioasic-irq.c
··· 1 1 /* 2 2 * DEC I/O ASIC interrupts. 3 3 * 4 - * Copyright (c) 2002, 2003 Maciej W. Rozycki 4 + * Copyright (c) 2002, 2003, 2013 Maciej W. Rozycki 5 5 * 6 6 * This program is free software; you can redistribute it and/or 7 7 * modify it under the terms of the GNU General Public License ··· 51 51 .irq_unmask = unmask_ioasic_irq, 52 52 }; 53 53 54 - void clear_ioasic_dma_irq(unsigned int irq) 54 + static void clear_ioasic_dma_irq(struct irq_data *d) 55 55 { 56 56 u32 sir; 57 57 58 - sir = ~(1 << (irq - ioasic_irq_base)); 58 + sir = ~(1 << (d->irq - ioasic_irq_base)); 59 59 ioasic_write(IO_REG_SIR, sir); 60 + fast_iob(); 60 61 } 61 62 62 63 static struct irq_chip ioasic_dma_irq_type = { 63 64 .name = "IO-ASIC-DMA", 64 - .irq_ack = ack_ioasic_irq, 65 + .irq_ack = clear_ioasic_dma_irq, 65 66 .irq_mask = mask_ioasic_irq, 66 - .irq_mask_ack = ack_ioasic_irq, 67 67 .irq_unmask = unmask_ioasic_irq, 68 + .irq_eoi = clear_ioasic_dma_irq, 68 69 }; 70 + 71 + /* 72 + * I/O ASIC implements two kinds of DMA interrupts, informational and 73 + * error interrupts. 74 + * 75 + * The formers do not stop DMA and should be cleared as soon as possible 76 + * so that if they retrigger before the handler has completed, usually as 77 + * a side effect of actions taken by the handler, then they are reissued. 78 + * These use the `handle_edge_irq' handler that clears the request right 79 + * away. 80 + * 81 + * The latters stop DMA and do not resume it until the interrupt has been 82 + * cleared. This cannot be done until after a corrective action has been 83 + * taken and this also means they will not retrigger. Therefore they use 84 + * the `handle_fasteoi_irq' handler that only clears the request on the 85 + * way out. Because MIPS processor interrupt inputs, one of which the I/O 86 + * ASIC is cascaded to, are level-triggered it is recommended that error 87 + * DMA interrupt action handlers are registered with the IRQF_ONESHOT flag 88 + * set so that they are run with the interrupt line masked. 89 + * 90 + * This mask has `1' bits in the positions of informational interrupts. 91 + */ 92 + #define IO_IRQ_DMA_INFO \ 93 + (IO_IRQ_MASK(IO_INR_SCC0A_RXDMA) | \ 94 + IO_IRQ_MASK(IO_INR_SCC1A_RXDMA) | \ 95 + IO_IRQ_MASK(IO_INR_ISDN_TXDMA) | \ 96 + IO_IRQ_MASK(IO_INR_ISDN_RXDMA) | \ 97 + IO_IRQ_MASK(IO_INR_ASC_DMA)) 69 98 70 99 void __init init_ioasic_irqs(int base) 71 100 { ··· 108 79 irq_set_chip_and_handler(i, &ioasic_irq_type, 109 80 handle_level_irq); 110 81 for (; i < base + IO_IRQ_LINES; i++) 111 - irq_set_chip(i, &ioasic_dma_irq_type); 82 + irq_set_chip_and_handler(i, &ioasic_dma_irq_type, 83 + 1 << (i - base) & IO_IRQ_DMA_INFO ? 84 + handle_edge_irq : handle_fasteoi_irq); 112 85 113 86 ioasic_irq_base = base; 114 87 }
-2
arch/mips/include/asm/dec/ioasic.h
··· 31 31 return ioasic_base[reg / 4]; 32 32 } 33 33 34 - extern void clear_ioasic_dma_irq(unsigned int irq); 35 - 36 34 extern void init_ioasic_irqs(int base); 37 35 38 36 extern int dec_ioasic_clocksource_init(void);
+1 -2
drivers/net/ethernet/amd/declance.c
··· 725 725 { 726 726 struct net_device *dev = dev_id; 727 727 728 - clear_ioasic_dma_irq(irq); 729 728 printk(KERN_ERR "%s: DMA error\n", dev->name); 730 729 return IRQ_HANDLED; 731 730 } ··· 811 812 if (lp->dma_irq >= 0) { 812 813 unsigned long flags; 813 814 814 - if (request_irq(lp->dma_irq, lance_dma_merr_int, 0, 815 + if (request_irq(lp->dma_irq, lance_dma_merr_int, IRQF_ONESHOT, 815 816 "lance error", dev)) { 816 817 free_irq(dev->irq, dev); 817 818 printk("%s: Can't get DMA IRQ %d\n", dev->name,