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, |
