ACPI / PM: Register power resource devices as soon as they are needed
authorRafael J. Wysocki <rjw@sisk.pl>
Wed, 24 Nov 2010 23:10:44 +0000 (00:10 +0100)
committerLen Brown <len.brown@intel.com>
Wed, 12 Jan 2011 09:48:45 +0000 (04:48 -0500)
Depending on the organization of the ACPI namespace, power resource
device objects may generally be scanned after the "regular" device
objects that they are referred from through _PRn.  This, in turn, may
cause acpi_bus_get_power_flags() to attempt to access them through
acpi_bus_init_power() before they are registered (and initialized by
acpi_power_driver).  [This is not a theoretical issue, it actually
happens for one PnP device on my testbed HP nx6325.]

To fix this problem, make acpi_bus_get_power_flags() attempt to
register power resource devices as soon as they have been found in
the _PRn output for any other devices.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/scan.c

index 2951a27303cb7c454f9fc755ec7397df0ca3fb18..cb7956c23ca4932825fe4b27720fa6c264d2270b 100644 (file)
@@ -847,6 +847,8 @@ end:
        return 0;
 }
 
+static void acpi_bus_add_power_resource(acpi_handle handle);
+
 static int acpi_bus_get_power_flags(struct acpi_device *device)
 {
        acpi_status status = 0;
@@ -875,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
                acpi_evaluate_reference(device->handle, object_name, NULL,
                                        &ps->resources);
                if (ps->resources.count) {
+                       int j;
+
                        device->power.flags.power_resources = 1;
                        ps->flags.valid = 1;
+                       for (j = 0; j < ps->resources.count; j++)
+                               acpi_bus_add_power_resource(ps->resources.handles[j]);
                }
 
                /* Evaluate "_PSx" to see if we can do explicit sets */
@@ -1323,6 +1329,20 @@ end:
 #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
                          ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING)
 
+static void acpi_bus_add_power_resource(acpi_handle handle)
+{
+       struct acpi_bus_ops ops = {
+               .acpi_op_add = 1,
+               .acpi_op_start = 1,
+       };
+       struct acpi_device *device = NULL;
+
+       acpi_bus_get_device(handle, &device);
+       if (!device)
+               acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
+                                       ACPI_STA_DEFAULT, &ops);
+}
+
 static int acpi_bus_type_and_status(acpi_handle handle, int *type,
                                    unsigned long long *sta)
 {