aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/device_pm.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-22 15:54:37 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-22 15:54:37 -0500
commit202317a573b20d77a9abb7c16a3fd5b40cef3d9d (patch)
tree2429aae549168cea780ac759939e1818b3487696 /drivers/acpi/device_pm.c
parentd783156ea38431b20af0d4f910a6f9f9054d33b9 (diff)
ACPI / scan: Add acpi_device objects for all device nodes in the namespace
Modify the ACPI namespace scanning code to register a struct acpi_device object for every namespace node representing a device, processor and so on, even if the device represented by that namespace node is reported to be not present and not functional by _STA. There are multiple reasons to do that. First of all, it avoids quite a lot of overhead when struct acpi_device objects are deleted every time acpi_bus_trim() is run and then added again by a subsequent acpi_bus_scan() for the same scope, although the namespace objects they correspond to stay in memory all the time (which always is the case on a vast majority of systems). Second, it will allow user space to see that there are namespace nodes representing devices that are not present at the moment and may be added to the system. It will also allow user space to evaluate _SUN for those nodes to check what physical slots the "missing" devices may be put into and it will make sense to add a sysfs attribute for _STA evaluation after this change (that will be useful for thermal management on some systems). Next, it will help to consolidate the ACPI hotplug handling among subsystems by making it possible to store hotplug-related information in struct acpi_device objects in a standard common way. Finally, it will help to avoid a race condition related to the deletion of ACPI namespace nodes. Namely, namespace nodes may be deleted as a result of a table unload triggered by _EJ0 or _DCK. If a hotplug notification for one of those nodes is triggered right before the deletion and it executes a hotplug callback via acpi_hotplug_execute(), the ACPI handle passed to that callback may be stale when the callback actually runs. One way to work around that is to always pass struct acpi_device pointers to hotplug callbacks after doing a get_device() on the objects in question which eliminates the use-after-free possibility (the ACPI handles in those objects are invalidated by acpi_scan_drop_device(), so they will trigger ACPICA errors on attempts to use them). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r--drivers/acpi/device_pm.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index b3480cf7db1a..d49f1e464703 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device)
256 return -EINVAL; 256 return -EINVAL;
257 257
258 device->power.state = ACPI_STATE_UNKNOWN; 258 device->power.state = ACPI_STATE_UNKNOWN;
259 if (!acpi_device_is_present(device))
260 return 0;
259 261
260 result = acpi_device_get_power(device, &state); 262 result = acpi_device_get_power(device, &state);
261 if (result) 263 if (result)
@@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device)
302 return ret; 304 return ret;
303} 305}
304 306
305int acpi_bus_update_power(acpi_handle handle, int *state_p) 307int acpi_device_update_power(struct acpi_device *device, int *state_p)
306{ 308{
307 struct acpi_device *device;
308 int state; 309 int state;
309 int result; 310 int result;
310 311
311 result = acpi_bus_get_device(handle, &device); 312 if (device->power.state == ACPI_STATE_UNKNOWN) {
312 if (result) 313 result = acpi_bus_init_power(device);
314 if (!result && state_p)
315 *state_p = device->power.state;
316
313 return result; 317 return result;
318 }
314 319
315 result = acpi_device_get_power(device, &state); 320 result = acpi_device_get_power(device, &state);
316 if (result) 321 if (result)
@@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
338 343
339 return 0; 344 return 0;
340} 345}
346
347int acpi_bus_update_power(acpi_handle handle, int *state_p)
348{
349 struct acpi_device *device;
350 int result;
351
352 result = acpi_bus_get_device(handle, &device);
353 return result ? result : acpi_device_update_power(device, state_p);
354}
341EXPORT_SYMBOL_GPL(acpi_bus_update_power); 355EXPORT_SYMBOL_GPL(acpi_bus_update_power);
342 356
343bool acpi_bus_power_manageable(acpi_handle handle) 357bool acpi_bus_power_manageable(acpi_handle handle)