Re: [PATCH] PCI and PCI Hotplug update for 2.6.6-rc1

Greg KH
2004-04-15T17:32:08Z

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;
}