ACPI / PM: Do not power manage devices in unknown initial states
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 1 Feb 2013 22:43:02 +0000 (23:43 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 1 Feb 2013 22:43:02 +0000 (23:43 +0100)
In general, for ACPI device power management to work, the initial
power states of devices must be known (otherwise, we wouldn't be able
to keep track of power resources, for example).  Hence, if it is
impossible to determine the initial ACPI power states of some
devices, they can't be regarded as power-manageable using ACPI.

For this reason, modify acpi_bus_get_power_flags() to clear the
power_manageable flag if acpi_bus_init_power() fails and add some
extra fallback code to acpi_bus_init_power() to cover broken
BIOSes that provide _PS0/_PS3 without _PSC for some devices.

Verified to work on my HP nx6325 that has this problem.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Peter Wu <lekensteyn@gmail.com>
drivers/acpi/device_pm.c
drivers/acpi/scan.c

index 3ef075b718703632481bf88c81377811bef0d340..164d609d7c9eb81216e9c3504686f25f9c6b76c1 100644 (file)
@@ -330,6 +330,12 @@ int acpi_bus_init_power(struct acpi_device *device)
                result = acpi_dev_pm_explicit_set(device, state);
                if (result)
                        return result;
+       } else if (state == ACPI_STATE_UNKNOWN) {
+               /* No power resources and missing _PSC? Try to force D0. */
+               state = ACPI_STATE_D0;
+               result = acpi_dev_pm_explicit_set(device, state);
+               if (result)
+                       return result;
        }
        device->power.state = state;
        return 0;
index 9801837876b7bcd2be21ee66ec859b81040c7e81..f75f25c2e4557fed7d1868c9b6c30a5317cf4045 100644 (file)
@@ -1180,7 +1180,10 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
                        device->power.flags.power_resources)
                device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
 
-       acpi_bus_init_power(device);
+       if (acpi_bus_init_power(device)) {
+               acpi_free_power_resources_lists(device);
+               device->flags.power_manageable = 0;
+       }
 }
 
 static void acpi_bus_get_flags(struct acpi_device *device)