diff options
-rw-r--r-- | arch/ia64/pci/pci.c | 12 | ||||
-rw-r--r-- | arch/x86/pci/acpi.c | 33 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.c | 3 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.h | 3 | ||||
-rw-r--r-- | drivers/pci/bus.c | 46 | ||||
-rw-r--r-- | drivers/pci/probe.c | 17 | ||||
-rw-r--r-- | include/linux/pci.h | 35 |
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) | |||
320 | static void __devinit | 320 | static void __devinit |
321 | pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl) | 321 | pcibios_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 | ||
48 | static int | ||
49 | bus_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 | |||
62 | static void | 48 | static void |
63 | align_resource(struct acpi_device *bridge, struct resource *res) | 49 | align_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 |
9 | struct pci_root_info { | 8 | struct 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 | ||
20 | void 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 | |||
36 | struct 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 | } | ||
50 | EXPORT_SYMBOL_GPL(pci_bus_resource_n); | ||
51 | |||
52 | void 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) | |||
394 | void __devinit pci_read_bridge_bases(struct pci_bus *child) | 395 | void __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 | |||
382 | struct 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 *); | |||
829 | void pci_release_selected_regions(struct pci_dev *, int); | 846 | void pci_release_selected_regions(struct pci_dev *, int); |
830 | 847 | ||
831 | /* drivers/pci/bus.c */ | 848 | /* drivers/pci/bus.c */ |
849 | void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags); | ||
850 | struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n); | ||
851 | void 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 | ||
835 | int __must_check pci_bus_alloc_resource(struct pci_bus *bus, | 858 | int __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, |