From 9bcfc7daabb138b0fe3d64d74892942d482e5bbd Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Wed, 16 Mar 2011 18:05:01 +0900 Subject: ioapic: when switches to level trigger mode, interrupts raised repeatedly. - the trigger mode is edge at first - During initializatoin, the interrupt is raised as edge which is masked. The corresponding bit of irr is set. - Then the mode is switched to level and it's unmasked. - the bit of irr is set, so the interrupt is raised repeatedly by ioapic_service(). - OS considers that the irq line is broken and falls back to polling mode. This patch fixes the issues. After raising edige, clear the bit of irr. > Bringing up interface eth0: > Determining IP information for eth0...irq 18: nobody cared (try booting with the "irqpoll" option) > Pid: 4126, comm: ip Not tainted 2.6.38-rc7 #1 > Call Trace: > [] ? __report_bad_irq+0x38/0x87 > [] ? note_interrupt+0x11f/0x188 > [] ? handle_fasteoi_irq+0xa7/0xd1 > [] ? handle_irq+0x83/0x8c > [] ? do_IRQ+0x48/0xaf > [] ? ret_from_intr+0x0/0xe > [] ? __do_softirq+0x4f/0x114 > [] ? call_softirq+0x1c/0x28 > [] ? do_softirq+0x33/0x68 > [] ? irq_exit+0x36/0x38 > [] ? smp_apic_timer_interrupt+0x88/0x96 > [] ? apic_timer_interrupt+0x13/0x20 > [] ? __ioapic_set_affinity+0x68/0x7c > [] ? _raw_spin_unlock_irqrestore+0x8/0xa > [] ? __setup_irq+0x224/0x2cb > [] ? e1000_intr+0x0/0x103 > [] ? request_threaded_irq+0xd1/0x114 > [] ? e1000_request_irq+0x34/0x63 > [] ? e1000_open+0x81/0x11f > [] ? call_netdevice_notifiers+0x45/0x4a > [] ? __dev_open+0x97/0xc4 > [] ? __dev_change_flags+0xb9/0x13d > [] ? dev_change_flags+0x1c/0x51 > [] ? devinet_ioctl+0x26e/0x594 > [] ? inet_ioctl+0x92/0xaa > [] ? T.1003+0x13/0x32 > [] ? sock_ioctl+0x1f2/0x1ff > [] ? do_vfs_ioctl+0x498/0x4e7 > [] ? sock_alloc_file+0xb3/0x115 > [] ? fd_install+0x31/0x5d > [] ? sys_ioctl+0x42/0x65 > [] ? system_call_fastpath+0x16/0x1b > handlers: > [] (e1000_intr+0x0/0x103) > Disabling IRQ #18 Signed-off-by: Isaku Yamahata Signed-off-by: Aurelien Jarno --- hw/ioapic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/ioapic.c b/hw/ioapic.c index 569327d..8557e5c 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -164,6 +164,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level) if (level) { s->irr |= mask; ioapic_service(s); + s->irr &= ~mask; } } } -- cgit v1.1