diff options
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r-- | arch/x86/pci/acpi.c | 128 |
1 files changed, 72 insertions, 56 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) |