Commit f672c392 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Jesse Barnes
Browse files

x86/PCI: use config space encoding for interrupt pins



Keep "pin" encoded as it is in the "Interrupt Pin" value in PCI config
space, i.e., 0=device doesn't use interrupts, 1=INTA, ..., 4=INTD.

This makes the bridge INTx swizzle match other architectures.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: hpa@zytor.com
Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 878f2e50
Loading
Loading
Loading
Loading
+20 −24
Original line number Diff line number Diff line
@@ -887,7 +887,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
		dev_dbg(&dev->dev, "no interrupt pin\n");
		return 0;
	}
	pin = pin - 1;

	/* Find IRQ routing entry */

@@ -897,17 +896,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
	info = pirq_get_info(dev);
	if (!info) {
		dev_dbg(&dev->dev, "PCI INT %c not found in routing table\n",
			'A' + pin);
			'A' + pin - 1);
		return 0;
	}
	pirq = info->irq[pin].link;
	mask = info->irq[pin].bitmap;
	pirq = info->irq[pin - 1].link;
	mask = info->irq[pin - 1].bitmap;
	if (!pirq) {
		dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin);
		dev_dbg(&dev->dev, "PCI INT %c not routed\n", 'A' + pin - 1);
		return 0;
	}
	dev_dbg(&dev->dev, "PCI INT %c -> PIRQ %02x, mask %04x, excl %04x",
		'A' + pin, pirq, mask, pirq_table->exclusive_irqs);
		'A' + pin - 1, pirq, mask, pirq_table->exclusive_irqs);
	mask &= pcibios_irq_mask;

	/* Work around broken HP Pavilion Notebooks which assign USB to
@@ -949,7 +948,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
				newirq = i;
		}
	}
	dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin, newirq);
	dev_dbg(&dev->dev, "PCI INT %c -> newirq %d", 'A' + pin - 1, newirq);

	/* Check if it is hardcoded */
	if ((pirq & 0xf0) == 0xf0) {
@@ -977,18 +976,18 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
			return 0;
		}
	}
	dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin, irq);
	dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin - 1, irq);

	/* Update IRQ for all devices with the same pirq value */
	while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
		if (!pin)
			continue;
		pin--;

		info = pirq_get_info(dev2);
		if (!info)
			continue;
		if (info->irq[pin].link == pirq) {
		if (info->irq[pin - 1].link == pirq) {
			/*
			 * We refuse to override the dev->irq
			 * information. Give a warning!
@@ -1055,9 +1054,8 @@ static void __init pcibios_fixup_irqs(void)
			/*
			 * interrupt pins are numbered starting from 1
			 */
			pin--;
			irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
				PCI_SLOT(dev->devfn), pin);
				PCI_SLOT(dev->devfn), pin - 1);
			/*
			 * Busses behind bridges are typically not listed in the
			 * MP-table.  In this case we have to look up the IRQ
@@ -1070,22 +1068,22 @@ static void __init pcibios_fixup_irqs(void)
				struct pci_dev *bridge = dev->bus->self;
				int bus;

				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
				pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
				bus = bridge->bus->number;
				irq = IO_APIC_get_PCI_irq_vector(bus,
						PCI_SLOT(bridge->devfn), pin);
						PCI_SLOT(bridge->devfn), pin - 1);
				if (irq >= 0)
					dev_warn(&dev->dev,
						"using bridge %s INT %c to "
							"get IRQ %d\n",
						 pci_name(bridge),
						 'A' + pin, irq);
						 'A' + pin - 1, irq);
			}
			if (irq >= 0) {
				dev_info(&dev->dev,
					"PCI->APIC IRQ transform: INT %c "
						"-> IRQ %d\n",
					'A' + pin, irq);
					'A' + pin - 1, irq);
				dev->irq = irq;
			}
		}
@@ -1220,12 +1218,10 @@ static int pirq_enable_irq(struct pci_dev *dev)
	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
		char *msg = "";

		pin--; /* interrupt pins are numbered starting from 1 */

		if (io_apic_assign_pci_irqs) {
			int irq;

			irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
			irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin - 1);
			/*
			 * Busses behind bridges are typically not listed in the MP-table.
			 * In this case we have to look up the IRQ based on the parent bus,
@@ -1236,20 +1232,20 @@ static int pirq_enable_irq(struct pci_dev *dev)
			while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
				struct pci_dev *bridge = dev->bus->self;

				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
				pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
				irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
						PCI_SLOT(bridge->devfn), pin);
						PCI_SLOT(bridge->devfn), pin - 1);
				if (irq >= 0)
					dev_warn(&dev->dev, "using bridge %s "
						 "INT %c to get IRQ %d\n",
						 pci_name(bridge), 'A' + pin,
						 pci_name(bridge), 'A' + pin - 1,
						 irq);
				dev = bridge;
			}
			dev = temp_dev;
			if (irq >= 0) {
				dev_info(&dev->dev, "PCI->APIC IRQ transform: "
					 "INT %c -> IRQ %d\n", 'A' + pin, irq);
					 "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
				dev->irq = irq;
				return 0;
			} else
@@ -1268,7 +1264,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
			return 0;

		dev_warn(&dev->dev, "can't find IRQ for PCI INT %c%s\n",
			 'A' + pin, msg);
			 'A' + pin - 1, msg);
	}
	return 0;
}