diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2013-09-22 16:55:19 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-10-29 16:24:42 -0400 |
commit | 0fabe1021f8bc9cffdede4ddad0dd04d43c5166c (patch) | |
tree | 0b1c61e3ef7c1858eb17603633b35c32d92933ad /arch/mips/dec/ioasic-irq.c | |
parent | 4e7f72660c39a81cc5745d5c6f23f9500f80d8d8 (diff) |
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>
Diffstat (limited to 'arch/mips/dec/ioasic-irq.c')
-rw-r--r-- | arch/mips/dec/ioasic-irq.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index 4b3e3a4375a6..e04d973ce5aa 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * DEC I/O ASIC interrupts. | 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 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -51,22 +51,51 @@ static struct irq_chip ioasic_irq_type = { | |||
51 | .irq_unmask = unmask_ioasic_irq, | 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 | u32 sir; | 56 | u32 sir; |
57 | 57 | ||
58 | sir = ~(1 << (irq - ioasic_irq_base)); | 58 | sir = ~(1 << (d->irq - ioasic_irq_base)); |
59 | ioasic_write(IO_REG_SIR, sir); | 59 | ioasic_write(IO_REG_SIR, sir); |
60 | fast_iob(); | ||
60 | } | 61 | } |
61 | 62 | ||
62 | static struct irq_chip ioasic_dma_irq_type = { | 63 | static struct irq_chip ioasic_dma_irq_type = { |
63 | .name = "IO-ASIC-DMA", | 64 | .name = "IO-ASIC-DMA", |
64 | .irq_ack = ack_ioasic_irq, | 65 | .irq_ack = clear_ioasic_dma_irq, |
65 | .irq_mask = mask_ioasic_irq, | 66 | .irq_mask = mask_ioasic_irq, |
66 | .irq_mask_ack = ack_ioasic_irq, | ||
67 | .irq_unmask = unmask_ioasic_irq, | 67 | .irq_unmask = unmask_ioasic_irq, |
68 | .irq_eoi = clear_ioasic_dma_irq, | ||
68 | }; | 69 | }; |
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)) | ||
98 | |||
70 | void __init init_ioasic_irqs(int base) | 99 | void __init init_ioasic_irqs(int base) |
71 | { | 100 | { |
72 | int i; | 101 | int i; |
@@ -79,7 +108,9 @@ void __init init_ioasic_irqs(int base) | |||
79 | irq_set_chip_and_handler(i, &ioasic_irq_type, | 108 | irq_set_chip_and_handler(i, &ioasic_irq_type, |
80 | handle_level_irq); | 109 | handle_level_irq); |
81 | for (; i < base + IO_IRQ_LINES; i++) | 110 | for (; i < base + IO_IRQ_LINES; i++) |
82 | irq_set_chip(i, &ioasic_dma_irq_type); | 111 | irq_set_chip_and_handler(i, &ioasic_dma_irq_type, |
112 | 1 << (i - base) & IO_IRQ_DMA_INFO ? | ||
113 | handle_edge_irq : handle_fasteoi_irq); | ||
83 | 114 | ||
84 | ioasic_irq_base = base; | 115 | ioasic_irq_base = base; |
85 | } | 116 | } |