diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2011-10-28 18:28:14 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-01-06 15:11:14 -0500 |
commit | 2cd6975a4ff92a75e46240109d01c1daf4682e5d (patch) | |
tree | ec5ca0a025c31e54c5f4c6701dc8c79ce012f820 /arch/x86/pci | |
parent | 46fbade05ca0784ca3c959bd7bf2aae7d81306c2 (diff) |
x86/PCI: convert to pci_create_root_bus() and pci_scan_root_bus()
x86 has two kinds of PCI root bus scanning:
(1) ACPI-based, using _CRS resources. This used pci_create_bus(), not
pci_scan_bus(), because ACPI hotplug needed to split the
pci_bus_add_devices() into a separate host bridge .start() method.
This patch parses the _CRS resources earlier, so we can build a list of
resources and pass it to pci_create_root_bus().
Note that as before, we parse the _CRS even if we aren't going to use
it so we can print it for debugging purposes.
(2) All other, which used either default resources (ioport_resource and
iomem_resource) or information read from the hardware via amd_bus.c or
similar. This used pci_scan_bus().
This patch converts x86_pci_root_bus_res_quirks() (previously called
from pcibios_fixup_bus()) to x86_pci_root_bus_resources(), which builds
a list of resources before we call pci_scan_root_bus().
We also use x86_pci_root_bus_resources() if we have ACPI but are
ignoring _CRS.
CC: Yinghai Lu <yinghai.lu@oracle.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/acpi.c | 28 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.c | 31 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 19 |
3 files changed, 44 insertions, 34 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 425500bb24e6..a312e76063a7 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -12,7 +12,7 @@ struct pci_root_info { | |||
12 | char *name; | 12 | char *name; |
13 | unsigned int res_num; | 13 | unsigned int res_num; |
14 | struct resource *res; | 14 | struct resource *res; |
15 | struct pci_bus *bus; | 15 | struct list_head *resources; |
16 | int busnum; | 16 | int busnum; |
17 | }; | 17 | }; |
18 | 18 | ||
@@ -304,23 +304,20 @@ static void add_resources(struct pci_root_info *info) | |||
304 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | 304 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
305 | res, conflict->name, conflict); | 305 | res, conflict->name, conflict); |
306 | else | 306 | else |
307 | pci_bus_add_resource(info->bus, res, 0); | 307 | pci_add_resource(info->resources, res); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | static void | 311 | static void |
312 | get_current_resources(struct acpi_device *device, int busnum, | 312 | get_current_resources(struct acpi_device *device, int busnum, |
313 | int domain, struct pci_bus *bus) | 313 | int domain, struct list_head *resources) |
314 | { | 314 | { |
315 | struct pci_root_info info; | 315 | struct pci_root_info info; |
316 | size_t size; | 316 | size_t size; |
317 | 317 | ||
318 | if (pci_use_crs) | ||
319 | pci_bus_remove_resources(bus); | ||
320 | |||
321 | info.bridge = device; | 318 | info.bridge = device; |
322 | info.bus = bus; | ||
323 | info.res_num = 0; | 319 | info.res_num = 0; |
320 | info.resources = resources; | ||
324 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 321 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
325 | &info); | 322 | &info); |
326 | if (!info.res_num) | 323 | if (!info.res_num) |
@@ -329,7 +326,7 @@ get_current_resources(struct acpi_device *device, int busnum, | |||
329 | size = sizeof(*info.res) * info.res_num; | 326 | size = sizeof(*info.res) * info.res_num; |
330 | info.res = kmalloc(size, GFP_KERNEL); | 327 | info.res = kmalloc(size, GFP_KERNEL); |
331 | if (!info.res) | 328 | if (!info.res) |
332 | goto res_alloc_fail; | 329 | return; |
333 | 330 | ||
334 | info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); | 331 | info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); |
335 | if (!info.name) | 332 | if (!info.name) |
@@ -344,8 +341,6 @@ get_current_resources(struct acpi_device *device, int busnum, | |||
344 | 341 | ||
345 | name_alloc_fail: | 342 | name_alloc_fail: |
346 | kfree(info.res); | 343 | kfree(info.res); |
347 | res_alloc_fail: | ||
348 | return; | ||
349 | } | 344 | } |
350 | 345 | ||
351 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | 346 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) |
@@ -353,6 +348,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
353 | struct acpi_device *device = root->device; | 348 | struct acpi_device *device = root->device; |
354 | int domain = root->segment; | 349 | int domain = root->segment; |
355 | int busnum = root->secondary.start; | 350 | int busnum = root->secondary.start; |
351 | LIST_HEAD(resources); | ||
356 | struct pci_bus *bus; | 352 | struct pci_bus *bus; |
357 | struct pci_sysdata *sd; | 353 | struct pci_sysdata *sd; |
358 | int node; | 354 | int node; |
@@ -407,11 +403,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
407 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 403 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
408 | kfree(sd); | 404 | kfree(sd); |
409 | } else { | 405 | } else { |
410 | bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); | 406 | get_current_resources(device, busnum, domain, &resources); |
411 | if (bus) { | 407 | if (list_empty(&resources)) |
412 | get_current_resources(device, busnum, domain, bus); | 408 | x86_pci_root_bus_resources(busnum, &resources); |
409 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, | ||
410 | &resources); | ||
411 | if (bus) | ||
413 | bus->subordinate = pci_scan_child_bus(bus); | 412 | bus->subordinate = pci_scan_child_bus(bus); |
414 | } | 413 | else |
414 | pci_free_resource_list(&resources); | ||
415 | } | 415 | } |
416 | 416 | ||
417 | /* After the PCI-E bus has been walked and all devices discovered, | 417 | /* After the PCI-E bus has been walked and all devices discovered, |
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index 64a122883896..fd3f65510e9d 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c | |||
@@ -7,45 +7,50 @@ | |||
7 | int pci_root_num; | 7 | int pci_root_num; |
8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; | 8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; |
9 | 9 | ||
10 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | 10 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) |
11 | { | 11 | { |
12 | int i; | 12 | int i; |
13 | int j; | 13 | int j; |
14 | struct pci_root_info *info; | 14 | struct pci_root_info *info; |
15 | 15 | ||
16 | /* don't go for it if _CRS is used already */ | ||
17 | if (b->resource[0] != &ioport_resource || | ||
18 | b->resource[1] != &iomem_resource) | ||
19 | return; | ||
20 | |||
21 | if (!pci_root_num) | 16 | if (!pci_root_num) |
22 | return; | 17 | goto default_resources; |
23 | 18 | ||
24 | for (i = 0; i < pci_root_num; i++) { | 19 | for (i = 0; i < pci_root_num; i++) { |
25 | if (pci_root_info[i].bus_min == b->number) | 20 | if (pci_root_info[i].bus_min == bus) |
26 | break; | 21 | break; |
27 | } | 22 | } |
28 | 23 | ||
29 | if (i == pci_root_num) | 24 | if (i == pci_root_num) |
30 | return; | 25 | goto default_resources; |
31 | 26 | ||
32 | printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", | 27 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", |
33 | b->number); | 28 | bus); |
34 | 29 | ||
35 | pci_bus_remove_resources(b); | ||
36 | info = &pci_root_info[i]; | 30 | info = &pci_root_info[i]; |
37 | for (j = 0; j < info->res_num; j++) { | 31 | for (j = 0; j < info->res_num; j++) { |
38 | struct resource *res; | 32 | struct resource *res; |
39 | struct resource *root; | 33 | struct resource *root; |
40 | 34 | ||
41 | res = &info->res[j]; | 35 | res = &info->res[j]; |
42 | pci_bus_add_resource(b, res, 0); | 36 | pci_add_resource(resources, res); |
43 | if (res->flags & IORESOURCE_IO) | 37 | if (res->flags & IORESOURCE_IO) |
44 | root = &ioport_resource; | 38 | root = &ioport_resource; |
45 | else | 39 | else |
46 | root = &iomem_resource; | 40 | root = &iomem_resource; |
47 | insert_resource(root, res); | 41 | insert_resource(root, res); |
48 | } | 42 | } |
43 | return; | ||
44 | |||
45 | default_resources: | ||
46 | /* | ||
47 | * We don't have any host bridge aperture information from the | ||
48 | * "native host bridge drivers," e.g., amd_bus or broadcom_bus, | ||
49 | * so fall back to the defaults historically used by pci_create_bus(). | ||
50 | */ | ||
51 | printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus); | ||
52 | pci_add_resource(resources, &ioport_resource); | ||
53 | pci_add_resource(resources, &iomem_resource); | ||
49 | } | 54 | } |
50 | 55 | ||
51 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, | 56 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 07c55ce6fdf5..323481e06ef8 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -164,9 +164,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) | |||
164 | { | 164 | { |
165 | struct pci_dev *dev; | 165 | struct pci_dev *dev; |
166 | 166 | ||
167 | /* root bus? */ | ||
168 | if (!b->parent) | ||
169 | x86_pci_root_bus_res_quirks(b); | ||
170 | pci_read_bridge_bases(b); | 167 | pci_read_bridge_bases(b); |
171 | list_for_each_entry(dev, &b->devices, bus_list) | 168 | list_for_each_entry(dev, &b->devices, bus_list) |
172 | pcibios_fixup_device_resources(dev); | 169 | pcibios_fixup_device_resources(dev); |
@@ -433,6 +430,7 @@ void __init dmi_check_pciprobe(void) | |||
433 | 430 | ||
434 | struct pci_bus * __devinit pcibios_scan_root(int busnum) | 431 | struct pci_bus * __devinit pcibios_scan_root(int busnum) |
435 | { | 432 | { |
433 | LIST_HEAD(resources); | ||
436 | struct pci_bus *bus = NULL; | 434 | struct pci_bus *bus = NULL; |
437 | struct pci_sysdata *sd; | 435 | struct pci_sysdata *sd; |
438 | 436 | ||
@@ -456,9 +454,12 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) | |||
456 | sd->node = get_mp_bus_to_node(busnum); | 454 | sd->node = get_mp_bus_to_node(busnum); |
457 | 455 | ||
458 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); | 456 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); |
459 | bus = pci_scan_bus(busnum, &pci_root_ops, sd); | 457 | x86_pci_root_bus_resources(busnum, &resources); |
460 | if (!bus) | 458 | bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources); |
459 | if (!bus) { | ||
460 | pci_free_resource_list(&resources); | ||
461 | kfree(sd); | 461 | kfree(sd); |
462 | } | ||
462 | 463 | ||
463 | return bus; | 464 | return bus; |
464 | } | 465 | } |
@@ -639,6 +640,7 @@ int pci_ext_cfg_avail(struct pci_dev *dev) | |||
639 | 640 | ||
640 | struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) | 641 | struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) |
641 | { | 642 | { |
643 | LIST_HEAD(resources); | ||
642 | struct pci_bus *bus = NULL; | 644 | struct pci_bus *bus = NULL; |
643 | struct pci_sysdata *sd; | 645 | struct pci_sysdata *sd; |
644 | 646 | ||
@@ -653,9 +655,12 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, | |||
653 | return NULL; | 655 | return NULL; |
654 | } | 656 | } |
655 | sd->node = node; | 657 | sd->node = node; |
656 | bus = pci_scan_bus(busno, ops, sd); | 658 | x86_pci_root_bus_resources(busno, &resources); |
657 | if (!bus) | 659 | bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); |
660 | if (!bus) { | ||
661 | pci_free_resource_list(&resources); | ||
658 | kfree(sd); | 662 | kfree(sd); |
663 | } | ||
659 | 664 | ||
660 | return bus; | 665 | return bus; |
661 | } | 666 | } |