|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* DEC I/O ASIC interrupts.
|
|
|
*
|
|
|
- * Copyright (c) 2002, 2003 Maciej W. Rozycki
|
|
|
+ * Copyright (c) 2002, 2003, 2013 Maciej W. Rozycki
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
* modify it under the terms of the GNU General Public License
|
|
@@ -51,22 +51,51 @@ static struct irq_chip ioasic_irq_type = {
|
|
|
.irq_unmask = unmask_ioasic_irq,
|
|
|
};
|
|
|
|
|
|
-void clear_ioasic_dma_irq(unsigned int irq)
|
|
|
+static void clear_ioasic_dma_irq(struct irq_data *d)
|
|
|
{
|
|
|
u32 sir;
|
|
|
|
|
|
- sir = ~(1 << (irq - ioasic_irq_base));
|
|
|
+ sir = ~(1 << (d->irq - ioasic_irq_base));
|
|
|
ioasic_write(IO_REG_SIR, sir);
|
|
|
+ fast_iob();
|
|
|
}
|
|
|
|
|
|
static struct irq_chip ioasic_dma_irq_type = {
|
|
|
.name = "IO-ASIC-DMA",
|
|
|
- .irq_ack = ack_ioasic_irq,
|
|
|
+ .irq_ack = clear_ioasic_dma_irq,
|
|
|
.irq_mask = mask_ioasic_irq,
|
|
|
- .irq_mask_ack = ack_ioasic_irq,
|
|
|
.irq_unmask = unmask_ioasic_irq,
|
|
|
+ .irq_eoi = clear_ioasic_dma_irq,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * I/O ASIC implements two kinds of DMA interrupts, informational and
|
|
|
+ * error interrupts.
|
|
|
+ *
|
|
|
+ * The formers do not stop DMA and should be cleared as soon as possible
|
|
|
+ * so that if they retrigger before the handler has completed, usually as
|
|
|
+ * a side effect of actions taken by the handler, then they are reissued.
|
|
|
+ * These use the `handle_edge_irq' handler that clears the request right
|
|
|
+ * away.
|
|
|
+ *
|
|
|
+ * The latters stop DMA and do not resume it until the interrupt has been
|
|
|
+ * cleared. This cannot be done until after a corrective action has been
|
|
|
+ * taken and this also means they will not retrigger. 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 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 mask has `1' bits in the positions of informational interrupts.
|
|
|
+ */
|
|
|
+#define IO_IRQ_DMA_INFO \
|
|
|
+ (IO_IRQ_MASK(IO_INR_SCC0A_RXDMA) | \
|
|
|
+ IO_IRQ_MASK(IO_INR_SCC1A_RXDMA) | \
|
|
|
+ IO_IRQ_MASK(IO_INR_ISDN_TXDMA) | \
|
|
|
+ IO_IRQ_MASK(IO_INR_ISDN_RXDMA) | \
|
|
|
+ IO_IRQ_MASK(IO_INR_ASC_DMA))
|
|
|
+
|
|
|
void __init init_ioasic_irqs(int base)
|
|
|
{
|
|
|
int i;
|
|
@@ -79,7 +108,9 @@ void __init init_ioasic_irqs(int base)
|
|
|
irq_set_chip_and_handler(i, &ioasic_irq_type,
|
|
|
handle_level_irq);
|
|
|
for (; i < base + IO_IRQ_LINES; i++)
|
|
|
- irq_set_chip(i, &ioasic_dma_irq_type);
|
|
|
+ irq_set_chip_and_handler(i, &ioasic_dma_irq_type,
|
|
|
+ 1 << (i - base) & IO_IRQ_DMA_INFO ?
|
|
|
+ handle_edge_irq : handle_fasteoi_irq);
|
|
|
|
|
|
ioasic_irq_base = base;
|
|
|
}
|