From: jbeulich@novell.com Subject: pass trigger mode and polarity information to Xen for all interrupts Patch-mainline: n/a For Xen to be able to use non-legacy IRQs e.g. for its serial console, it needs to know trigger mode and polarity for them regardless of whether the kernel is also going to (try to) use those interrupts. --- head-2011-01-30.orig/arch/x86/kernel/apic/io_apic-xen.c 2011-02-01 16:05:51.000000000 +0100 +++ head-2011-01-30/arch/x86/kernel/apic/io_apic-xen.c 2011-02-02 15:10:38.000000000 +0100 @@ -1400,6 +1400,10 @@ static int setup_ioapic_entry(int apic_i return 0; } +static struct { + DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); +} mp_ioapic_routing[MAX_IO_APICS]; + static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq, struct irq_cfg *cfg, int trigger, int polarity) { @@ -1416,6 +1420,42 @@ static void setup_ioapic_irq(int apic_id */ if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain)) apic->vector_allocation_domain(0, cfg->domain); +#else + /* + * For legacy IRQs we may get here before trigger mode and polarity + * get obtained, but Xen refuses to set those through + * PHYSDEVOP_setup_gsi more than once (perhaps even at all). + */ + if (irq >= legacy_pic->nr_legacy_irqs + || test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) { + struct physdev_setup_gsi setup_gsi = { + .gsi = irq, + .triggering = trigger, + .polarity = polarity + }; + struct physdev_map_pirq map_pirq = { + .domid = DOMID_SELF, + .type = MAP_PIRQ_TYPE_GSI, + .index = irq, + .pirq = irq + }; + + switch (HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, + &setup_gsi)) { + case -EEXIST: + if (irq < legacy_pic->nr_legacy_irqs) + break; + /* fall through */ + case 0: + evtchn_register_pirq(irq); + if (HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, + &map_pirq) == 0) { + /* fake (for init_IO_APIC_traps()): */ + cfg->vector = irq; + return; + } + } + } #endif if (assign_irq_vector(irq, cfg, apic->target_cpus())) @@ -1451,10 +1491,6 @@ static void setup_ioapic_irq(int apic_id ioapic_write_entry(apic_id, pin, entry); } -static struct { - DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); -} mp_ioapic_routing[MAX_IO_APICS]; - static void __init setup_IO_APIC_irqs(void) { int apic_id, pin, idx, irq, notcon = 0; --- head-2011-01-30.orig/drivers/acpi/pci_irq.c 2011-01-05 01:50:19.000000000 +0100 +++ head-2011-01-30/drivers/acpi/pci_irq.c 2011-02-02 15:10:38.000000000 +0100 @@ -469,3 +469,80 @@ void acpi_pci_irq_disable(struct pci_dev dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); acpi_unregister_gsi(gsi); } + +#if defined(CONFIG_XEN) && defined(CONFIG_PCI) +static int __init xen_setup_gsi(void) +{ + struct pci_dev *dev = NULL; + + if (acpi_noirq) + return 0; + + /* Loop body is a clone of acpi_pci_irq_enable(). */ + for_each_pci_dev(dev) { + const struct acpi_prt_entry *entry; + int gsi; + int triggering = ACPI_LEVEL_SENSITIVE; + int polarity = ACPI_ACTIVE_LOW; + struct physdev_setup_gsi setup_gsi; + + if (!dev->pin) + continue; + + entry = acpi_pci_irq_lookup(dev, dev->pin); + if (!entry) { + /* + * IDE legacy mode controller IRQs are magic. Why do + * compat extensions always make such a nasty mess. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && + (dev->class & 0x05) == 0) + continue; + } + + gsi = entry + ? entry->link + ? acpi_pci_link_allocate_irq(entry->link, + entry->index, + &triggering, &polarity, + NULL) + : entry->index + : -1; + + if (gsi >= 0) { + setup_gsi.gsi = gsi; + setup_gsi.triggering + = (triggering == ACPI_LEVEL_SENSITIVE); + setup_gsi.polarity = (polarity == ACPI_ACTIVE_LOW); + if (HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, + &setup_gsi) < 0) + continue; + + dev_info(&dev->dev, "GSI%d: %s-%s\n", gsi, + triggering == ACPI_LEVEL_SENSITIVE ? "level" + : "edge", + polarity == ACPI_ACTIVE_LOW ? "low" : "high"); + } else { + /* + * No IRQ known to the ACPI subsystem - maybe the + * BIOS / driver reported one, then use it. + */ + dev_warn(&dev->dev, "PCI INT %c: no GSI", + pin_name(dev->pin)); + /* Interrupt Line values above 0xF are forbidden */ + if (dev->irq > 0 && (dev->irq <= 0xF)) { + pr_cont(" - using IRQ %d\n", dev->irq); + setup_gsi.gsi = dev->irq; + setup_gsi.triggering = 1; + setup_gsi.polarity = 1; + VOID(HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, + &setup_gsi)); + } else + pr_cont("\n"); + } + } + + return 0; +} +subsys_initcall(xen_setup_gsi); +#endif