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.
Unified · Split
| @@ -164,15 +164,24 @@ static int acpi_lpss_create_device(struct acpi_device *adev, · 163 unmodified lines | ||
| 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 | } |
| 174 | 171 | } |
| 175 | 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; | |
| 183 | + } | |
| 184 | + | |
| 176 | 185 | adev->driver_data = pdata; |
| 177 | 186 | ret = acpi_create_platform_device(adev, id); |
| 178 | 187 | if (ret > 0) |
| @@ -290,6 +290,26 @@ int acpi_bus_init_power(struct acpi_device *device) · 289 unmodified lines | ||
| 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; |
| @@ -382,6 +382,7 @@ const char *acpi_power_state_string(int state); · 381 unmodified lines | ||
| 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 | |