Merge branch 'akpm' (patches from Andrew)
[linux-2.6-block.git] / drivers / pci / hotplug / acpi_pcihp.c
index 5bd6c1573295696acf8387bd7cd953bf8f369546..6b7c1ed58e7e0a2d881a97436c87ee4bc6ab7d20 100644 (file)
@@ -73,20 +73,6 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
        acpi_handle chandle, handle;
        struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
-       /*
-        * Per PCI firmware specification, we should run the ACPI _OSC
-        * method to get control of hotplug hardware before using it. If
-        * an _OSC is missing, we look for an OSHP to do the same thing.
-        * To handle different BIOS behavior, we look for _OSC on a root
-        * bridge preferentially (according to PCI fw spec). Later for
-        * OSHP within the scope of the hotplug controller and its parents,
-        * up to the host bridge under which this controller exists.
-        */
-       if (shpchp_is_native(pdev))
-               return 0;
-
-       /* If _OSC exists, we should not evaluate OSHP */
-
        /*
         * If there's no ACPI host bridge (i.e., ACPI support is compiled
         * into the kernel but the hardware platform doesn't support ACPI),
@@ -97,9 +83,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
        if (!root)
                return 0;
 
-       if (root->osc_support_set)
-               goto no_control;
+       /*
+        * If _OSC exists, it determines whether we're allowed to manage
+        * the SHPC.  We executed it while enumerating the host bridge.
+        */
+       if (root->osc_support_set) {
+               if (host->native_shpc_hotplug)
+                       return 0;
+               return -ENODEV;
+       }
 
+       /*
+        * In the absence of _OSC, we're always allowed to manage the SHPC.
+        * However, if an OSHP method is present, we must execute it so the
+        * firmware can transfer control to the OS, e.g., direct interrupts
+        * to the OS instead of to the firmware.
+        *
+        * N.B. The PCI Firmware Spec (r3.2, sec 4.8) does not endorse
+        * searching up the ACPI hierarchy, so the loops below are suspect.
+        */
        handle = ACPI_HANDLE(&pdev->dev);
        if (!handle) {
                /*
@@ -128,7 +130,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
                if (ACPI_FAILURE(status))
                        break;
        }
-no_control:
+
        pci_info(pdev, "Cannot get control of SHPC hotplug\n");
        kfree(string.pointer);
        return -ENODEV;