diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2009-02-17 00:13:59 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-03-20 13:48:02 -0400 |
commit | d391f00f0e7fb6d883c6724b31a1799e19a584c5 (patch) | |
tree | 02d81d24488963f97c6d4d2e102ead27fcf78ae5 /drivers/pci | |
parent | 267efd7eec5eca62f32f8c9bc1721b578d5da963 (diff) |
PCI hotplug: fix wrong assumption in acpi_get_hp_hw_control_from_firmware
Current acpi_get_hp_hw_control_from_firmware() has a assumption that
pci_bus->self is NULL on a PCI root bus. But it might not be true on
some platforms. Because of this wrong assumption, current
acpi_get_hp_hw_control_from_firmware() might cause endless loop. We
must check pci_bus->parent instead.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 34 |
1 files changed, 12 insertions, 22 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 09a84402986d..fbc63d5e459f 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -372,12 +372,10 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); | |||
372 | * | 372 | * |
373 | * Attempt to take hotplug control from firmware. | 373 | * Attempt to take hotplug control from firmware. |
374 | */ | 374 | */ |
375 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | 375 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) |
376 | { | 376 | { |
377 | acpi_status status; | 377 | acpi_status status; |
378 | acpi_handle chandle, handle; | 378 | acpi_handle chandle, handle; |
379 | struct pci_dev *pdev = dev; | ||
380 | struct pci_bus *parent; | ||
381 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | 379 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
382 | 380 | ||
383 | flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | | 381 | flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | |
@@ -409,26 +407,18 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | |||
409 | string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; | 407 | string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; |
410 | } | 408 | } |
411 | 409 | ||
412 | pdev = dev; | 410 | handle = DEVICE_ACPI_HANDLE(&pdev->dev); |
413 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | 411 | if (!handle) { |
414 | while (!handle) { | ||
415 | /* | 412 | /* |
416 | * This hotplug controller was not listed in the ACPI name | 413 | * This hotplug controller was not listed in the ACPI name |
417 | * space at all. Try to get acpi handle of parent pci bus. | 414 | * space at all. Try to get acpi handle of parent pci bus. |
418 | */ | 415 | */ |
419 | if (!pdev || !pdev->bus->parent) | 416 | struct pci_bus *pbus; |
420 | break; | 417 | for (pbus = pdev->bus; pbus; pbus = pbus->parent) { |
421 | parent = pdev->bus->parent; | 418 | handle = acpi_pci_get_bridge_handle(pbus); |
422 | dbg("Could not find %s in acpi namespace, trying parent\n", | 419 | if (handle) |
423 | pci_name(pdev)); | 420 | break; |
424 | if (!parent->self) | 421 | } |
425 | /* Parent must be a host bridge */ | ||
426 | handle = acpi_get_pci_rootbridge_handle( | ||
427 | pci_domain_nr(parent), | ||
428 | parent->number); | ||
429 | else | ||
430 | handle = DEVICE_ACPI_HANDLE(&(parent->self->dev)); | ||
431 | pdev = parent->self; | ||
432 | } | 422 | } |
433 | 423 | ||
434 | while (handle) { | 424 | while (handle) { |
@@ -447,13 +437,13 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | |||
447 | } | 437 | } |
448 | 438 | ||
449 | dbg("Cannot get control of hotplug hardware for pci %s\n", | 439 | dbg("Cannot get control of hotplug hardware for pci %s\n", |
450 | pci_name(dev)); | 440 | pci_name(pdev)); |
451 | 441 | ||
452 | kfree(string.pointer); | 442 | kfree(string.pointer); |
453 | return -ENODEV; | 443 | return -ENODEV; |
454 | got_one: | 444 | got_one: |
455 | dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), | 445 | dbg("Gained control for hotplug HW for pci %s (%s)\n", |
456 | (char *)string.pointer); | 446 | pci_name(pdev), (char *)string.pointer); |
457 | kfree(string.pointer); | 447 | kfree(string.pointer); |
458 | return 0; | 448 | return 0; |
459 | } | 449 | } |