aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2010-02-23 12:24:36 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-23 12:43:37 -0500
commit2fe2abf896c1e7a0ee65faaf3ef0ce654848abbd (patch)
treef066d5c94bbed5ca3556b4d2f0c4b3a9795b6eff /drivers/pci
parent89a74ecccd1f78e51faf6287e5c0e93a92ac096e (diff)
PCI: augment bus resource table with a list
Previously we used a table of size PCI_BUS_NUM_RESOURCES (16) for resources forwarded to a bus by its upstream bridge. We've increased this size several times when the table overflowed. But there's no good limit on the number of resources because host bridges and subtractive decode bridges can forward any number of ranges to their secondary buses. This patch reduces the table to only PCI_BRIDGE_RESOURCE_NUM (4) entries, which corresponds to the number of windows a PCI-to-PCI (3) or CardBus (4) bridge can positively decode. Any additional resources, e.g., PCI host bridge windows or subtractively-decoded regions, are kept in a list. I'd prefer a single list rather than this split table/list approach, but that requires simultaneous changes to every architecture. This approach only requires immediate changes where we set up (a) host bridges with more than four windows and (b) subtractive-decode P2P bridges, and we can incrementally change other architectures to use the list. Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/bus.c46
-rw-r--r--drivers/pci/probe.c17
2 files changed, 59 insertions, 4 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index e75d219fd107..712250f5874a 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -17,6 +17,52 @@
17 17
18#include "pci.h" 18#include "pci.h"
19 19
20void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
21 unsigned int flags)
22{
23 struct pci_bus_resource *bus_res;
24
25 bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
26 if (!bus_res) {
27 dev_err(&bus->dev, "can't add %pR resource\n", res);
28 return;
29 }
30
31 bus_res->res = res;
32 bus_res->flags = flags;
33 list_add_tail(&bus_res->list, &bus->resources);
34}
35
36struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n)
37{
38 struct pci_bus_resource *bus_res;
39
40 if (n < PCI_BRIDGE_RESOURCE_NUM)
41 return bus->resource[n];
42
43 n -= PCI_BRIDGE_RESOURCE_NUM;
44 list_for_each_entry(bus_res, &bus->resources, list) {
45 if (n-- == 0)
46 return bus_res->res;
47 }
48 return NULL;
49}
50EXPORT_SYMBOL_GPL(pci_bus_resource_n);
51
52void pci_bus_remove_resources(struct pci_bus *bus)
53{
54 struct pci_bus_resource *bus_res, *tmp;
55 int i;
56
57 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
58 bus->resource[i] = 0;
59
60 list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
61 list_del(&bus_res->list);
62 kfree(bus_res);
63 }
64}
65
20/** 66/**
21 * pci_bus_alloc_resource - allocate a resource from a parent bus 67 * pci_bus_alloc_resource - allocate a resource from a parent bus
22 * @bus: PCI bus 68 * @bus: PCI bus
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 70c4ed2e67cc..270d069819f7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -89,6 +89,7 @@ static void release_pcibus_dev(struct device *dev)
89 89
90 if (pci_bus->bridge) 90 if (pci_bus->bridge)
91 put_device(pci_bus->bridge); 91 put_device(pci_bus->bridge);
92 pci_bus_remove_resources(pci_bus);
92 kfree(pci_bus); 93 kfree(pci_bus);
93} 94}
94 95
@@ -394,6 +395,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
394void __devinit pci_read_bridge_bases(struct pci_bus *child) 395void __devinit pci_read_bridge_bases(struct pci_bus *child)
395{ 396{
396 struct pci_dev *dev = child->self; 397 struct pci_dev *dev = child->self;
398 struct resource *res;
397 int i; 399 int i;
398 400
399 if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ 401 if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
@@ -403,17 +405,23 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
403 child->secondary, child->subordinate, 405 child->secondary, child->subordinate,
404 dev->transparent ? " (subtractive decode)" : ""); 406 dev->transparent ? " (subtractive decode)" : "");
405 407
408 pci_bus_remove_resources(child);
409 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
410 child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
411
406 pci_read_bridge_io(child); 412 pci_read_bridge_io(child);
407 pci_read_bridge_mmio(child); 413 pci_read_bridge_mmio(child);
408 pci_read_bridge_mmio_pref(child); 414 pci_read_bridge_mmio_pref(child);
409 415
410 if (dev->transparent) { 416 if (dev->transparent) {
411 for (i = 3; i < PCI_BUS_NUM_RESOURCES; i++) { 417 pci_bus_for_each_resource(child->parent, res, i) {
412 child->resource[i] = child->parent->resource[i - 3]; 418 if (res) {
413 if (child->resource[i]) 419 pci_bus_add_resource(child, res,
420 PCI_SUBTRACTIVE_DECODE);
414 dev_printk(KERN_DEBUG, &dev->dev, 421 dev_printk(KERN_DEBUG, &dev->dev,
415 " bridge window %pR (subtractive decode)\n", 422 " bridge window %pR (subtractive decode)\n",
416 child->resource[i]); 423 res);
424 }
417 } 425 }
418 } 426 }
419} 427}
@@ -428,6 +436,7 @@ static struct pci_bus * pci_alloc_bus(void)
428 INIT_LIST_HEAD(&b->children); 436 INIT_LIST_HEAD(&b->children);
429 INIT_LIST_HEAD(&b->devices); 437 INIT_LIST_HEAD(&b->devices);
430 INIT_LIST_HEAD(&b->slots); 438 INIT_LIST_HEAD(&b->slots);
439 INIT_LIST_HEAD(&b->resources);
431 b->max_bus_speed = PCI_SPEED_UNKNOWN; 440 b->max_bus_speed = PCI_SPEED_UNKNOWN;
432 b->cur_bus_speed = PCI_SPEED_UNKNOWN; 441 b->cur_bus_speed = PCI_SPEED_UNKNOWN;
433 } 442 }