aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/ia64/pci/pci.c12
-rw-r--r--arch/x86/pci/acpi.c33
-rw-r--r--arch/x86/pci/bus_numa.c3
-rw-r--r--arch/x86/pci/bus_numa.h3
-rw-r--r--drivers/pci/bus.c46
-rw-r--r--drivers/pci/probe.c17
-rw-r--r--include/linux/pci.h35
7 files changed, 98 insertions, 51 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 89f957ca3eb2..64aff520b899 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -320,9 +320,9 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
320static void __devinit 320static void __devinit
321pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl) 321pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
322{ 322{
323 int i, j; 323 int i;
324 324
325 j = 0; 325 pci_bus_remove_resources(bus);
326 for (i = 0; i < ctrl->windows; i++) { 326 for (i = 0; i < ctrl->windows; i++) {
327 struct resource *res = &ctrl->window[i].resource; 327 struct resource *res = &ctrl->window[i].resource;
328 /* HP's firmware has a hack to work around a Windows bug. 328 /* HP's firmware has a hack to work around a Windows bug.
@@ -330,13 +330,7 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
330 if ((res->flags & IORESOURCE_MEM) && 330 if ((res->flags & IORESOURCE_MEM) &&
331 (res->end - res->start < 16)) 331 (res->end - res->start < 16))
332 continue; 332 continue;
333 if (j >= PCI_BUS_NUM_RESOURCES) { 333 pci_bus_add_resource(bus, res, 0);
334 dev_warn(&bus->dev,
335 "ignoring host bridge window %pR (no space)\n",
336 res);
337 continue;
338 }
339 bus->resource[j++] = res;
340 } 334 }
341} 335}
342 336
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 959e548a7039..a2f8cdb8c1d5 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -45,20 +45,6 @@ count_resource(struct acpi_resource *acpi_res, void *data)
45 return AE_OK; 45 return AE_OK;
46} 46}
47 47
48static int
49bus_has_transparent_bridge(struct pci_bus *bus)
50{
51 struct pci_dev *dev;
52
53 list_for_each_entry(dev, &bus->devices, bus_list) {
54 u16 class = dev->class >> 8;
55
56 if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
57 return true;
58 }
59 return false;
60}
61
62static void 48static void
63align_resource(struct acpi_device *bridge, struct resource *res) 49align_resource(struct acpi_device *bridge, struct resource *res)
64{ 50{
@@ -92,12 +78,8 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
92 acpi_status status; 78 acpi_status status;
93 unsigned long flags; 79 unsigned long flags;
94 struct resource *root; 80 struct resource *root;
95 int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
96 u64 start, end; 81 u64 start, end;
97 82
98 if (bus_has_transparent_bridge(info->bus))
99 max_root_bus_resources -= 3;
100
101 status = resource_to_addr(acpi_res, &addr); 83 status = resource_to_addr(acpi_res, &addr);
102 if (!ACPI_SUCCESS(status)) 84 if (!ACPI_SUCCESS(status))
103 return AE_OK; 85 return AE_OK;
@@ -115,15 +97,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
115 97
116 start = addr.minimum + addr.translation_offset; 98 start = addr.minimum + addr.translation_offset;
117 end = start + addr.address_length - 1; 99 end = start + addr.address_length - 1;
118 if (info->res_num >= max_root_bus_resources) {
119 if (pci_probe & PCI_USE__CRS)
120 printk(KERN_WARNING "PCI: Failed to allocate "
121 "0x%lx-0x%lx from %s for %s due to _CRS "
122 "returning more than %d resource descriptors\n",
123 (unsigned long) start, (unsigned long) end,
124 root->name, info->name, max_root_bus_resources);
125 return AE_OK;
126 }
127 100
128 res = &info->res[info->res_num]; 101 res = &info->res[info->res_num];
129 res->name = info->name; 102 res->name = info->name;
@@ -143,7 +116,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
143 dev_err(&info->bridge->dev, 116 dev_err(&info->bridge->dev,
144 "can't allocate host bridge window %pR\n", res); 117 "can't allocate host bridge window %pR\n", res);
145 } else { 118 } else {
146 info->bus->resource[info->res_num] = res; 119 pci_bus_add_resource(info->bus, res, 0);
147 info->res_num++; 120 info->res_num++;
148 if (addr.translation_offset) 121 if (addr.translation_offset)
149 dev_info(&info->bridge->dev, "host bridge window %pR " 122 dev_info(&info->bridge->dev, "host bridge window %pR "
@@ -164,7 +137,9 @@ get_current_resources(struct acpi_device *device, int busnum,
164 struct pci_root_info info; 137 struct pci_root_info info;
165 size_t size; 138 size_t size;
166 139
167 if (!(pci_probe & PCI_USE__CRS)) 140 if (pci_probe & PCI_USE__CRS)
141 pci_bus_remove_resources(bus);
142 else
168 dev_info(&device->dev, 143 dev_info(&device->dev,
169 "ignoring host bridge windows from ACPI; " 144 "ignoring host bridge windows from ACPI; "
170 "boot with \"pci=use_crs\" to use them\n"); 145 "boot with \"pci=use_crs\" to use them\n");
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index f939d603adfa..12d54ff3654d 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -36,13 +36,14 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
36 printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", 36 printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
37 b->number); 37 b->number);
38 38
39 pci_bus_remove_resources(b);
39 info = &pci_root_info[i]; 40 info = &pci_root_info[i];
40 for (j = 0; j < info->res_num; j++) { 41 for (j = 0; j < info->res_num; j++) {
41 struct resource *res; 42 struct resource *res;
42 struct resource *root; 43 struct resource *root;
43 44
44 res = &info->res[j]; 45 res = &info->res[j];
45 b->resource[j] = res; 46 pci_bus_add_resource(b, res, 0);
46 if (res->flags & IORESOURCE_IO) 47 if (res->flags & IORESOURCE_IO)
47 root = &ioport_resource; 48 root = &ioport_resource;
48 else 49 else
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index adbc23fe82ac..731b64ee8d84 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -2,8 +2,7 @@
2 2
3/* 3/*
4 * sub bus (transparent) will use entres from 3 to store extra from 4 * sub bus (transparent) will use entres from 3 to store extra from
5 * root, so need to make sure we have enough slot there, Should we 5 * root, so need to make sure we have enough slot there.
6 * increase PCI_BUS_NUM_RESOURCES?
7 */ 6 */
8#define RES_NUM 16 7#define RES_NUM 16
9struct pci_root_info { 8struct pci_root_info {
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 }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2ff9d26a078f..e19a69613d8f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -364,9 +364,26 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
364 hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space); 364 hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
365} 365}
366 366
367#ifndef PCI_BUS_NUM_RESOURCES 367/*
368#define PCI_BUS_NUM_RESOURCES 16 368 * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
369#endif 369 * to P2P or CardBus bridge windows) go in a table. Additional ones (for
370 * buses below host bridges or subtractive decode bridges) go in the list.
371 * Use pci_bus_for_each_resource() to iterate through all the resources.
372 */
373
374/*
375 * PCI_SUBTRACTIVE_DECODE means the bridge forwards the window implicitly
376 * and there's no way to program the bridge with the details of the window.
377 * This does not apply to ACPI _CRS windows, even with the _DEC subtractive-
378 * decode bit set, because they are explicit and can be programmed with _SRS.
379 */
380#define PCI_SUBTRACTIVE_DECODE 0x1
381
382struct pci_bus_resource {
383 struct list_head list;
384 struct resource *res;
385 unsigned int flags;
386};
370 387
371#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ 388#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
372 389
@@ -377,8 +394,8 @@ struct pci_bus {
377 struct list_head devices; /* list of devices on this bus */ 394 struct list_head devices; /* list of devices on this bus */
378 struct pci_dev *self; /* bridge device as seen by parent */ 395 struct pci_dev *self; /* bridge device as seen by parent */
379 struct list_head slots; /* list of slots on this bus */ 396 struct list_head slots; /* list of slots on this bus */
380 struct resource *resource[PCI_BUS_NUM_RESOURCES]; 397 struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
381 /* address space routed to this bus */ 398 struct list_head resources; /* address space routed to this bus */
382 399
383 struct pci_ops *ops; /* configuration access functions */ 400 struct pci_ops *ops; /* configuration access functions */
384 void *sysdata; /* hook for sys-specific extension */ 401 void *sysdata; /* hook for sys-specific extension */
@@ -829,8 +846,14 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
829void pci_release_selected_regions(struct pci_dev *, int); 846void pci_release_selected_regions(struct pci_dev *, int);
830 847
831/* drivers/pci/bus.c */ 848/* drivers/pci/bus.c */
849void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
850struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
851void pci_bus_remove_resources(struct pci_bus *bus);
852
832#define pci_bus_for_each_resource(bus, res, i) \ 853#define pci_bus_for_each_resource(bus, res, i) \
833 for (i = 0; res = bus->resource[i], i < PCI_BUS_NUM_RESOURCES; i++) 854 for (i = 0; \
855 (res = pci_bus_resource_n(bus, i)) || i < PCI_BRIDGE_RESOURCE_NUM; \
856 i++)
834 857
835int __must_check pci_bus_alloc_resource(struct pci_bus *bus, 858int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
836 struct resource *res, resource_size_t size, 859 struct resource *res, resource_size_t size,