diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2008-08-11 11:47:40 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-08-18 16:47:20 -0400 |
commit | e0d94beead4ef652ec1c066be886140eebb06d8b (patch) | |
tree | 5009a20f5242b0399a2eabe4410d932bc1491fff | |
parent | 89499759dc0dd300528510f465b0bf532fc79a2a (diff) |
PCI: acpi_pcihp: run _OSC on a root bridge
_OSC should be ran on a root bridge instead of the device itself. Do
this before touching OSHP since PCI fw specs states that _OSC should be
preferred over OSHP (however if the device has OSHP but not _OSC -- not
a root bridge -- it's not).
Cc: kristen.c.accardi@intel.com
Acked-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 93e37f0666ab..bd831970f00b 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -382,7 +382,7 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); | |||
382 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | 382 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) |
383 | { | 383 | { |
384 | acpi_status status; | 384 | acpi_status status; |
385 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | 385 | acpi_handle chandle, handle; |
386 | struct pci_dev *pdev = dev; | 386 | struct pci_dev *pdev = dev; |
387 | struct pci_bus *parent; | 387 | struct pci_bus *parent; |
388 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; | 388 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
@@ -399,10 +399,28 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | |||
399 | * Per PCI firmware specification, we should run the ACPI _OSC | 399 | * Per PCI firmware specification, we should run the ACPI _OSC |
400 | * method to get control of hotplug hardware before using it. If | 400 | * method to get control of hotplug hardware before using it. If |
401 | * an _OSC is missing, we look for an OSHP to do the same thing. | 401 | * an _OSC is missing, we look for an OSHP to do the same thing. |
402 | * To handle different BIOS behavior, we look for _OSC and OSHP | 402 | * To handle different BIOS behavior, we look for _OSC on a root |
403 | * within the scope of the hotplug controller and its parents, | 403 | * bridge preferentially (according to PCI fw spec). Later for |
404 | * OSHP within the scope of the hotplug controller and its parents, | ||
404 | * upto the host bridge under which this controller exists. | 405 | * upto the host bridge under which this controller exists. |
405 | */ | 406 | */ |
407 | while (pdev->bus->self) | ||
408 | pdev = pdev->bus->self; | ||
409 | handle = acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus), | ||
410 | pdev->bus->number); | ||
411 | if (handle) { | ||
412 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | ||
413 | dbg("Trying to get hotplug control for %s\n", | ||
414 | (char *)string.pointer); | ||
415 | status = pci_osc_control_set(handle, flags); | ||
416 | if (ACPI_SUCCESS(status)) | ||
417 | goto got_one; | ||
418 | kfree(string.pointer); | ||
419 | string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; | ||
420 | } | ||
421 | |||
422 | pdev = dev; | ||
423 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
406 | while (!handle) { | 424 | while (!handle) { |
407 | /* | 425 | /* |
408 | * This hotplug controller was not listed in the ACPI name | 426 | * This hotplug controller was not listed in the ACPI name |
@@ -427,15 +445,9 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | |||
427 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | 445 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); |
428 | dbg("Trying to get hotplug control for %s \n", | 446 | dbg("Trying to get hotplug control for %s \n", |
429 | (char *)string.pointer); | 447 | (char *)string.pointer); |
430 | status = pci_osc_control_set(handle, flags); | 448 | status = acpi_run_oshp(handle); |
431 | if (status == AE_NOT_FOUND) | 449 | if (ACPI_SUCCESS(status)) |
432 | status = acpi_run_oshp(handle); | 450 | goto got_one; |
433 | if (ACPI_SUCCESS(status)) { | ||
434 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | ||
435 | pci_name(dev), (char *)string.pointer); | ||
436 | kfree(string.pointer); | ||
437 | return 0; | ||
438 | } | ||
439 | if (acpi_root_bridge(handle)) | 451 | if (acpi_root_bridge(handle)) |
440 | break; | 452 | break; |
441 | chandle = handle; | 453 | chandle = handle; |
@@ -449,6 +461,11 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) | |||
449 | 461 | ||
450 | kfree(string.pointer); | 462 | kfree(string.pointer); |
451 | return -ENODEV; | 463 | return -ENODEV; |
464 | got_one: | ||
465 | dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), | ||
466 | (char *)string.pointer); | ||
467 | kfree(string.pointer); | ||
468 | return 0; | ||
452 | } | 469 | } |
453 | EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); | 470 | EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); |
454 | 471 | ||