Blob Blame History Raw
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.orig/arch/x86/kernel/apic/io_apic-xen.c	2012-04-11 14:22:38.000000000 +0200
+++ head/arch/x86/kernel/apic/io_apic-xen.c	2012-04-11 17:03:35.000000000 +0200
@@ -1534,6 +1534,43 @@ static void setup_ioapic_irq(unsigned in
 	 */
 	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(attr->ioapic_pin,
+			ioapics[attr->ioapic].pin_programmed)) {
+		struct physdev_setup_gsi setup_gsi = {
+			.gsi = irq,
+			.triggering = attr->trigger,
+			.polarity = attr->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()))
--- head.orig/drivers/acpi/pci_irq.c	2012-03-19 00:15:34.000000000 +0100
+++ head/drivers/acpi/pci_irq.c	2012-02-10 11:55:35.000000000 +0100
@@ -527,3 +527,80 @@ void acpi_pci_irq_disable(struct pci_dev
 	dev_dbg(&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