forked from luck/tmp_suning_uos_patched
5359b938c0
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>
86 lines
1.8 KiB
C
86 lines
1.8 KiB
C
/*
|
|
* DEC I/O ASIC interrupts.
|
|
*
|
|
* Copyright (c) 2002, 2003 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
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <asm/dec/ioasic.h>
|
|
#include <asm/dec/ioasic_addrs.h>
|
|
#include <asm/dec/ioasic_ints.h>
|
|
|
|
static int ioasic_irq_base;
|
|
|
|
static void unmask_ioasic_irq(struct irq_data *d)
|
|
{
|
|
u32 simr;
|
|
|
|
simr = ioasic_read(IO_REG_SIMR);
|
|
simr |= (1 << (d->irq - ioasic_irq_base));
|
|
ioasic_write(IO_REG_SIMR, simr);
|
|
}
|
|
|
|
static void mask_ioasic_irq(struct irq_data *d)
|
|
{
|
|
u32 simr;
|
|
|
|
simr = ioasic_read(IO_REG_SIMR);
|
|
simr &= ~(1 << (d->irq - ioasic_irq_base));
|
|
ioasic_write(IO_REG_SIMR, simr);
|
|
}
|
|
|
|
static void ack_ioasic_irq(struct irq_data *d)
|
|
{
|
|
mask_ioasic_irq(d);
|
|
fast_iob();
|
|
}
|
|
|
|
static struct irq_chip ioasic_irq_type = {
|
|
.name = "IO-ASIC",
|
|
.irq_ack = ack_ioasic_irq,
|
|
.irq_mask = mask_ioasic_irq,
|
|
.irq_mask_ack = ack_ioasic_irq,
|
|
.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,
|
|
.irq_mask = mask_ioasic_irq,
|
|
.irq_mask_ack = ack_ioasic_irq,
|
|
.irq_unmask = unmask_ioasic_irq,
|
|
};
|
|
|
|
void __init init_ioasic_irqs(int base)
|
|
{
|
|
int i;
|
|
|
|
/* Mask interrupts. */
|
|
ioasic_write(IO_REG_SIMR, 0);
|
|
fast_iob();
|
|
|
|
for (i = base; i < base + IO_INR_DMA; i++)
|
|
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);
|
|
|
|
ioasic_irq_base = base;
|
|
}
|