diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 19:24:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 19:24:54 -0400 |
commit | 3bb07f1b73ea6313b843807063e183e168c9182a (patch) | |
tree | f0e2ab77b8bc993a843a0edede00668c589863cc /arch/x86 | |
parent | 6326c71fd2fb3bef5fa33951479298b683da35fe (diff) | |
parent | 5420e46d4d79bcd5d5952df98d022c8412385d32 (diff) |
Merge tag 'pci-for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI changes from Bjorn Helgaas:
- Host bridge cleanups from Yinghai
- Disable Bus Master bit on PCI device shutdown (kexec-related)
- Stratus ftServer fix
- pci_dev_reset() locking fix
- IvyBridge graphics erratum workaround
* tag 'pci-for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (21 commits)
microblaze/PCI: fix "io_offset undeclared" error
x86/PCI: only check for spinlock being held in SMP kernels
resources: add resource_overlaps()
PCI: fix uninitialized variable 'cap_mask'
MAINTAINERS: update PCI git tree and patchwork
PCI: disable Bus Master on PCI device shutdown
PCI: work around IvyBridge internal graphics FLR erratum
x86/PCI: fix unused variable warning in amd_bus.c
PCI: move mutex locking out of pci_dev_reset function
PCI: work around Stratus ftServer broken PCIe hierarchy
x86/PCI: merge pcibios_scan_root() and pci_scan_bus_on_node()
x86/PCI: dynamically allocate pci_root_info for native host bridge drivers
x86/PCI: embed pci_sysdata into pci_root_info on ACPI path
x86/PCI: embed name into pci_root_info struct
x86/PCI: add host bridge resource release for _CRS path
x86/PCI: refactor get_current_resources()
PCI: add host bridge release support
PCI: add generic device into pci_host_bridge struct
PCI: rename pci_host_bridge() to find_pci_root_bridge()
x86/PCI: fix memleak with get_current_resources()
...
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/pci/acpi.c | 128 | ||||
-rw-r--r-- | arch/x86/pci/amd_bus.c | 91 | ||||
-rw-r--r-- | arch/x86/pci/broadcom_bus.c | 12 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.c | 69 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.h | 18 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 43 | ||||
-rw-r--r-- | arch/x86/pci/i386.c | 2 |
7 files changed, 191 insertions, 172 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index ed2835e148b5..fc09c2754e08 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -9,11 +9,11 @@ | |||
9 | 9 | ||
10 | struct pci_root_info { | 10 | struct pci_root_info { |
11 | struct acpi_device *bridge; | 11 | struct acpi_device *bridge; |
12 | char *name; | 12 | char name[16]; |
13 | unsigned int res_num; | 13 | unsigned int res_num; |
14 | struct resource *res; | 14 | struct resource *res; |
15 | struct list_head *resources; | ||
16 | int busnum; | 15 | int busnum; |
16 | struct pci_sysdata sd; | ||
17 | }; | 17 | }; |
18 | 18 | ||
19 | static bool pci_use_crs = true; | 19 | static bool pci_use_crs = true; |
@@ -245,13 +245,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
245 | return AE_OK; | 245 | return AE_OK; |
246 | } | 246 | } |
247 | 247 | ||
248 | static bool resource_contains(struct resource *res, resource_size_t point) | ||
249 | { | ||
250 | if (res->start <= point && point <= res->end) | ||
251 | return true; | ||
252 | return false; | ||
253 | } | ||
254 | |||
255 | static void coalesce_windows(struct pci_root_info *info, unsigned long type) | 248 | static void coalesce_windows(struct pci_root_info *info, unsigned long type) |
256 | { | 249 | { |
257 | int i, j; | 250 | int i, j; |
@@ -272,10 +265,7 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) | |||
272 | * our resources no longer match the ACPI _CRS, but | 265 | * our resources no longer match the ACPI _CRS, but |
273 | * the kernel resource tree doesn't allow overlaps. | 266 | * the kernel resource tree doesn't allow overlaps. |
274 | */ | 267 | */ |
275 | if (resource_contains(res1, res2->start) || | 268 | if (resource_overlaps(res1, res2)) { |
276 | resource_contains(res1, res2->end) || | ||
277 | resource_contains(res2, res1->start) || | ||
278 | resource_contains(res2, res1->end)) { | ||
279 | res1->start = min(res1->start, res2->start); | 269 | res1->start = min(res1->start, res2->start); |
280 | res1->end = max(res1->end, res2->end); | 270 | res1->end = max(res1->end, res2->end); |
281 | dev_info(&info->bridge->dev, | 271 | dev_info(&info->bridge->dev, |
@@ -287,7 +277,8 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) | |||
287 | } | 277 | } |
288 | } | 278 | } |
289 | 279 | ||
290 | static void add_resources(struct pci_root_info *info) | 280 | static void add_resources(struct pci_root_info *info, |
281 | struct list_head *resources) | ||
291 | { | 282 | { |
292 | int i; | 283 | int i; |
293 | struct resource *res, *root, *conflict; | 284 | struct resource *res, *root, *conflict; |
@@ -311,53 +302,74 @@ static void add_resources(struct pci_root_info *info) | |||
311 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | 302 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
312 | res, conflict->name, conflict); | 303 | res, conflict->name, conflict); |
313 | else | 304 | else |
314 | pci_add_resource(info->resources, res); | 305 | pci_add_resource(resources, res); |
315 | } | 306 | } |
316 | } | 307 | } |
317 | 308 | ||
309 | static void free_pci_root_info_res(struct pci_root_info *info) | ||
310 | { | ||
311 | kfree(info->res); | ||
312 | info->res = NULL; | ||
313 | info->res_num = 0; | ||
314 | } | ||
315 | |||
316 | static void __release_pci_root_info(struct pci_root_info *info) | ||
317 | { | ||
318 | int i; | ||
319 | struct resource *res; | ||
320 | |||
321 | for (i = 0; i < info->res_num; i++) { | ||
322 | res = &info->res[i]; | ||
323 | |||
324 | if (!res->parent) | ||
325 | continue; | ||
326 | |||
327 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
328 | continue; | ||
329 | |||
330 | release_resource(res); | ||
331 | } | ||
332 | |||
333 | free_pci_root_info_res(info); | ||
334 | |||
335 | kfree(info); | ||
336 | } | ||
337 | static void release_pci_root_info(struct pci_host_bridge *bridge) | ||
338 | { | ||
339 | struct pci_root_info *info = bridge->release_data; | ||
340 | |||
341 | __release_pci_root_info(info); | ||
342 | } | ||
343 | |||
318 | static void | 344 | static void |
319 | get_current_resources(struct acpi_device *device, int busnum, | 345 | probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, |
320 | int domain, struct list_head *resources) | 346 | int busnum, int domain) |
321 | { | 347 | { |
322 | struct pci_root_info info; | ||
323 | size_t size; | 348 | size_t size; |
324 | 349 | ||
325 | info.bridge = device; | 350 | info->bridge = device; |
326 | info.res_num = 0; | 351 | info->res_num = 0; |
327 | info.resources = resources; | ||
328 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 352 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
329 | &info); | 353 | info); |
330 | if (!info.res_num) | 354 | if (!info->res_num) |
331 | return; | 355 | return; |
332 | 356 | ||
333 | size = sizeof(*info.res) * info.res_num; | 357 | size = sizeof(*info->res) * info->res_num; |
334 | info.res = kmalloc(size, GFP_KERNEL); | 358 | info->res_num = 0; |
335 | if (!info.res) | 359 | info->res = kmalloc(size, GFP_KERNEL); |
360 | if (!info->res) | ||
336 | return; | 361 | return; |
337 | 362 | ||
338 | info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); | 363 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); |
339 | if (!info.name) | ||
340 | goto name_alloc_fail; | ||
341 | 364 | ||
342 | info.res_num = 0; | ||
343 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | 365 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, |
344 | &info); | 366 | info); |
345 | |||
346 | if (pci_use_crs) { | ||
347 | add_resources(&info); | ||
348 | |||
349 | return; | ||
350 | } | ||
351 | |||
352 | kfree(info.name); | ||
353 | |||
354 | name_alloc_fail: | ||
355 | kfree(info.res); | ||
356 | } | 367 | } |
357 | 368 | ||
358 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | 369 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) |
359 | { | 370 | { |
360 | struct acpi_device *device = root->device; | 371 | struct acpi_device *device = root->device; |
372 | struct pci_root_info *info = NULL; | ||
361 | int domain = root->segment; | 373 | int domain = root->segment; |
362 | int busnum = root->secondary.start; | 374 | int busnum = root->secondary.start; |
363 | LIST_HEAD(resources); | 375 | LIST_HEAD(resources); |
@@ -389,17 +401,14 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
389 | if (node != -1 && !node_online(node)) | 401 | if (node != -1 && !node_online(node)) |
390 | node = -1; | 402 | node = -1; |
391 | 403 | ||
392 | /* Allocate per-root-bus (not per bus) arch-specific data. | 404 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
393 | * TODO: leak; this memory is never freed. | 405 | if (!info) { |
394 | * It's arguable whether it's worth the trouble to care. | ||
395 | */ | ||
396 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | ||
397 | if (!sd) { | ||
398 | printk(KERN_WARNING "pci_bus %04x:%02x: " | 406 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
399 | "ignored (out of memory)\n", domain, busnum); | 407 | "ignored (out of memory)\n", domain, busnum); |
400 | return NULL; | 408 | return NULL; |
401 | } | 409 | } |
402 | 410 | ||
411 | sd = &info->sd; | ||
403 | sd->domain = domain; | 412 | sd->domain = domain; |
404 | sd->node = node; | 413 | sd->node = node; |
405 | /* | 414 | /* |
@@ -413,22 +422,32 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
413 | * be replaced by sd. | 422 | * be replaced by sd. |
414 | */ | 423 | */ |
415 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 424 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
416 | kfree(sd); | 425 | kfree(info); |
417 | } else { | 426 | } else { |
418 | get_current_resources(device, busnum, domain, &resources); | 427 | probe_pci_root_info(info, device, busnum, domain); |
419 | 428 | ||
420 | /* | 429 | /* |
421 | * _CRS with no apertures is normal, so only fall back to | 430 | * _CRS with no apertures is normal, so only fall back to |
422 | * defaults or native bridge info if we're ignoring _CRS. | 431 | * defaults or native bridge info if we're ignoring _CRS. |
423 | */ | 432 | */ |
424 | if (!pci_use_crs) | 433 | if (pci_use_crs) |
434 | add_resources(info, &resources); | ||
435 | else { | ||
436 | free_pci_root_info_res(info); | ||
425 | x86_pci_root_bus_resources(busnum, &resources); | 437 | x86_pci_root_bus_resources(busnum, &resources); |
438 | } | ||
439 | |||
426 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, | 440 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, |
427 | &resources); | 441 | &resources); |
428 | if (bus) | 442 | if (bus) { |
429 | bus->subordinate = pci_scan_child_bus(bus); | 443 | bus->subordinate = pci_scan_child_bus(bus); |
430 | else | 444 | pci_set_host_bridge_release( |
445 | to_pci_host_bridge(bus->bridge), | ||
446 | release_pci_root_info, info); | ||
447 | } else { | ||
431 | pci_free_resource_list(&resources); | 448 | pci_free_resource_list(&resources); |
449 | __release_pci_root_info(info); | ||
450 | } | ||
432 | } | 451 | } |
433 | 452 | ||
434 | /* After the PCI-E bus has been walked and all devices discovered, | 453 | /* After the PCI-E bus has been walked and all devices discovered, |
@@ -445,9 +464,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
445 | } | 464 | } |
446 | } | 465 | } |
447 | 466 | ||
448 | if (!bus) | ||
449 | kfree(sd); | ||
450 | |||
451 | if (bus && node != -1) { | 467 | if (bus && node != -1) { |
452 | #ifdef CONFIG_ACPI_NUMA | 468 | #ifdef CONFIG_ACPI_NUMA |
453 | if (pxm >= 0) | 469 | if (pxm >= 0) |
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 0567df3890e1..5aed49bff058 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -32,6 +32,27 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = { | |||
32 | 32 | ||
33 | #define RANGE_NUM 16 | 33 | #define RANGE_NUM 16 |
34 | 34 | ||
35 | static struct pci_root_info __init *find_pci_root_info(int node, int link) | ||
36 | { | ||
37 | struct pci_root_info *info; | ||
38 | |||
39 | /* find the position */ | ||
40 | list_for_each_entry(info, &pci_root_infos, list) | ||
41 | if (info->node == node && info->link == link) | ||
42 | return info; | ||
43 | |||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static void __init set_mp_bus_range_to_node(int min_bus, int max_bus, int node) | ||
48 | { | ||
49 | #ifdef CONFIG_NUMA | ||
50 | int j; | ||
51 | |||
52 | for (j = min_bus; j <= max_bus; j++) | ||
53 | set_mp_bus_to_node(j, node); | ||
54 | #endif | ||
55 | } | ||
35 | /** | 56 | /** |
36 | * early_fill_mp_bus_to_node() | 57 | * early_fill_mp_bus_to_node() |
37 | * called before pcibios_scan_root and pci_scan_bus | 58 | * called before pcibios_scan_root and pci_scan_bus |
@@ -41,7 +62,6 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = { | |||
41 | static int __init early_fill_mp_bus_info(void) | 62 | static int __init early_fill_mp_bus_info(void) |
42 | { | 63 | { |
43 | int i; | 64 | int i; |
44 | int j; | ||
45 | unsigned bus; | 65 | unsigned bus; |
46 | unsigned slot; | 66 | unsigned slot; |
47 | int node; | 67 | int node; |
@@ -50,7 +70,6 @@ static int __init early_fill_mp_bus_info(void) | |||
50 | int def_link; | 70 | int def_link; |
51 | struct pci_root_info *info; | 71 | struct pci_root_info *info; |
52 | u32 reg; | 72 | u32 reg; |
53 | struct resource *res; | ||
54 | u64 start; | 73 | u64 start; |
55 | u64 end; | 74 | u64 end; |
56 | struct range range[RANGE_NUM]; | 75 | struct range range[RANGE_NUM]; |
@@ -86,7 +105,6 @@ static int __init early_fill_mp_bus_info(void) | |||
86 | if (!found) | 105 | if (!found) |
87 | return 0; | 106 | return 0; |
88 | 107 | ||
89 | pci_root_num = 0; | ||
90 | for (i = 0; i < 4; i++) { | 108 | for (i = 0; i < 4; i++) { |
91 | int min_bus; | 109 | int min_bus; |
92 | int max_bus; | 110 | int max_bus; |
@@ -99,19 +117,11 @@ static int __init early_fill_mp_bus_info(void) | |||
99 | min_bus = (reg >> 16) & 0xff; | 117 | min_bus = (reg >> 16) & 0xff; |
100 | max_bus = (reg >> 24) & 0xff; | 118 | max_bus = (reg >> 24) & 0xff; |
101 | node = (reg >> 4) & 0x07; | 119 | node = (reg >> 4) & 0x07; |
102 | #ifdef CONFIG_NUMA | 120 | set_mp_bus_range_to_node(min_bus, max_bus, node); |
103 | for (j = min_bus; j <= max_bus; j++) | ||
104 | set_mp_bus_to_node(j, node); | ||
105 | #endif | ||
106 | link = (reg >> 8) & 0x03; | 121 | link = (reg >> 8) & 0x03; |
107 | 122 | ||
108 | info = &pci_root_info[pci_root_num]; | 123 | info = alloc_pci_root_info(min_bus, max_bus, node, link); |
109 | info->bus_min = min_bus; | ||
110 | info->bus_max = max_bus; | ||
111 | info->node = node; | ||
112 | info->link = link; | ||
113 | sprintf(info->name, "PCI Bus #%02x", min_bus); | 124 | sprintf(info->name, "PCI Bus #%02x", min_bus); |
114 | pci_root_num++; | ||
115 | } | 125 | } |
116 | 126 | ||
117 | /* get the default node and link for left over res */ | 127 | /* get the default node and link for left over res */ |
@@ -134,16 +144,10 @@ static int __init early_fill_mp_bus_info(void) | |||
134 | link = (reg >> 4) & 0x03; | 144 | link = (reg >> 4) & 0x03; |
135 | end = (reg & 0xfff000) | 0xfff; | 145 | end = (reg & 0xfff000) | 0xfff; |
136 | 146 | ||
137 | /* find the position */ | 147 | info = find_pci_root_info(node, link); |
138 | for (j = 0; j < pci_root_num; j++) { | 148 | if (!info) |
139 | info = &pci_root_info[j]; | ||
140 | if (info->node == node && info->link == link) | ||
141 | break; | ||
142 | } | ||
143 | if (j == pci_root_num) | ||
144 | continue; /* not found */ | 149 | continue; /* not found */ |
145 | 150 | ||
146 | info = &pci_root_info[j]; | ||
147 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | 151 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", |
148 | node, link, start, end); | 152 | node, link, start, end); |
149 | 153 | ||
@@ -155,13 +159,8 @@ static int __init early_fill_mp_bus_info(void) | |||
155 | } | 159 | } |
156 | /* add left over io port range to def node/link, [0, 0xffff] */ | 160 | /* add left over io port range to def node/link, [0, 0xffff] */ |
157 | /* find the position */ | 161 | /* find the position */ |
158 | for (j = 0; j < pci_root_num; j++) { | 162 | info = find_pci_root_info(def_node, def_link); |
159 | info = &pci_root_info[j]; | 163 | if (info) { |
160 | if (info->node == def_node && info->link == def_link) | ||
161 | break; | ||
162 | } | ||
163 | if (j < pci_root_num) { | ||
164 | info = &pci_root_info[j]; | ||
165 | for (i = 0; i < RANGE_NUM; i++) { | 164 | for (i = 0; i < RANGE_NUM; i++) { |
166 | if (!range[i].end) | 165 | if (!range[i].end) |
167 | continue; | 166 | continue; |
@@ -214,16 +213,10 @@ static int __init early_fill_mp_bus_info(void) | |||
214 | end <<= 8; | 213 | end <<= 8; |
215 | end |= 0xffff; | 214 | end |= 0xffff; |
216 | 215 | ||
217 | /* find the position */ | 216 | info = find_pci_root_info(node, link); |
218 | for (j = 0; j < pci_root_num; j++) { | ||
219 | info = &pci_root_info[j]; | ||
220 | if (info->node == node && info->link == link) | ||
221 | break; | ||
222 | } | ||
223 | if (j == pci_root_num) | ||
224 | continue; /* not found */ | ||
225 | 217 | ||
226 | info = &pci_root_info[j]; | 218 | if (!info) |
219 | continue; | ||
227 | 220 | ||
228 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 221 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
229 | node, link, start, end); | 222 | node, link, start, end); |
@@ -291,14 +284,8 @@ static int __init early_fill_mp_bus_info(void) | |||
291 | * add left over mmio range to def node/link ? | 284 | * add left over mmio range to def node/link ? |
292 | * that is tricky, just record range in from start_min to 4G | 285 | * that is tricky, just record range in from start_min to 4G |
293 | */ | 286 | */ |
294 | for (j = 0; j < pci_root_num; j++) { | 287 | info = find_pci_root_info(def_node, def_link); |
295 | info = &pci_root_info[j]; | 288 | if (info) { |
296 | if (info->node == def_node && info->link == def_link) | ||
297 | break; | ||
298 | } | ||
299 | if (j < pci_root_num) { | ||
300 | info = &pci_root_info[j]; | ||
301 | |||
302 | for (i = 0; i < RANGE_NUM; i++) { | 289 | for (i = 0; i < RANGE_NUM; i++) { |
303 | if (!range[i].end) | 290 | if (!range[i].end) |
304 | continue; | 291 | continue; |
@@ -309,20 +296,16 @@ static int __init early_fill_mp_bus_info(void) | |||
309 | } | 296 | } |
310 | } | 297 | } |
311 | 298 | ||
312 | for (i = 0; i < pci_root_num; i++) { | 299 | list_for_each_entry(info, &pci_root_infos, list) { |
313 | int res_num; | ||
314 | int busnum; | 300 | int busnum; |
301 | struct pci_root_res *root_res; | ||
315 | 302 | ||
316 | info = &pci_root_info[i]; | ||
317 | res_num = info->res_num; | ||
318 | busnum = info->bus_min; | 303 | busnum = info->bus_min; |
319 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", | 304 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
320 | info->bus_min, info->bus_max, info->node, info->link); | 305 | info->bus_min, info->bus_max, info->node, info->link); |
321 | for (j = 0; j < res_num; j++) { | 306 | list_for_each_entry(root_res, &info->resources, list) |
322 | res = &info->res[j]; | 307 | printk(KERN_DEBUG "bus: %02x %pR\n", |
323 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", | 308 | busnum, &root_res->res); |
324 | busnum, j, res); | ||
325 | } | ||
326 | } | 309 | } |
327 | 310 | ||
328 | return 0; | 311 | return 0; |
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index f3a7c569a403..614392ced7d6 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c | |||
@@ -22,19 +22,15 @@ | |||
22 | static void __init cnb20le_res(u8 bus, u8 slot, u8 func) | 22 | static void __init cnb20le_res(u8 bus, u8 slot, u8 func) |
23 | { | 23 | { |
24 | struct pci_root_info *info; | 24 | struct pci_root_info *info; |
25 | struct pci_root_res *root_res; | ||
25 | struct resource res; | 26 | struct resource res; |
26 | u16 word1, word2; | 27 | u16 word1, word2; |
27 | u8 fbus, lbus; | 28 | u8 fbus, lbus; |
28 | int i; | ||
29 | |||
30 | info = &pci_root_info[pci_root_num]; | ||
31 | pci_root_num++; | ||
32 | 29 | ||
33 | /* read the PCI bus numbers */ | 30 | /* read the PCI bus numbers */ |
34 | fbus = read_pci_config_byte(bus, slot, func, 0x44); | 31 | fbus = read_pci_config_byte(bus, slot, func, 0x44); |
35 | lbus = read_pci_config_byte(bus, slot, func, 0x45); | 32 | lbus = read_pci_config_byte(bus, slot, func, 0x45); |
36 | info->bus_min = fbus; | 33 | info = alloc_pci_root_info(fbus, lbus, 0, 0); |
37 | info->bus_max = lbus; | ||
38 | 34 | ||
39 | /* | 35 | /* |
40 | * Add the legacy IDE ports on bus 0 | 36 | * Add the legacy IDE ports on bus 0 |
@@ -86,8 +82,8 @@ static void __init cnb20le_res(u8 bus, u8 slot, u8 func) | |||
86 | res.flags = IORESOURCE_BUS; | 82 | res.flags = IORESOURCE_BUS; |
87 | printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res); | 83 | printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res); |
88 | 84 | ||
89 | for (i = 0; i < info->res_num; i++) | 85 | list_for_each_entry(root_res, &info->resources, list) |
90 | printk(KERN_INFO "host bridge window %pR\n", &info->res[i]); | 86 | printk(KERN_INFO "host bridge window %pR\n", &root_res->res); |
91 | } | 87 | } |
92 | 88 | ||
93 | static int __init broadcom_postcore_init(void) | 89 | static int __init broadcom_postcore_init(void) |
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index fd3f65510e9d..306579f7d0fd 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c | |||
@@ -4,35 +4,38 @@ | |||
4 | 4 | ||
5 | #include "bus_numa.h" | 5 | #include "bus_numa.h" |
6 | 6 | ||
7 | int pci_root_num; | 7 | LIST_HEAD(pci_root_infos); |
8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
9 | 8 | ||
10 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) | 9 | static struct pci_root_info *x86_find_pci_root_info(int bus) |
11 | { | 10 | { |
12 | int i; | ||
13 | int j; | ||
14 | struct pci_root_info *info; | 11 | struct pci_root_info *info; |
15 | 12 | ||
16 | if (!pci_root_num) | 13 | if (list_empty(&pci_root_infos)) |
17 | goto default_resources; | 14 | return NULL; |
18 | 15 | ||
19 | for (i = 0; i < pci_root_num; i++) { | 16 | list_for_each_entry(info, &pci_root_infos, list) |
20 | if (pci_root_info[i].bus_min == bus) | 17 | if (info->bus_min == bus) |
21 | break; | 18 | return info; |
22 | } | 19 | |
20 | return NULL; | ||
21 | } | ||
23 | 22 | ||
24 | if (i == pci_root_num) | 23 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) |
24 | { | ||
25 | struct pci_root_info *info = x86_find_pci_root_info(bus); | ||
26 | struct pci_root_res *root_res; | ||
27 | |||
28 | if (!info) | ||
25 | goto default_resources; | 29 | goto default_resources; |
26 | 30 | ||
27 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", | 31 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", |
28 | bus); | 32 | bus); |
29 | 33 | ||
30 | info = &pci_root_info[i]; | 34 | list_for_each_entry(root_res, &info->resources, list) { |
31 | for (j = 0; j < info->res_num; j++) { | ||
32 | struct resource *res; | 35 | struct resource *res; |
33 | struct resource *root; | 36 | struct resource *root; |
34 | 37 | ||
35 | res = &info->res[j]; | 38 | res = &root_res->res; |
36 | pci_add_resource(resources, res); | 39 | pci_add_resource(resources, res); |
37 | if (res->flags & IORESOURCE_IO) | 40 | if (res->flags & IORESOURCE_IO) |
38 | root = &ioport_resource; | 41 | root = &ioport_resource; |
@@ -53,11 +56,32 @@ default_resources: | |||
53 | pci_add_resource(resources, &iomem_resource); | 56 | pci_add_resource(resources, &iomem_resource); |
54 | } | 57 | } |
55 | 58 | ||
59 | struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max, | ||
60 | int node, int link) | ||
61 | { | ||
62 | struct pci_root_info *info; | ||
63 | |||
64 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
65 | |||
66 | if (!info) | ||
67 | return info; | ||
68 | |||
69 | INIT_LIST_HEAD(&info->resources); | ||
70 | info->bus_min = bus_min; | ||
71 | info->bus_max = bus_max; | ||
72 | info->node = node; | ||
73 | info->link = link; | ||
74 | |||
75 | list_add_tail(&info->list, &pci_root_infos); | ||
76 | |||
77 | return info; | ||
78 | } | ||
79 | |||
56 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, | 80 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, |
57 | resource_size_t end, unsigned long flags, int merge) | 81 | resource_size_t end, unsigned long flags, int merge) |
58 | { | 82 | { |
59 | int i; | ||
60 | struct resource *res; | 83 | struct resource *res; |
84 | struct pci_root_res *root_res; | ||
61 | 85 | ||
62 | if (start > end) | 86 | if (start > end) |
63 | return; | 87 | return; |
@@ -69,11 +93,11 @@ void __devinit update_res(struct pci_root_info *info, resource_size_t start, | |||
69 | goto addit; | 93 | goto addit; |
70 | 94 | ||
71 | /* try to merge it with old one */ | 95 | /* try to merge it with old one */ |
72 | for (i = 0; i < info->res_num; i++) { | 96 | list_for_each_entry(root_res, &info->resources, list) { |
73 | resource_size_t final_start, final_end; | 97 | resource_size_t final_start, final_end; |
74 | resource_size_t common_start, common_end; | 98 | resource_size_t common_start, common_end; |
75 | 99 | ||
76 | res = &info->res[i]; | 100 | res = &root_res->res; |
77 | if (res->flags != flags) | 101 | if (res->flags != flags) |
78 | continue; | 102 | continue; |
79 | 103 | ||
@@ -93,14 +117,15 @@ void __devinit update_res(struct pci_root_info *info, resource_size_t start, | |||
93 | addit: | 117 | addit: |
94 | 118 | ||
95 | /* need to add that */ | 119 | /* need to add that */ |
96 | if (info->res_num >= RES_NUM) | 120 | root_res = kzalloc(sizeof(*root_res), GFP_KERNEL); |
121 | if (!root_res) | ||
97 | return; | 122 | return; |
98 | 123 | ||
99 | res = &info->res[info->res_num]; | 124 | res = &root_res->res; |
100 | res->name = info->name; | 125 | res->name = info->name; |
101 | res->flags = flags; | 126 | res->flags = flags; |
102 | res->start = start; | 127 | res->start = start; |
103 | res->end = end; | 128 | res->end = end; |
104 | res->child = NULL; | 129 | |
105 | info->res_num++; | 130 | list_add_tail(&root_res->list, &info->resources); |
106 | } | 131 | } |
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h index 804a4b40c31a..226a466b2b2b 100644 --- a/arch/x86/pci/bus_numa.h +++ b/arch/x86/pci/bus_numa.h | |||
@@ -4,22 +4,24 @@ | |||
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. | 5 | * root, so need to make sure we have enough slot there. |
6 | */ | 6 | */ |
7 | #define RES_NUM 16 | 7 | struct pci_root_res { |
8 | struct list_head list; | ||
9 | struct resource res; | ||
10 | }; | ||
11 | |||
8 | struct pci_root_info { | 12 | struct pci_root_info { |
13 | struct list_head list; | ||
9 | char name[12]; | 14 | char name[12]; |
10 | unsigned int res_num; | 15 | struct list_head resources; |
11 | struct resource res[RES_NUM]; | ||
12 | int bus_min; | 16 | int bus_min; |
13 | int bus_max; | 17 | int bus_max; |
14 | int node; | 18 | int node; |
15 | int link; | 19 | int link; |
16 | }; | 20 | }; |
17 | 21 | ||
18 | /* 4 at this time, it may become to 32 */ | 22 | extern struct list_head pci_root_infos; |
19 | #define PCI_ROOT_NR 4 | 23 | struct pci_root_info *alloc_pci_root_info(int bus_min, int bus_max, |
20 | extern int pci_root_num; | 24 | int node, int link); |
21 | extern struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
22 | |||
23 | extern void update_res(struct pci_root_info *info, resource_size_t start, | 25 | extern void update_res(struct pci_root_info *info, resource_size_t start, |
24 | resource_size_t end, unsigned long flags, int merge); | 26 | resource_size_t end, unsigned long flags, int merge); |
25 | #endif | 27 | #endif |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 323481e06ef8..0ad990a20d4a 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/dmi.h> | 11 | #include <linux/dmi.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | 13 | ||
14 | #include <asm-generic/pci-bridge.h> | ||
14 | #include <asm/acpi.h> | 15 | #include <asm/acpi.h> |
15 | #include <asm/segment.h> | 16 | #include <asm/segment.h> |
16 | #include <asm/io.h> | 17 | #include <asm/io.h> |
@@ -229,6 +230,14 @@ static int __devinit assign_all_busses(const struct dmi_system_id *d) | |||
229 | } | 230 | } |
230 | #endif | 231 | #endif |
231 | 232 | ||
233 | static int __devinit set_scan_all(const struct dmi_system_id *d) | ||
234 | { | ||
235 | printk(KERN_INFO "PCI: %s detected, enabling pci=pcie_scan_all\n", | ||
236 | d->ident); | ||
237 | pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
232 | static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { | 241 | static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { |
233 | #ifdef __i386__ | 242 | #ifdef __i386__ |
234 | /* | 243 | /* |
@@ -420,6 +429,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { | |||
420 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), | 429 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), |
421 | }, | 430 | }, |
422 | }, | 431 | }, |
432 | { | ||
433 | .callback = set_scan_all, | ||
434 | .ident = "Stratus/NEC ftServer", | ||
435 | .matches = { | ||
436 | DMI_MATCH(DMI_SYS_VENDOR, "ftServer"), | ||
437 | }, | ||
438 | }, | ||
423 | {} | 439 | {} |
424 | }; | 440 | }; |
425 | 441 | ||
@@ -430,9 +446,7 @@ void __init dmi_check_pciprobe(void) | |||
430 | 446 | ||
431 | struct pci_bus * __devinit pcibios_scan_root(int busnum) | 447 | struct pci_bus * __devinit pcibios_scan_root(int busnum) |
432 | { | 448 | { |
433 | LIST_HEAD(resources); | ||
434 | struct pci_bus *bus = NULL; | 449 | struct pci_bus *bus = NULL; |
435 | struct pci_sysdata *sd; | ||
436 | 450 | ||
437 | while ((bus = pci_find_next_bus(bus)) != NULL) { | 451 | while ((bus = pci_find_next_bus(bus)) != NULL) { |
438 | if (bus->number == busnum) { | 452 | if (bus->number == busnum) { |
@@ -441,28 +455,10 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) | |||
441 | } | 455 | } |
442 | } | 456 | } |
443 | 457 | ||
444 | /* Allocate per-root-bus (not per bus) arch-specific data. | 458 | return pci_scan_bus_on_node(busnum, &pci_root_ops, |
445 | * TODO: leak; this memory is never freed. | 459 | get_mp_bus_to_node(busnum)); |
446 | * It's arguable whether it's worth the trouble to care. | ||
447 | */ | ||
448 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | ||
449 | if (!sd) { | ||
450 | printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); | ||
451 | return NULL; | ||
452 | } | ||
453 | |||
454 | sd->node = get_mp_bus_to_node(busnum); | ||
455 | |||
456 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); | ||
457 | x86_pci_root_bus_resources(busnum, &resources); | ||
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); | ||
462 | } | ||
463 | |||
464 | return bus; | ||
465 | } | 460 | } |
461 | |||
466 | void __init pcibios_set_cache_line_size(void) | 462 | void __init pcibios_set_cache_line_size(void) |
467 | { | 463 | { |
468 | struct cpuinfo_x86 *c = &boot_cpu_data; | 464 | struct cpuinfo_x86 *c = &boot_cpu_data; |
@@ -656,6 +652,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, | |||
656 | } | 652 | } |
657 | sd->node = node; | 653 | sd->node = node; |
658 | x86_pci_root_bus_resources(busno, &resources); | 654 | x86_pci_root_bus_resources(busno, &resources); |
655 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno); | ||
659 | bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); | 656 | bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); |
660 | if (!bus) { | 657 | if (!bus) { |
661 | pci_free_resource_list(&resources); | 658 | pci_free_resource_list(&resources); |
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 831971e731f7..dd8ca6f7223b 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c | |||
@@ -57,7 +57,7 @@ static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev) | |||
57 | { | 57 | { |
58 | struct pcibios_fwaddrmap *map; | 58 | struct pcibios_fwaddrmap *map; |
59 | 59 | ||
60 | WARN_ON(!spin_is_locked(&pcibios_fwaddrmap_lock)); | 60 | WARN_ON_SMP(!spin_is_locked(&pcibios_fwaddrmap_lock)); |
61 | 61 | ||
62 | list_for_each_entry(map, &pcibios_fwaddrmappings, list) | 62 | list_for_each_entry(map, &pcibios_fwaddrmappings, list) |
63 | if (map->dev == dev) | 63 | if (map->dev == dev) |