Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI / LPSS: Power up LPSS devices during enumeration

Commit 7cd8407 (ACPI / PM: Do not execute _PS0 for devices without
_PSC during initialization) introduced a regression on some systems
with Intel Lynxpoint Low-Power Subsystem (LPSS) where some devices
need to be powered up during initialization, but their device objects
in the ACPI namespace have _PS0 and _PS3 only (without _PSC or power
resources).

To work around this problem, make the ACPI LPSS driver power up
devices it knows about by using a new helper function
acpi_device_fix_up_power() that does all of the necessary
sanity checks and calls acpi_dev_pm_explicit_set() to put the
device into D0.

Reported-and-tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+36 -6
+15 -6
drivers/acpi/acpi_lpss.c
··· 164 164 if (dev_desc->clk_required) { 165 165 ret = register_device_clock(adev, pdata); 166 166 if (ret) { 167 - /* 168 - * Skip the device, but don't terminate the namespace 169 - * scan. 170 - */ 171 - kfree(pdata); 172 - return 0; 167 + /* Skip the device, but continue the namespace scan. */ 168 + ret = 0; 169 + goto err_out; 173 170 } 171 + } 172 + 173 + /* 174 + * This works around a known issue in ACPI tables where LPSS devices 175 + * have _PS0 and _PS3 without _PSC (and no power resources), so 176 + * acpi_bus_init_power() will assume that the BIOS has put them into D0. 177 + */ 178 + ret = acpi_device_fix_up_power(adev); 179 + if (ret) { 180 + /* Skip the device, but continue the namespace scan. */ 181 + ret = 0; 182 + goto err_out; 174 183 } 175 184 176 185 adev->driver_data = pdata;
+20
drivers/acpi/device_pm.c
··· 290 290 return 0; 291 291 } 292 292 293 + /** 294 + * acpi_device_fix_up_power - Force device with missing _PSC into D0. 295 + * @device: Device object whose power state is to be fixed up. 296 + * 297 + * Devices without power resources and _PSC, but having _PS0 and _PS3 defined, 298 + * are assumed to be put into D0 by the BIOS. However, in some cases that may 299 + * not be the case and this function should be used then. 300 + */ 301 + int acpi_device_fix_up_power(struct acpi_device *device) 302 + { 303 + int ret = 0; 304 + 305 + if (!device->power.flags.power_resources 306 + && !device->power.flags.explicit_get 307 + && device->power.state == ACPI_STATE_D0) 308 + ret = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); 309 + 310 + return ret; 311 + } 312 + 293 313 int acpi_bus_update_power(acpi_handle handle, int *state_p) 294 314 { 295 315 struct acpi_device *device;
+1
include/acpi/acpi_bus.h
··· 382 382 int acpi_device_get_power(struct acpi_device *device, int *state); 383 383 int acpi_device_set_power(struct acpi_device *device, int state); 384 384 int acpi_bus_init_power(struct acpi_device *device); 385 + int acpi_device_fix_up_power(struct acpi_device *device); 385 386 int acpi_bus_update_power(acpi_handle handle, int *state_p); 386 387 bool acpi_bus_power_manageable(acpi_handle handle); 387 388