ChangeSet 1.1692.3.5, 2004/03/26 16:32:52-08:00, willy@debian.org [PATCH] PCI Hotplug: Rewrite acpiphp detect_used_resource There are two unrelated problems in acpiphp that are fixed by this patch. First, acpiphp can be a module, so it is unsafe to probe the BARs of each device while it initialises -- the device may be active at the time. Second, it does not know about PCI-PCI bridge registers and so it reads garbage for the last 4 registers of the PCI-PCI bridge card and doesn't take into account the ranges that are forwarded by the bridge. This patch avoids all that by using the struct resources embedded in the pci_dev. Note that we no longer need to recurse as all the devices on the other side of a PCI-PCI bridge have their resources entirely contained within the PCI-PCI bridge's ranges. drivers/pci/hotplug/acpiphp_pci.c | 110 ++++++++------------------------------ 1 files changed, 26 insertions(+), 84 deletions(-) diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c --- a/drivers/pci/hotplug/acpiphp_pci.c Thu Apr 15 10:05:40 2004 +++ b/drivers/pci/hotplug/acpiphp_pci.c Thu Apr 15 10:05:40 2004 @@ -198,106 +198,42 @@ /* detect_used_resource - subtract resource under dev from bridge */ static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) { - u32 bar, len; - u64 base; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; int count; - struct pci_resource *res; dbg("Device %s\n", pci_name(dev)); - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); + for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) { + struct pci_resource *res; + struct pci_resource **head; + unsigned long base = dev->resource[count].start; + unsigned long len = dev->resource[count].end - base + 1; + unsigned long flags = dev->resource[count].flags; - if (!bar) /* This BAR is not implemented */ + if (!flags) continue; - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); + dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base, + base + len - 1, flags); - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); - len = len & ~(len - 1); - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->io_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); + if (flags & IORESOURCE_IO) { + head = &bridge->io_head; + } else if (flags & IORESOURCE_PREFETCH) { + head = &bridge->p_mem_head; } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } + head = &bridge->mem_head; } - pci_write_config_dword(dev, address[count], bar); + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); } return 0; } -/* detect_pci_resource_bus - subtract resource under pci_bus */ -static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus) -{ - struct list_head *l; - struct pci_dev *dev; - - list_for_each (l, &bus->devices) { - dev = pci_dev_b(l); - detect_used_resource(bridge, dev); - /* XXX recursive call */ - if (dev->subordinate) - detect_used_resource_bus(bridge, dev->subordinate); - } -} - - /** * acpiphp_detect_pci_resource - detect resources under bridge * @bridge: detect all resources already used under this bridge @@ -306,7 +242,13 @@ */ int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) { - detect_used_resource_bus(bridge, bridge->pci_bus); + struct list_head *l; + struct pci_dev *dev; + + list_for_each (l, &bridge->pci_bus->devices) { + dev = pci_dev_b(l); + detect_used_resource(bridge, dev); + } return 0; }