From b9370dceabb7841c5e65ce4ee4405b9db5231fc4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 14 May 2021 21:08:51 +0200 Subject: ACPI: PM / fan: Put fan device IDs into separate header file The ACPI fan device IDs are shared between the fan driver and the device power management code. The former is modular, so it needs to include the table of device IDs for module autoloading and the latter needs that list to avoid attaching the generic ACPI PM domain to fan devices (which doesn't make sense) possibly before the fan driver module is loaded. Unfortunately, that requires the list of fan device IDs to be updated in two places which is prone to mistakes, so put it into a symbol definition in a separate header file so there is only one copy of it in case it needs to be updated again in the future. Fixes: b9ea0bae260f ("ACPI: PM: Avoid attaching ACPI PM domain to certain devices") Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/acpi/device_pm.c') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index d260bc1f3e6e..9d2d3b9bb8b5 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -20,6 +20,7 @@ #include #include +#include "fan.h" #include "internal.h" /** @@ -1310,10 +1311,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) * with the generic ACPI PM domain. */ static const struct acpi_device_id special_pm_ids[] = { - {"PNP0C0B", }, /* Generic ACPI fan */ - {"INT3404", }, /* Fan */ - {"INTC1044", }, /* Fan for Tiger Lake generation */ - {"INTC1048", }, /* Fan for Alder Lake generation */ + ACPI_FAN_DEVICE_IDS, {} }; struct acpi_device *adev = ACPI_COMPANION(dev); -- cgit v1.2.3 From f7599be2bb7694d94b65a57a74aba75f2c101c28 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 22 Jun 2021 14:39:39 -0700 Subject: ACPI: PM: postpone bringing devices to D0 unless we need them Currently ACPI power domain brings devices into D0 state in the "resume early" phase. Normally this does not cause any issues, as powering up happens quickly. However there are peripherals that have certain timing requirements for powering on, for example some models of Elan touchscreens need 300msec after powering up/releasing reset line before they can accept commands from the host. Such devices will dominate the time spent in early resume phase and cause increase in overall resume time as we wait for early resume to complete before we can proceed to the normal resume stage. There are ways for a driver to indicate that it can tolerate device being in the low power mode and that it knows how to power the device back up when resuming, bit that requires changes to individual drivers that may not really care about details of ACPI controlled power management. This change attempts to solve this issue at ACPI power domain level, by postponing powering up device until we get to the normal resume stage, unless there is early resume handler defined for the device, or device does not declare any resume handlers, in which case we continue powering up such devices early. This allows us to shave off several hundred milliseconds of resume time on affected systems. Signed-off-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers/acpi/device_pm.c') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 9d2d3b9bb8b5..675a69de516f 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1134,19 +1134,48 @@ static int acpi_subsys_resume_noirq(struct device *dev) * * Use ACPI to put the given device into the full-power state and carry out the * generic early resume procedure for it during system transition into the - * working state. + * working state, but only do that if device either defines early resume + * handler, or does not define power operations at all. Otherwise powering up + * of the device is postponed to the normal resume phase. */ static int acpi_subsys_resume_early(struct device *dev) { + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int ret; if (dev_pm_skip_resume(dev)) return 0; + if (pm && !pm->resume_early) { + dev_dbg(dev, "postponing D0 transition to normal resume stage\n"); + return 0; + } + ret = acpi_dev_resume(dev); return ret ? ret : pm_generic_resume_early(dev); } +/** + * acpi_subsys_resume - Resume device using ACPI. + * @dev: Device to Resume. + * + * Use ACPI to put the given device into the full-power state if it has not been + * powered up during early resume phase, and carry out the generic resume + * procedure for it during system transition into the working state. + */ +static int acpi_subsys_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret = 0; + + if (!dev_pm_skip_resume(dev) && pm && !pm->resume_early) { + dev_dbg(dev, "executing postponed D0 transition\n"); + ret = acpi_dev_resume(dev); + } + + return ret ? ret : pm_generic_resume(dev); +} + /** * acpi_subsys_freeze - Run the device driver's freeze callback. * @dev: Device to handle. @@ -1240,6 +1269,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { .prepare = acpi_subsys_prepare, .complete = acpi_subsys_complete, .suspend = acpi_subsys_suspend, + .resume = acpi_subsys_resume, .suspend_late = acpi_subsys_suspend_late, .suspend_noirq = acpi_subsys_suspend_noirq, .resume_noirq = acpi_subsys_resume_noirq, -- cgit v1.2.3