diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 9c79703..fd7f4ba 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -47,11 +47,7 @@ static struct irq_chip i8259A_chip = { /* * This contains the irq mask for both 8259A irq controllers, */ -static unsigned int cached_irq_mask = 0xffff; - -#define cached_master_mask (cached_irq_mask) -#define cached_slave_mask (cached_irq_mask >> 8) - +unsigned int cached_irq_mask = 0xffff; void disable_8259A_irq(unsigned int irq) { unsigned int mask; diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h index e88a016..e7dcf7b 100644 --- a/include/asm-mips/i8259.h +++ b/include/asm-mips/i8259.h @@ -37,11 +37,55 @@ extern spinlock_t i8259A_lock; +extern unsigned int cached_irq_mask; +#define cached_master_mask (cached_irq_mask) +#define cached_slave_mask (cached_irq_mask >> 8) + extern void init_8259A(int auto_eoi); extern void enable_8259A_irq(unsigned int irq); extern void disable_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); +#define CONFIG_NO_INTERRUPT_ACK +#ifdef CONFIG_NO_INTERRUPT_ACK +static inline int _byte_ffs(u8 word) +{ + int num = 0; + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +static inline int read_irq(int port) +{ + int irq; + outb(0x0A, port); + if (port == PIC_MASTER_CMD) { + irq = inb(port) & ~cached_master_mask; + } else { + irq = inb(port) & ~cached_slave_mask; + } + if (irq == 0) + return -1; + else + return _byte_ffs(irq); +} +#else +static inline int read_irq(int port) +{ + /* Perform an interrupt acknowledge cycle on controller 1. */ + outb(0x0C, port); /* prepare for poll */ + return inb(port) & 7; +} +#endif /* * Do the traditional i8259 interrupt polling thing. This is for the few @@ -54,18 +98,16 @@ static inline int i8259_irq(void) spin_lock(&i8259A_lock); - /* Perform an interrupt acknowledge cycle on controller 1. */ - outb(0x0C, PIC_MASTER_CMD); /* prepare for poll */ - irq = inb(PIC_MASTER_CMD) & 7; + irq = read_irq(PIC_MASTER_CMD); if (irq == PIC_CASCADE_IR) { /* * Interrupt is cascaded so perform interrupt * acknowledge on controller 2. */ - outb(0x0C, PIC_SLAVE_CMD); /* prepare for poll */ - irq = (inb(PIC_SLAVE_CMD) & 7) + 8; - } + irq = read_irq(PIC_SLAVE_CMD) + 8; + } +#ifndef CONFIG_NO_INTERRUPT_ACK if (unlikely(irq == 7)) { /* * This may be a spurious interrupt. @@ -78,6 +120,11 @@ static inline int i8259_irq(void) if(~inb(PIC_MASTER_ISR) & 0x80) irq = -1; } +#else + if (cached_irq_mask & (1 << irq)) { + irq = -1; + } +#endif spin_unlock(&i8259A_lock);