--- 2.4/arch/i386/kernel/io_apic.c Fri Feb 2 15:51:57 2001 +++ build-2.4/arch/i386/kernel/io_apic.c Fri Feb 2 23:04:44 2001 @@ -115,10 +115,10 @@ /* * It appears there is an erratum which affects at least the 82093AA - * I/O APIC. If a level-triggered interrupt input is being masked in - * the redirection entry while the interrupt is send pending (its - * delivery status bit is set), the interrupt is erroneously - * delivered as edge-triggered but the IRR bit gets set nevertheless. + * I/O APIC. If a level-triggered interrupt input is being unmasked in + * the redirection entry while the interrupt line is active, then + * the interrupt is erroneously delivered as edge-triggered but the + * IRR bit gets set nevertheless. * As a result the I/O unit expects an EOI message but it will never * arrive and further interrupts are blocked for the source. * @@ -126,12 +126,8 @@ * a level-triggered interrupt and to revert the mode when unmasking. * The idea is from Manfred Spraul. */ -DO_ACTION( __mask, 0, = (reg & 0xffff7fff) | 0x00010000, - io_apic_sync(entry->apic)) /* mask = 1, trigger = edge */ -DO_ACTION( __unmask_edge, 0, &= 0xfffeffff, - ) /* mask = 0 */ -DO_ACTION( __unmask_level, 0, = (reg & 0xfffeffff) | 0x00008000, - ) /* mask = 0, trigger = level */ +DO_ACTION( __mask, 0, = (reg & 0xffff7fff) | 0x00010000, io_apic_sync(entry->apic)) /* mask = 1 */ +DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ static void mask_IO_APIC_irq (unsigned int irq) { @@ -142,26 +138,15 @@ spin_unlock_irqrestore(&ioapic_lock, flags); } -static void unmask_edge_IO_APIC_irq (unsigned int irq) +static void unmask_IO_APIC_irq (unsigned int irq) { unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - __unmask_edge_IO_APIC_irq(irq); + __unmask_IO_APIC_irq(irq); spin_unlock_irqrestore(&ioapic_lock, flags); } -static void unmask_level_IO_APIC_irq (unsigned int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&ioapic_lock, flags); - __unmask_level_IO_APIC_irq(irq); - spin_unlock_irqrestore(&ioapic_lock, flags); -} - -#define unmask_IO_APIC_irq unmask_edge_IO_APIC_irq - void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -712,7 +697,7 @@ printk(KERN_WARNING " to linux-smp@vger.kernel.org\n"); } -void __init print_IO_APIC(void) +void print_IO_APIC(void) { int apic, i; struct IO_APIC_reg_00 reg_00; @@ -1117,7 +1102,7 @@ * that was delayed but this is now handled in the device * independent code. */ -#define enable_edge_ioapic_irq unmask_edge_IO_APIC_irq +#define enable_edge_ioapic_irq unmask_IO_APIC_irq static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } @@ -1142,7 +1127,7 @@ if (i8259A_irq_pending(irq)) was_pending = 1; } - __unmask_edge_IO_APIC_irq(irq); + __unmask_IO_APIC_irq(irq); spin_unlock_irqrestore(&ioapic_lock, flags); return was_pending; @@ -1182,21 +1167,66 @@ */ static unsigned int startup_level_ioapic_irq (unsigned int irq) { - unmask_level_IO_APIC_irq(irq); + unmask_IO_APIC_irq(irq); return 0; /* don't check for pending */ } #define shutdown_level_ioapic_irq mask_IO_APIC_irq -#define enable_level_ioapic_irq unmask_level_IO_APIC_irq -#define disable_level_ioapic_irq mask_IO_APIC_irq + +static void enable_level_ioapic_irq (unsigned int i) +{ + unsigned long flags; + int pin; + struct irq_pin_list *entry; + + spin_lock_irqsave(&ioapic_lock, flags); + entry = irq_2_pin + i; + + for (;;) { + unsigned int reg, reg2; + pin = entry->pin; + if (pin == -1) + break; + reg = io_apic_read(entry->apic, 0x10 + pin*2); + if(!(reg & 0x10000)) { + printk(KERN_DEBUG "quick enable_level_ioapic_irq for %d.\n",i); + break; + } + reg &= ~(0x10000); + reg |= 0x8000; + printk(KERN_DEBUG "physically reenabling int %d, writing %lxh.\n",i, reg); +reg2 = io_apic_read(entry->apic, 0x10 + pin*2); + io_apic_modify(entry->apic, reg); +printk(KERN_DEBUG "overwriting %xh.\n",reg2); + io_apic_sync(entry->apic); +reg2 = io_apic_read(entry->apic, 0x10 + pin*2); +printk(KERN_DEBUG "new val %xh.\n",reg2); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } + + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void disable_level_ioapic_irq (unsigned int i) { /* delayed */ } static void end_level_ioapic_irq (unsigned int i) { ack_APIC_irq(); } -static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } +static void mask_and_ack_level_ioapic_irq (unsigned int i) +{ + if(i == 16) + printk(KERN_DEBUG "irq 0x16 seen on cpu %d.\n", + smp_processor_id()); + if (irq_desc[i].status & IRQ_DISABLED) { + mask_IO_APIC_irq(i); + printk(KERN_DEBUG "physically disabling int %d.\n",i); + } +} static void set_ioapic_affinity (unsigned int irq, unsigned long mask) {