diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-04-30 18:55:58 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-04-30 18:55:58 -0400 |
commit | 29473ec23aa79d401ffe06ec3f3ad3755382be13 (patch) | |
tree | 67b136cee8c5f407db94a73cb950ca421fba5759 | |
parent | 977f857ca566a1e68045fcbb7cfc9c4acb077cf0 (diff) | |
parent | c57ca65a6ea3171370cbb3010e5a3aea7399a5e1 (diff) |
Merge branch 'topic/yinghai-hostbridge-cleanup' into next
-rw-r--r-- | arch/x86/pci/acpi.c | 116 | ||||
-rw-r--r-- | arch/x86/pci/amd_bus.c | 76 | ||||
-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 | 27 | ||||
-rw-r--r-- | drivers/pci/Makefile | 2 | ||||
-rw-r--r-- | drivers/pci/host-bridge.c | 96 | ||||
-rw-r--r-- | drivers/pci/probe.c | 146 | ||||
-rw-r--r-- | include/linux/pci.h | 9 |
10 files changed, 304 insertions, 267 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index ed2835e148b5..8a17b23f8c84 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; |
@@ -287,7 +287,8 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) | |||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | static void add_resources(struct pci_root_info *info) | 290 | static void add_resources(struct pci_root_info *info, |
291 | struct list_head *resources) | ||
291 | { | 292 | { |
292 | int i; | 293 | int i; |
293 | struct resource *res, *root, *conflict; | 294 | struct resource *res, *root, *conflict; |
@@ -311,53 +312,74 @@ static void add_resources(struct pci_root_info *info) | |||
311 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | 312 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
312 | res, conflict->name, conflict); | 313 | res, conflict->name, conflict); |
313 | else | 314 | else |
314 | pci_add_resource(info->resources, res); | 315 | pci_add_resource(resources, res); |
315 | } | 316 | } |
316 | } | 317 | } |
317 | 318 | ||
319 | static void free_pci_root_info_res(struct pci_root_info *info) | ||
320 | { | ||
321 | kfree(info->res); | ||
322 | info->res = NULL; | ||
323 | info->res_num = 0; | ||
324 | } | ||
325 | |||
326 | static void __release_pci_root_info(struct pci_root_info *info) | ||
327 | { | ||
328 | int i; | ||
329 | struct resource *res; | ||
330 | |||
331 | for (i = 0; i < info->res_num; i++) { | ||
332 | res = &info->res[i]; | ||
333 | |||
334 | if (!res->parent) | ||
335 | continue; | ||
336 | |||
337 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
338 | continue; | ||
339 | |||
340 | release_resource(res); | ||
341 | } | ||
342 | |||
343 | free_pci_root_info_res(info); | ||
344 | |||
345 | kfree(info); | ||
346 | } | ||
347 | static void release_pci_root_info(struct pci_host_bridge *bridge) | ||
348 | { | ||
349 | struct pci_root_info *info = bridge->release_data; | ||
350 | |||
351 | __release_pci_root_info(info); | ||
352 | } | ||
353 | |||
318 | static void | 354 | static void |
319 | get_current_resources(struct acpi_device *device, int busnum, | 355 | probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, |
320 | int domain, struct list_head *resources) | 356 | int busnum, int domain) |
321 | { | 357 | { |
322 | struct pci_root_info info; | ||
323 | size_t size; | 358 | size_t size; |
324 | 359 | ||
325 | info.bridge = device; | 360 | info->bridge = device; |
326 | info.res_num = 0; | 361 | info->res_num = 0; |
327 | info.resources = resources; | ||
328 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 362 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
329 | &info); | 363 | info); |
330 | if (!info.res_num) | 364 | if (!info->res_num) |
331 | return; | 365 | return; |
332 | 366 | ||
333 | size = sizeof(*info.res) * info.res_num; | 367 | size = sizeof(*info->res) * info->res_num; |
334 | info.res = kmalloc(size, GFP_KERNEL); | 368 | info->res_num = 0; |
335 | if (!info.res) | 369 | info->res = kmalloc(size, GFP_KERNEL); |
370 | if (!info->res) | ||
336 | return; | 371 | return; |
337 | 372 | ||
338 | info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); | 373 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); |
339 | if (!info.name) | ||
340 | goto name_alloc_fail; | ||
341 | 374 | ||
342 | info.res_num = 0; | ||
343 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | 375 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, |
344 | &info); | 376 | 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 | } | 377 | } |
357 | 378 | ||
358 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | 379 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) |
359 | { | 380 | { |
360 | struct acpi_device *device = root->device; | 381 | struct acpi_device *device = root->device; |
382 | struct pci_root_info *info = NULL; | ||
361 | int domain = root->segment; | 383 | int domain = root->segment; |
362 | int busnum = root->secondary.start; | 384 | int busnum = root->secondary.start; |
363 | LIST_HEAD(resources); | 385 | LIST_HEAD(resources); |
@@ -389,17 +411,14 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
389 | if (node != -1 && !node_online(node)) | 411 | if (node != -1 && !node_online(node)) |
390 | node = -1; | 412 | node = -1; |
391 | 413 | ||
392 | /* Allocate per-root-bus (not per bus) arch-specific data. | 414 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
393 | * TODO: leak; this memory is never freed. | 415 | 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: " | 416 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
399 | "ignored (out of memory)\n", domain, busnum); | 417 | "ignored (out of memory)\n", domain, busnum); |
400 | return NULL; | 418 | return NULL; |
401 | } | 419 | } |
402 | 420 | ||
421 | sd = &info->sd; | ||
403 | sd->domain = domain; | 422 | sd->domain = domain; |
404 | sd->node = node; | 423 | sd->node = node; |
405 | /* | 424 | /* |
@@ -413,22 +432,32 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
413 | * be replaced by sd. | 432 | * be replaced by sd. |
414 | */ | 433 | */ |
415 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 434 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
416 | kfree(sd); | 435 | kfree(info); |
417 | } else { | 436 | } else { |
418 | get_current_resources(device, busnum, domain, &resources); | 437 | probe_pci_root_info(info, device, busnum, domain); |
419 | 438 | ||
420 | /* | 439 | /* |
421 | * _CRS with no apertures is normal, so only fall back to | 440 | * _CRS with no apertures is normal, so only fall back to |
422 | * defaults or native bridge info if we're ignoring _CRS. | 441 | * defaults or native bridge info if we're ignoring _CRS. |
423 | */ | 442 | */ |
424 | if (!pci_use_crs) | 443 | if (pci_use_crs) |
444 | add_resources(info, &resources); | ||
445 | else { | ||
446 | free_pci_root_info_res(info); | ||
425 | x86_pci_root_bus_resources(busnum, &resources); | 447 | x86_pci_root_bus_resources(busnum, &resources); |
448 | } | ||
449 | |||
426 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, | 450 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, |
427 | &resources); | 451 | &resources); |
428 | if (bus) | 452 | if (bus) { |
429 | bus->subordinate = pci_scan_child_bus(bus); | 453 | bus->subordinate = pci_scan_child_bus(bus); |
430 | else | 454 | pci_set_host_bridge_release( |
455 | to_pci_host_bridge(bus->bridge), | ||
456 | release_pci_root_info, info); | ||
457 | } else { | ||
431 | pci_free_resource_list(&resources); | 458 | pci_free_resource_list(&resources); |
459 | __release_pci_root_info(info); | ||
460 | } | ||
432 | } | 461 | } |
433 | 462 | ||
434 | /* After the PCI-E bus has been walked and all devices discovered, | 463 | /* After the PCI-E bus has been walked and all devices discovered, |
@@ -445,9 +474,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
445 | } | 474 | } |
446 | } | 475 | } |
447 | 476 | ||
448 | if (!bus) | ||
449 | kfree(sd); | ||
450 | |||
451 | if (bus && node != -1) { | 477 | if (bus && node != -1) { |
452 | #ifdef CONFIG_ACPI_NUMA | 478 | #ifdef CONFIG_ACPI_NUMA |
453 | if (pxm >= 0) | 479 | if (pxm >= 0) |
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 0567df3890e1..459a7316375c 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -32,6 +32,18 @@ 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 | |||
35 | /** | 47 | /** |
36 | * early_fill_mp_bus_to_node() | 48 | * early_fill_mp_bus_to_node() |
37 | * called before pcibios_scan_root and pci_scan_bus | 49 | * called before pcibios_scan_root and pci_scan_bus |
@@ -50,7 +62,6 @@ static int __init early_fill_mp_bus_info(void) | |||
50 | int def_link; | 62 | int def_link; |
51 | struct pci_root_info *info; | 63 | struct pci_root_info *info; |
52 | u32 reg; | 64 | u32 reg; |
53 | struct resource *res; | ||
54 | u64 start; | 65 | u64 start; |
55 | u64 end; | 66 | u64 end; |
56 | struct range range[RANGE_NUM]; | 67 | struct range range[RANGE_NUM]; |
@@ -86,7 +97,6 @@ static int __init early_fill_mp_bus_info(void) | |||
86 | if (!found) | 97 | if (!found) |
87 | return 0; | 98 | return 0; |
88 | 99 | ||
89 | pci_root_num = 0; | ||
90 | for (i = 0; i < 4; i++) { | 100 | for (i = 0; i < 4; i++) { |
91 | int min_bus; | 101 | int min_bus; |
92 | int max_bus; | 102 | int max_bus; |
@@ -105,13 +115,8 @@ static int __init early_fill_mp_bus_info(void) | |||
105 | #endif | 115 | #endif |
106 | link = (reg >> 8) & 0x03; | 116 | link = (reg >> 8) & 0x03; |
107 | 117 | ||
108 | info = &pci_root_info[pci_root_num]; | 118 | 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); | 119 | sprintf(info->name, "PCI Bus #%02x", min_bus); |
114 | pci_root_num++; | ||
115 | } | 120 | } |
116 | 121 | ||
117 | /* get the default node and link for left over res */ | 122 | /* get the default node and link for left over res */ |
@@ -134,16 +139,10 @@ static int __init early_fill_mp_bus_info(void) | |||
134 | link = (reg >> 4) & 0x03; | 139 | link = (reg >> 4) & 0x03; |
135 | end = (reg & 0xfff000) | 0xfff; | 140 | end = (reg & 0xfff000) | 0xfff; |
136 | 141 | ||
137 | /* find the position */ | 142 | info = find_pci_root_info(node, link); |
138 | for (j = 0; j < pci_root_num; j++) { | 143 | 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 */ | 144 | continue; /* not found */ |
145 | 145 | ||
146 | info = &pci_root_info[j]; | ||
147 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | 146 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", |
148 | node, link, start, end); | 147 | node, link, start, end); |
149 | 148 | ||
@@ -155,13 +154,8 @@ static int __init early_fill_mp_bus_info(void) | |||
155 | } | 154 | } |
156 | /* add left over io port range to def node/link, [0, 0xffff] */ | 155 | /* add left over io port range to def node/link, [0, 0xffff] */ |
157 | /* find the position */ | 156 | /* find the position */ |
158 | for (j = 0; j < pci_root_num; j++) { | 157 | info = find_pci_root_info(def_node, def_link); |
159 | info = &pci_root_info[j]; | 158 | 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++) { | 159 | for (i = 0; i < RANGE_NUM; i++) { |
166 | if (!range[i].end) | 160 | if (!range[i].end) |
167 | continue; | 161 | continue; |
@@ -214,16 +208,10 @@ static int __init early_fill_mp_bus_info(void) | |||
214 | end <<= 8; | 208 | end <<= 8; |
215 | end |= 0xffff; | 209 | end |= 0xffff; |
216 | 210 | ||
217 | /* find the position */ | 211 | 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 | 212 | ||
226 | info = &pci_root_info[j]; | 213 | if (!info) |
214 | continue; | ||
227 | 215 | ||
228 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 216 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
229 | node, link, start, end); | 217 | node, link, start, end); |
@@ -291,14 +279,8 @@ static int __init early_fill_mp_bus_info(void) | |||
291 | * add left over mmio range to def node/link ? | 279 | * add left over mmio range to def node/link ? |
292 | * that is tricky, just record range in from start_min to 4G | 280 | * that is tricky, just record range in from start_min to 4G |
293 | */ | 281 | */ |
294 | for (j = 0; j < pci_root_num; j++) { | 282 | info = find_pci_root_info(def_node, def_link); |
295 | info = &pci_root_info[j]; | 283 | 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++) { | 284 | for (i = 0; i < RANGE_NUM; i++) { |
303 | if (!range[i].end) | 285 | if (!range[i].end) |
304 | continue; | 286 | continue; |
@@ -309,20 +291,16 @@ static int __init early_fill_mp_bus_info(void) | |||
309 | } | 291 | } |
310 | } | 292 | } |
311 | 293 | ||
312 | for (i = 0; i < pci_root_num; i++) { | 294 | list_for_each_entry(info, &pci_root_infos, list) { |
313 | int res_num; | ||
314 | int busnum; | 295 | int busnum; |
296 | struct pci_root_res *root_res; | ||
315 | 297 | ||
316 | info = &pci_root_info[i]; | ||
317 | res_num = info->res_num; | ||
318 | busnum = info->bus_min; | 298 | busnum = info->bus_min; |
319 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", | 299 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
320 | info->bus_min, info->bus_max, info->node, info->link); | 300 | info->bus_min, info->bus_max, info->node, info->link); |
321 | for (j = 0; j < res_num; j++) { | 301 | list_for_each_entry(root_res, &info->resources, list) |
322 | res = &info->res[j]; | 302 | printk(KERN_DEBUG "bus: %02x %pR\n", |
323 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", | 303 | busnum, &root_res->res); |
324 | busnum, j, res); | ||
325 | } | ||
326 | } | 304 | } |
327 | 305 | ||
328 | return 0; | 306 | 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..8e04ec591543 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -430,9 +430,7 @@ void __init dmi_check_pciprobe(void) | |||
430 | 430 | ||
431 | struct pci_bus * __devinit pcibios_scan_root(int busnum) | 431 | struct pci_bus * __devinit pcibios_scan_root(int busnum) |
432 | { | 432 | { |
433 | LIST_HEAD(resources); | ||
434 | struct pci_bus *bus = NULL; | 433 | struct pci_bus *bus = NULL; |
435 | struct pci_sysdata *sd; | ||
436 | 434 | ||
437 | while ((bus = pci_find_next_bus(bus)) != NULL) { | 435 | while ((bus = pci_find_next_bus(bus)) != NULL) { |
438 | if (bus->number == busnum) { | 436 | if (bus->number == busnum) { |
@@ -441,28 +439,10 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) | |||
441 | } | 439 | } |
442 | } | 440 | } |
443 | 441 | ||
444 | /* Allocate per-root-bus (not per bus) arch-specific data. | 442 | return pci_scan_bus_on_node(busnum, &pci_root_ops, |
445 | * TODO: leak; this memory is never freed. | 443 | 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 | } | 444 | } |
445 | |||
466 | void __init pcibios_set_cache_line_size(void) | 446 | void __init pcibios_set_cache_line_size(void) |
467 | { | 447 | { |
468 | struct cpuinfo_x86 *c = &boot_cpu_data; | 448 | struct cpuinfo_x86 *c = &boot_cpu_data; |
@@ -656,6 +636,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, | |||
656 | } | 636 | } |
657 | sd->node = node; | 637 | sd->node = node; |
658 | x86_pci_root_bus_resources(busno, &resources); | 638 | x86_pci_root_bus_resources(busno, &resources); |
639 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno); | ||
659 | bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); | 640 | bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources); |
660 | if (!bus) { | 641 | if (!bus) { |
661 | pci_free_resource_list(&resources); | 642 | pci_free_resource_list(&resources); |
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 083a49fee56a..2c224edae1ac 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the PCI bus specific drivers. | 2 | # Makefile for the PCI bus specific drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += access.o bus.o probe.o remove.o pci.o \ | 5 | obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ |
6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ | 6 | pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ |
7 | irq.o vpd.o | 7 | irq.o vpd.o |
8 | obj-$(CONFIG_PROC_FS) += proc.o | 8 | obj-$(CONFIG_PROC_FS) += proc.o |
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c new file mode 100644 index 000000000000..a68dc613a5be --- /dev/null +++ b/drivers/pci/host-bridge.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * host bridge related code | ||
3 | */ | ||
4 | |||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/pci.h> | ||
8 | #include <linux/module.h> | ||
9 | |||
10 | #include "pci.h" | ||
11 | |||
12 | static struct pci_bus *find_pci_root_bus(struct pci_dev *dev) | ||
13 | { | ||
14 | struct pci_bus *bus; | ||
15 | |||
16 | bus = dev->bus; | ||
17 | while (bus->parent) | ||
18 | bus = bus->parent; | ||
19 | |||
20 | return bus; | ||
21 | } | ||
22 | |||
23 | static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev) | ||
24 | { | ||
25 | struct pci_bus *bus = find_pci_root_bus(dev); | ||
26 | |||
27 | return to_pci_host_bridge(bus->bridge); | ||
28 | } | ||
29 | |||
30 | void pci_set_host_bridge_release(struct pci_host_bridge *bridge, | ||
31 | void (*release_fn)(struct pci_host_bridge *), | ||
32 | void *release_data) | ||
33 | { | ||
34 | bridge->release_fn = release_fn; | ||
35 | bridge->release_data = release_data; | ||
36 | } | ||
37 | |||
38 | static bool resource_contains(struct resource *res1, struct resource *res2) | ||
39 | { | ||
40 | return res1->start <= res2->start && res1->end >= res2->end; | ||
41 | } | ||
42 | |||
43 | void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, | ||
44 | struct resource *res) | ||
45 | { | ||
46 | struct pci_host_bridge *bridge = find_pci_host_bridge(dev); | ||
47 | struct pci_host_bridge_window *window; | ||
48 | resource_size_t offset = 0; | ||
49 | |||
50 | list_for_each_entry(window, &bridge->windows, list) { | ||
51 | if (resource_type(res) != resource_type(window->res)) | ||
52 | continue; | ||
53 | |||
54 | if (resource_contains(window->res, res)) { | ||
55 | offset = window->offset; | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | region->start = res->start - offset; | ||
61 | region->end = res->end - offset; | ||
62 | } | ||
63 | EXPORT_SYMBOL(pcibios_resource_to_bus); | ||
64 | |||
65 | static bool region_contains(struct pci_bus_region *region1, | ||
66 | struct pci_bus_region *region2) | ||
67 | { | ||
68 | return region1->start <= region2->start && region1->end >= region2->end; | ||
69 | } | ||
70 | |||
71 | void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, | ||
72 | struct pci_bus_region *region) | ||
73 | { | ||
74 | struct pci_host_bridge *bridge = find_pci_host_bridge(dev); | ||
75 | struct pci_host_bridge_window *window; | ||
76 | resource_size_t offset = 0; | ||
77 | |||
78 | list_for_each_entry(window, &bridge->windows, list) { | ||
79 | struct pci_bus_region bus_region; | ||
80 | |||
81 | if (resource_type(res) != resource_type(window->res)) | ||
82 | continue; | ||
83 | |||
84 | bus_region.start = window->res->start - window->offset; | ||
85 | bus_region.end = window->res->end - window->offset; | ||
86 | |||
87 | if (region_contains(&bus_region, region)) { | ||
88 | offset = window->offset; | ||
89 | break; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | res->start = region->start + offset; | ||
94 | res->end = region->end + offset; | ||
95 | } | ||
96 | EXPORT_SYMBOL(pcibios_bus_to_resource); | ||
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5e1ca3c58a7d..4c2f22668ea7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -15,13 +15,10 @@ | |||
15 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ | 15 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ |
16 | #define CARDBUS_RESERVE_BUSNR 3 | 16 | #define CARDBUS_RESERVE_BUSNR 3 |
17 | 17 | ||
18 | static LIST_HEAD(pci_host_bridges); | ||
19 | |||
20 | /* Ugh. Need to stop exporting this to modules. */ | 18 | /* Ugh. Need to stop exporting this to modules. */ |
21 | LIST_HEAD(pci_root_buses); | 19 | LIST_HEAD(pci_root_buses); |
22 | EXPORT_SYMBOL(pci_root_buses); | 20 | EXPORT_SYMBOL(pci_root_buses); |
23 | 21 | ||
24 | |||
25 | static int find_anything(struct device *dev, void *data) | 22 | static int find_anything(struct device *dev, void *data) |
26 | { | 23 | { |
27 | return 1; | 24 | return 1; |
@@ -44,82 +41,6 @@ int no_pci_devices(void) | |||
44 | } | 41 | } |
45 | EXPORT_SYMBOL(no_pci_devices); | 42 | EXPORT_SYMBOL(no_pci_devices); |
46 | 43 | ||
47 | static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev) | ||
48 | { | ||
49 | struct pci_bus *bus; | ||
50 | struct pci_host_bridge *bridge; | ||
51 | |||
52 | bus = dev->bus; | ||
53 | while (bus->parent) | ||
54 | bus = bus->parent; | ||
55 | |||
56 | list_for_each_entry(bridge, &pci_host_bridges, list) { | ||
57 | if (bridge->bus == bus) | ||
58 | return bridge; | ||
59 | } | ||
60 | |||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | static bool resource_contains(struct resource *res1, struct resource *res2) | ||
65 | { | ||
66 | return res1->start <= res2->start && res1->end >= res2->end; | ||
67 | } | ||
68 | |||
69 | void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, | ||
70 | struct resource *res) | ||
71 | { | ||
72 | struct pci_host_bridge *bridge = pci_host_bridge(dev); | ||
73 | struct pci_host_bridge_window *window; | ||
74 | resource_size_t offset = 0; | ||
75 | |||
76 | list_for_each_entry(window, &bridge->windows, list) { | ||
77 | if (resource_type(res) != resource_type(window->res)) | ||
78 | continue; | ||
79 | |||
80 | if (resource_contains(window->res, res)) { | ||
81 | offset = window->offset; | ||
82 | break; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | region->start = res->start - offset; | ||
87 | region->end = res->end - offset; | ||
88 | } | ||
89 | EXPORT_SYMBOL(pcibios_resource_to_bus); | ||
90 | |||
91 | static bool region_contains(struct pci_bus_region *region1, | ||
92 | struct pci_bus_region *region2) | ||
93 | { | ||
94 | return region1->start <= region2->start && region1->end >= region2->end; | ||
95 | } | ||
96 | |||
97 | void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, | ||
98 | struct pci_bus_region *region) | ||
99 | { | ||
100 | struct pci_host_bridge *bridge = pci_host_bridge(dev); | ||
101 | struct pci_host_bridge_window *window; | ||
102 | struct pci_bus_region bus_region; | ||
103 | resource_size_t offset = 0; | ||
104 | |||
105 | list_for_each_entry(window, &bridge->windows, list) { | ||
106 | if (resource_type(res) != resource_type(window->res)) | ||
107 | continue; | ||
108 | |||
109 | bus_region.start = window->res->start - window->offset; | ||
110 | bus_region.end = window->res->end - window->offset; | ||
111 | |||
112 | if (region_contains(&bus_region, region)) { | ||
113 | offset = window->offset; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | res->start = region->start + offset; | ||
119 | res->end = region->end + offset; | ||
120 | } | ||
121 | EXPORT_SYMBOL(pcibios_bus_to_resource); | ||
122 | |||
123 | /* | 44 | /* |
124 | * PCI Bus Class | 45 | * PCI Bus Class |
125 | */ | 46 | */ |
@@ -501,6 +422,19 @@ static struct pci_bus * pci_alloc_bus(void) | |||
501 | return b; | 422 | return b; |
502 | } | 423 | } |
503 | 424 | ||
425 | static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) | ||
426 | { | ||
427 | struct pci_host_bridge *bridge; | ||
428 | |||
429 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | ||
430 | if (bridge) { | ||
431 | INIT_LIST_HEAD(&bridge->windows); | ||
432 | bridge->bus = b; | ||
433 | } | ||
434 | |||
435 | return bridge; | ||
436 | } | ||
437 | |||
504 | static unsigned char pcix_bus_speed[] = { | 438 | static unsigned char pcix_bus_speed[] = { |
505 | PCI_SPEED_UNKNOWN, /* 0 */ | 439 | PCI_SPEED_UNKNOWN, /* 0 */ |
506 | PCI_SPEED_66MHz_PCIX, /* 1 */ | 440 | PCI_SPEED_66MHz_PCIX, /* 1 */ |
@@ -1201,7 +1135,14 @@ int pci_cfg_space_size(struct pci_dev *dev) | |||
1201 | 1135 | ||
1202 | static void pci_release_bus_bridge_dev(struct device *dev) | 1136 | static void pci_release_bus_bridge_dev(struct device *dev) |
1203 | { | 1137 | { |
1204 | kfree(dev); | 1138 | struct pci_host_bridge *bridge = to_pci_host_bridge(dev); |
1139 | |||
1140 | if (bridge->release_fn) | ||
1141 | bridge->release_fn(bridge); | ||
1142 | |||
1143 | pci_free_resource_list(&bridge->windows); | ||
1144 | |||
1145 | kfree(bridge); | ||
1205 | } | 1146 | } |
1206 | 1147 | ||
1207 | struct pci_dev *alloc_pci_dev(void) | 1148 | struct pci_dev *alloc_pci_dev(void) |
@@ -1650,28 +1591,19 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1650 | int error; | 1591 | int error; |
1651 | struct pci_host_bridge *bridge; | 1592 | struct pci_host_bridge *bridge; |
1652 | struct pci_bus *b, *b2; | 1593 | struct pci_bus *b, *b2; |
1653 | struct device *dev; | ||
1654 | struct pci_host_bridge_window *window, *n; | 1594 | struct pci_host_bridge_window *window, *n; |
1655 | struct resource *res; | 1595 | struct resource *res; |
1656 | resource_size_t offset; | 1596 | resource_size_t offset; |
1657 | char bus_addr[64]; | 1597 | char bus_addr[64]; |
1658 | char *fmt; | 1598 | char *fmt; |
1659 | 1599 | ||
1660 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | ||
1661 | if (!bridge) | ||
1662 | return NULL; | ||
1663 | 1600 | ||
1664 | b = pci_alloc_bus(); | 1601 | b = pci_alloc_bus(); |
1665 | if (!b) | 1602 | if (!b) |
1666 | goto err_bus; | 1603 | return NULL; |
1667 | |||
1668 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
1669 | if (!dev) | ||
1670 | goto err_dev; | ||
1671 | 1604 | ||
1672 | b->sysdata = sysdata; | 1605 | b->sysdata = sysdata; |
1673 | b->ops = ops; | 1606 | b->ops = ops; |
1674 | |||
1675 | b2 = pci_find_bus(pci_domain_nr(b), bus); | 1607 | b2 = pci_find_bus(pci_domain_nr(b), bus); |
1676 | if (b2) { | 1608 | if (b2) { |
1677 | /* If we already got to this bus through a different bridge, ignore it */ | 1609 | /* If we already got to this bus through a different bridge, ignore it */ |
@@ -1679,13 +1611,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1679 | goto err_out; | 1611 | goto err_out; |
1680 | } | 1612 | } |
1681 | 1613 | ||
1682 | dev->parent = parent; | 1614 | bridge = pci_alloc_host_bridge(b); |
1683 | dev->release = pci_release_bus_bridge_dev; | 1615 | if (!bridge) |
1684 | dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus); | 1616 | goto err_out; |
1685 | error = device_register(dev); | 1617 | |
1618 | bridge->dev.parent = parent; | ||
1619 | bridge->dev.release = pci_release_bus_bridge_dev; | ||
1620 | dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); | ||
1621 | error = device_register(&bridge->dev); | ||
1686 | if (error) | 1622 | if (error) |
1687 | goto dev_reg_err; | 1623 | goto bridge_dev_reg_err; |
1688 | b->bridge = get_device(dev); | 1624 | b->bridge = get_device(&bridge->dev); |
1689 | device_enable_async_suspend(b->bridge); | 1625 | device_enable_async_suspend(b->bridge); |
1690 | pci_set_bus_of_node(b); | 1626 | pci_set_bus_of_node(b); |
1691 | 1627 | ||
@@ -1704,9 +1640,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1704 | 1640 | ||
1705 | b->number = b->secondary = bus; | 1641 | b->number = b->secondary = bus; |
1706 | 1642 | ||
1707 | bridge->bus = b; | ||
1708 | INIT_LIST_HEAD(&bridge->windows); | ||
1709 | |||
1710 | if (parent) | 1643 | if (parent) |
1711 | dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); | 1644 | dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); |
1712 | else | 1645 | else |
@@ -1732,25 +1665,18 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1732 | } | 1665 | } |
1733 | 1666 | ||
1734 | down_write(&pci_bus_sem); | 1667 | down_write(&pci_bus_sem); |
1735 | list_add_tail(&bridge->list, &pci_host_bridges); | ||
1736 | list_add_tail(&b->node, &pci_root_buses); | 1668 | list_add_tail(&b->node, &pci_root_buses); |
1737 | up_write(&pci_bus_sem); | 1669 | up_write(&pci_bus_sem); |
1738 | 1670 | ||
1739 | return b; | 1671 | return b; |
1740 | 1672 | ||
1741 | class_dev_reg_err: | 1673 | class_dev_reg_err: |
1742 | device_unregister(dev); | 1674 | put_device(&bridge->dev); |
1743 | dev_reg_err: | 1675 | device_unregister(&bridge->dev); |
1744 | down_write(&pci_bus_sem); | 1676 | bridge_dev_reg_err: |
1745 | list_del(&bridge->list); | 1677 | kfree(bridge); |
1746 | list_del(&b->node); | ||
1747 | up_write(&pci_bus_sem); | ||
1748 | err_out: | 1678 | err_out: |
1749 | kfree(dev); | ||
1750 | err_dev: | ||
1751 | kfree(b); | 1679 | kfree(b); |
1752 | err_bus: | ||
1753 | kfree(bridge); | ||
1754 | return NULL; | 1680 | return NULL; |
1755 | } | 1681 | } |
1756 | 1682 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index e444f5b49118..17b7b5b01b4a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -375,11 +375,18 @@ struct pci_host_bridge_window { | |||
375 | }; | 375 | }; |
376 | 376 | ||
377 | struct pci_host_bridge { | 377 | struct pci_host_bridge { |
378 | struct list_head list; | 378 | struct device dev; |
379 | struct pci_bus *bus; /* root bus */ | 379 | struct pci_bus *bus; /* root bus */ |
380 | struct list_head windows; /* pci_host_bridge_windows */ | 380 | struct list_head windows; /* pci_host_bridge_windows */ |
381 | void (*release_fn)(struct pci_host_bridge *); | ||
382 | void *release_data; | ||
381 | }; | 383 | }; |
382 | 384 | ||
385 | #define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev) | ||
386 | void pci_set_host_bridge_release(struct pci_host_bridge *bridge, | ||
387 | void (*release_fn)(struct pci_host_bridge *), | ||
388 | void *release_data); | ||
389 | |||
383 | /* | 390 | /* |
384 | * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond | 391 | * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond |
385 | * to P2P or CardBus bridge windows) go in a table. Additional ones (for | 392 | * to P2P or CardBus bridge windows) go in a table. Additional ones (for |