Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] Use delayed disable mode of ioapic edge triggered interrupts

Komuro reports that ISA interrupts do not work after a disable_irq(),
causing some PCMCIA drivers to not work, with messages like

eth0: Asix AX88190: io 0x300, irq 3, hw_addr xx:xx:xx:xx:xx:xx
eth0: found link beat
eth0: autonegotiation complete: 100baseT-FD selected
eth0: interrupt(s) dropped!
eth0: interrupt(s) dropped!
eth0: interrupt(s) dropped!
...

Linus Torvalds <torvalds@osdl.org> said:

"Now, edge-triggered interrupts are a _lot_ harder to mask, because the
Intel APIC is an unbelievable piece of sh*t, and has the edge-detect logic
_before_ the mask logic, so if a edge happens _while_ the device is
masked, you'll never ever see the edge ever again (unmasking will not
cause a new edge, so you simply lost the interrupt).

So when you "mask" an edge-triggered IRQ, you can't really mask it at all,
because if you did that, you'd lose it forever if the IRQ comes in while
you masked it. Instead, we're supposed to leave it active, and set a flag,
and IF the IRQ comes in, we just remember it, and mask it at that point
instead, and then on unmasking, we have to replay it by sending a
self-IPI."

This trivial patch solves the problem.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Ingo Molnar <mingo@redhat.com>
Acked-by: Komuro <komurojun-mbn@nifty.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Eric W. Biederman and committed by
Linus Torvalds
45c99533 134a11f0

+6 -2
+3 -1
arch/i386/kernel/io_apic.c
··· 1287 1287 trigger == IOAPIC_LEVEL) 1288 1288 set_irq_chip_and_handler_name(irq, &ioapic_chip, 1289 1289 handle_fasteoi_irq, "fasteoi"); 1290 - else 1290 + else { 1291 + irq_desc[irq].status |= IRQ_DELAYED_DISABLE; 1291 1292 set_irq_chip_and_handler_name(irq, &ioapic_chip, 1292 1293 handle_edge_irq, "edge"); 1294 + } 1293 1295 set_intr_gate(vector, interrupt[irq]); 1294 1296 } 1295 1297
+3 -1
arch/x86_64/kernel/io_apic.c
··· 790 790 trigger == IOAPIC_LEVEL) 791 791 set_irq_chip_and_handler_name(irq, &ioapic_chip, 792 792 handle_fasteoi_irq, "fasteoi"); 793 - else 793 + else { 794 + irq_desc[irq].status |= IRQ_DELAYED_DISABLE; 794 795 set_irq_chip_and_handler_name(irq, &ioapic_chip, 795 796 handle_edge_irq, "edge"); 797 + } 796 798 } 797 799 798 800 static void __init setup_IO_APIC_irqs(void)