On Wed, 2015-05-20 at 17:19 -0500, Suravee Suthikulpanit wrote:
Current logic does not parse the _PRT object inside the DSDT of PCI host bridge, and result in failing to route PCI legacy interrupt. This patch adds the logic to do so.
In what way is it not parsed already? This is all code used by other architectures isn't it? I think the code expects firmware to set up the _PRT for each device/slot. That seems to be the intent in acpi_pci_irq_check_entry() where device id is checked:
if (((prt->address >> 16) & 0xffff) != device || prt->pin + 1 != pin) return -ENODEV;
Signed-off-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com
drivers/acpi/pci_irq.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b1def41..671c92c 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -157,13 +157,13 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, } } -static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, +static int acpi_pci_irq_check_entry(acpi_handle handle,
struct pci_bus *pbus, int device, int pin, struct acpi_pci_routing_table *prt, struct acpi_prt_entry **entry_ptr)
{
- int segment = pci_domain_nr(dev->bus);
- int bus = dev->bus->number;
- int device = PCI_SLOT(dev->devfn);
- int segment = pci_domain_nr(pbus);
- int bus = pbus->number; struct acpi_prt_entry *entry;
if (((prt->address >> 16) & 0xffff) != device || @@ -223,7 +223,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, return 0; } -static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, +static int acpi_pci_irq_find_prt_entry(struct pci_bus *bus, int devid, int pin, struct acpi_prt_entry **entry_ptr) { acpi_status status; @@ -231,8 +231,8 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, struct acpi_pci_routing_table *entry; acpi_handle handle = NULL;
- if (dev->bus->bridge)
handle = ACPI_HANDLE(dev->bus->bridge);
- if (bus->bridge)
handle = ACPI_HANDLE(bus->bridge);
if (!handle) return -ENODEV; @@ -246,8 +246,8 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, entry = buffer.pointer; while (entry && (entry->length > 0)) {
if (!acpi_pci_irq_check_entry(handle, dev, pin,
entry, entry_ptr))
if (!acpi_pci_irq_check_entry(handle, bus, devid,
entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length);pin, entry, entry_ptr)) break;
@@ -322,7 +322,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) u8 bridge_pin, orig_pin = pin; int ret;
- ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry);
- ret = acpi_pci_irq_find_prt_entry(dev->bus, PCI_SLOT(dev->devfn), pin, &entry); if (!ret && entry) {
#ifdef CONFIG_X86_IO_APIC acpi_reroute_boot_interrupt(dev, entry); @@ -336,7 +336,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) * Attempt to derive an IRQ for this device from a parent bridge's * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */
- bridge = dev->bus->self;
- bridge = pci_upstream_bridge(dev); while (bridge) { pin = pci_swizzle_interrupt_pin(dev, pin);
@@ -352,7 +352,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) pin = bridge_pin; }
ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry);
if (!ret && entry) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived GSI for %s INT %c from %s\n",ret = acpi_pci_irq_find_prt_entry(bridge->bus, PCI_SLOT(bridge->devfn), pin, &entry);
@@ -362,7 +362,27 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) } dev = bridge;
bridge = dev->bus->self;
bridge = pci_upstream_bridge(dev);
- }
- if (!bridge) {
struct device *hb_dev = pci_get_host_bridge_device(dev);
struct pci_host_bridge *h_br = NULL;
if (hb_dev)
h_br = to_pci_host_bridge(hb_dev);
if (h_br)
ret = acpi_pci_irq_find_prt_entry(h_br->bus, 0, pin,
&entry);
pci_put_host_bridge_device(hdev);
if (!ret && entry) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Derived GSI for %s INT %c from %s\n",
pci_name(dev), pin_name(orig_pin),
"host bridge"));
return entry;
}}
dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",