aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,