You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qubes-linux-kernel/patches.xen/xen-setup-gsi

159 lines
4.6 KiB

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