MIPS: DECstation I/O ASIC DMA interrupt classes
This change complements commits d0da7c002f7b2a93582187a9e3f73891a01d8ee4
[MIPS: DEC: Convert to new irq_chip functions] and
5359b938c0
[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>
This commit is contained in:
parent
4e7f72660c
commit
0fabe1021f
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* DEC I/O ASIC interrupts.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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,
|
.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;
|
u32 sir;
|
||||||
|
|
||||||
sir = ~(1 << (irq - ioasic_irq_base));
|
sir = ~(1 << (d->irq - ioasic_irq_base));
|
||||||
ioasic_write(IO_REG_SIR, sir);
|
ioasic_write(IO_REG_SIR, sir);
|
||||||
|
fast_iob();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip ioasic_dma_irq_type = {
|
static struct irq_chip ioasic_dma_irq_type = {
|
||||||
.name = "IO-ASIC-DMA",
|
.name = "IO-ASIC-DMA",
|
||||||
.irq_ack = ack_ioasic_irq,
|
.irq_ack = clear_ioasic_dma_irq,
|
||||||
.irq_mask = mask_ioasic_irq,
|
.irq_mask = mask_ioasic_irq,
|
||||||
.irq_mask_ack = ack_ioasic_irq,
|
|
||||||
.irq_unmask = unmask_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)
|
void __init init_ioasic_irqs(int base)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -79,7 +108,9 @@ void __init init_ioasic_irqs(int base)
|
|||||||
irq_set_chip_and_handler(i, &ioasic_irq_type,
|
irq_set_chip_and_handler(i, &ioasic_irq_type,
|
||||||
handle_level_irq);
|
handle_level_irq);
|
||||||
for (; i < base + IO_IRQ_LINES; i++)
|
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;
|
ioasic_irq_base = base;
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ static inline u32 ioasic_read(unsigned int reg)
|
|||||||
return ioasic_base[reg / 4];
|
return ioasic_base[reg / 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void clear_ioasic_dma_irq(unsigned int irq);
|
|
||||||
|
|
||||||
extern void init_ioasic_irqs(int base);
|
extern void init_ioasic_irqs(int base);
|
||||||
|
|
||||||
extern int dec_ioasic_clocksource_init(void);
|
extern int dec_ioasic_clocksource_init(void);
|
||||||
|
@ -725,7 +725,6 @@ static irqreturn_t lance_dma_merr_int(int irq, void *dev_id)
|
|||||||
{
|
{
|
||||||
struct net_device *dev = dev_id;
|
struct net_device *dev = dev_id;
|
||||||
|
|
||||||
clear_ioasic_dma_irq(irq);
|
|
||||||
printk(KERN_ERR "%s: DMA error\n", dev->name);
|
printk(KERN_ERR "%s: DMA error\n", dev->name);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -812,7 +811,7 @@ static int lance_open(struct net_device *dev)
|
|||||||
if (lp->dma_irq >= 0) {
|
if (lp->dma_irq >= 0) {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (request_irq(lp->dma_irq, lance_dma_merr_int, 0,
|
if (request_irq(lp->dma_irq, lance_dma_merr_int, IRQF_ONESHOT,
|
||||||
"lance error", dev)) {
|
"lance error", dev)) {
|
||||||
free_irq(dev->irq, dev);
|
free_irq(dev->irq, dev);
|
||||||
printk("%s: Can't get DMA IRQ %d\n", dev->name,
|
printk("%s: Can't get DMA IRQ %d\n", dev->name,
|
||||||
|
Loading…
Reference in New Issue
Block a user