diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-11-24 18:10:44 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-01-12 04:48:45 -0500 |
commit | bf325f9538d8c89312be305b9779edbcb436af00 (patch) | |
tree | fee681d8bf0c0058450b34a325bb60c5f02994aa /drivers/acpi/scan.c | |
parent | 97d9a9e9f5ee68f20005ca5aa77c6b684e7cace8 (diff) |
ACPI / PM: Register power resource devices as soon as they are needed
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>
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2951a27303c..cb7956c23ca 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -847,6 +847,8 @@ end: | |||
847 | return 0; | 847 | return 0; |
848 | } | 848 | } |
849 | 849 | ||
850 | static void acpi_bus_add_power_resource(acpi_handle handle); | ||
851 | |||
850 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 852 | static int acpi_bus_get_power_flags(struct acpi_device *device) |
851 | { | 853 | { |
852 | acpi_status status = 0; | 854 | acpi_status status = 0; |
@@ -875,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
875 | acpi_evaluate_reference(device->handle, object_name, NULL, | 877 | acpi_evaluate_reference(device->handle, object_name, NULL, |
876 | &ps->resources); | 878 | &ps->resources); |
877 | if (ps->resources.count) { | 879 | if (ps->resources.count) { |
880 | int j; | ||
881 | |||
878 | device->power.flags.power_resources = 1; | 882 | device->power.flags.power_resources = 1; |
879 | ps->flags.valid = 1; | 883 | ps->flags.valid = 1; |
884 | for (j = 0; j < ps->resources.count; j++) | ||
885 | acpi_bus_add_power_resource(ps->resources.handles[j]); | ||
880 | } | 886 | } |
881 | 887 | ||
882 | /* Evaluate "_PSx" to see if we can do explicit sets */ | 888 | /* Evaluate "_PSx" to see if we can do explicit sets */ |
@@ -1323,6 +1329,20 @@ end: | |||
1323 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ | 1329 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
1324 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) | 1330 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
1325 | 1331 | ||
1332 | static void acpi_bus_add_power_resource(acpi_handle handle) | ||
1333 | { | ||
1334 | struct acpi_bus_ops ops = { | ||
1335 | .acpi_op_add = 1, | ||
1336 | .acpi_op_start = 1, | ||
1337 | }; | ||
1338 | struct acpi_device *device = NULL; | ||
1339 | |||
1340 | acpi_bus_get_device(handle, &device); | ||
1341 | if (!device) | ||
1342 | acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, | ||
1343 | ACPI_STA_DEFAULT, &ops); | ||
1344 | } | ||
1345 | |||
1326 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, | 1346 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, |
1327 | unsigned long long *sta) | 1347 | unsigned long long *sta) |
1328 | { | 1348 | { |