aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic/io_apic.c
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2015-10-15 13:42:23 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-10-16 10:31:24 -0400
commitc0ff971ef9acacd4d2caa508e444edad958dead9 (patch)
tree9b9a890cfaf1c095149bdd49b50edfffeb5c8f06 /arch/x86/kernel/apic/io_apic.c
parent1a800589052f03ce09008f82ad2c69f0af5d315a (diff)
x86/ioapic: Disable interrupts when re-routing legacy IRQs
A sporadic hang with consequent crash is observed when booting Hyper-V Gen1 guests: Call Trace: <IRQ> [<ffffffff810ab68d>] ? trace_hardirqs_off+0xd/0x10 [<ffffffff8107b616>] queue_work_on+0x46/0x90 [<ffffffff81365696>] ? add_interrupt_randomness+0x176/0x1d0 ... <EOI> [<ffffffff81471ddb>] ? _raw_spin_unlock_irqrestore+0x3b/0x60 [<ffffffff810c295e>] __irq_put_desc_unlock+0x1e/0x40 [<ffffffff810c5c35>] irq_modify_status+0xb5/0xd0 [<ffffffff8104adbb>] mp_register_handler+0x4b/0x70 [<ffffffff8104c55a>] mp_irqdomain_alloc+0x1ea/0x2a0 [<ffffffff810c7f10>] irq_domain_alloc_irqs_recursive+0x40/0xa0 [<ffffffff810c860c>] __irq_domain_alloc_irqs+0x13c/0x2b0 [<ffffffff8104b070>] alloc_isa_irq_from_domain.isra.1+0xc0/0xe0 [<ffffffff8104bfa5>] mp_map_pin_to_irq+0x165/0x2d0 [<ffffffff8104c157>] pin_2_irq+0x47/0x80 [<ffffffff81744253>] setup_IO_APIC+0xfe/0x802 ... [<ffffffff814631c0>] ? rest_init+0x140/0x140 The issue is easily reproducible with a simple instrumentation: if mdelay(10) is put between mp_setup_entry() and mp_register_handler() calls in mp_irqdomain_alloc() Hyper-V guest always fails to boot when re-routing IRQ0. The issue seems to be caused by the fact that we don't disable interrupts while doing IOPIC programming for legacy IRQs and IRQ0 actually happens. Protect the setup sequence against concurrent interrupts. [ tglx: Make the protection unconditional and not only for legacy interrupts ] Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: Jiang Liu <jiang.liu@linux.intel.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: K. Y. Srinivasan <kys@microsoft.com> Link: http://lkml.kernel.org/r/1444930943-19336-1-git-send-email-vkuznets@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r--arch/x86/kernel/apic/io_apic.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 5c60bb162622..bb6bfc01cb82 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2907,6 +2907,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
2907 struct irq_data *irq_data; 2907 struct irq_data *irq_data;
2908 struct mp_chip_data *data; 2908 struct mp_chip_data *data;
2909 struct irq_alloc_info *info = arg; 2909 struct irq_alloc_info *info = arg;
2910 unsigned long flags;
2910 2911
2911 if (!info || nr_irqs > 1) 2912 if (!info || nr_irqs > 1)
2912 return -EINVAL; 2913 return -EINVAL;
@@ -2939,11 +2940,14 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
2939 2940
2940 cfg = irqd_cfg(irq_data); 2941 cfg = irqd_cfg(irq_data);
2941 add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin); 2942 add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
2943
2944 local_irq_save(flags);
2942 if (info->ioapic_entry) 2945 if (info->ioapic_entry)
2943 mp_setup_entry(cfg, data, info->ioapic_entry); 2946 mp_setup_entry(cfg, data, info->ioapic_entry);
2944 mp_register_handler(virq, data->trigger); 2947 mp_register_handler(virq, data->trigger);
2945 if (virq < nr_legacy_irqs()) 2948 if (virq < nr_legacy_irqs())
2946 legacy_pic->mask(virq); 2949 legacy_pic->mask(virq);
2950 local_irq_restore(flags);
2947 2951
2948 apic_printk(APIC_VERBOSE, KERN_DEBUG 2952 apic_printk(APIC_VERBOSE, KERN_DEBUG
2949 "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n", 2953 "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",