From 36fcb4292473cb9c9ce7706d038bcf0eda5cabeb Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 6 Dec 2019 13:07:41 -0200 Subject: [PATCH 1/4] cpuidle: use first valid target residency as poll time Commit 259231a04561 ("cpuidle: add poll_limit_ns to cpuidle_device structure") changed, by mistake, the target residency from the first available sleep state to the last available sleep state (which should be longer). This might cause excessive polling. Fixes: 259231a04561 ("cpuidle: add poll_limit_ns to cpuidle_device structure") Signed-off-by: Marcelo Tosatti Cc: 5.4+ # 5.4+ Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0005be5ea2b45..15877b4311438 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -382,6 +382,7 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv, continue; limit_ns = (u64)drv->states[i].target_residency_ns; + break; } dev->poll_limit_ns = limit_ns; From b9ea0bae260f6aae546db224daa6ac1bd9d94b91 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 4 Dec 2019 02:54:27 +0100 Subject: [PATCH 2/4] ACPI: PM: Avoid attaching ACPI PM domain to certain devices Certain ACPI-enumerated devices represented as platform devices in Linux, like fans, require special low-level power management handling implemented by their drivers that is not in agreement with the ACPI PM domain behavior. That leads to problems with managing ACPI fans during system-wide suspend and resume. For this reason, make acpi_dev_pm_attach() skip the affected devices by adding a list of device IDs to avoid to it and putting the IDs of the affected devices into that list. Fixes: e5cc8ef31267 (ACPI / PM: Provide ACPI PM callback routines for subsystems) Reported-by: Zhang Rui Tested-by: Todd Brandt Cc: 3.10+ # 3.10+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 08bb9f2f2d231..5e4a8860a9c0c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1314,9 +1314,19 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off) */ int acpi_dev_pm_attach(struct device *dev, bool power_on) { + /* + * Skip devices whose ACPI companions match the device IDs below, + * because they require special power management handling incompatible + * with the generic ACPI PM domain. + */ + static const struct acpi_device_id special_pm_ids[] = { + {"PNP0C0B", }, /* Generic ACPI fan */ + {"INT3404", }, /* Fan */ + {} + }; struct acpi_device *adev = ACPI_COMPANION(dev); - if (!adev) + if (!adev || !acpi_match_device_ids(adev, special_pm_ids)) return 0; /* From b0142d66f4edb8578b7772d6d7ad731836b82ddb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 10 Dec 2019 12:48:35 +0100 Subject: [PATCH 3/4] cpuidle: Fix cpuidle_driver_state_disabled() It turns out that cpuidle_driver_state_disabled() can be called before registering the cpufreq driver on some platforms, which was not expected when it was introduced and which leads to a NULL pointer dereference when trying to walk the CPUs associated with the given cpuidle driver. Fix the problem by making cpuidle_driver_state_disabled() check if the driver's mask of CPUs associated with it is present and to set CPUIDLE_FLAG_UNUSABLE for the given idle state in the driver's states list if that is not the case to cause __cpuidle_register_device() to set CPUIDLE_STATE_DISABLED_BY_DRIVER for that state for all cpuidle devices registered by it later. Fixes: cbda56d5fefc ("cpuidle: Introduce cpuidle_driver_state_disabled() for driver quirks") Reported-by: Daniel Lezcano Tested-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index c76423aaef4d7..ce6a5f80fb838 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -403,6 +403,13 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, mutex_lock(&cpuidle_lock); + spin_lock(&cpuidle_driver_lock); + + if (!drv->cpumask) { + drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE; + goto unlock; + } + for_each_cpu(cpu, drv->cpumask) { struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); @@ -415,5 +422,8 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER; } +unlock: + spin_unlock(&cpuidle_driver_lock); + mutex_unlock(&cpuidle_lock); } From d4d8140176972fdb3f00bffc88e63af781de8d67 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 11 Dec 2019 11:30:50 +0100 Subject: [PATCH 4/4] cpuidle: Drop unnecessary type cast in cpuidle_poll_time() The data type of the target_residency_ns field in struct cpuidle_state is u64, so it does not need to be cast into u64. Get rid of the unnecessary type cast. Signed-off-by: Rafael J. Wysocki Acked-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 15877b4311438..33d19c8eb0272 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -381,7 +381,7 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv, if (dev->states_usage[i].disable) continue; - limit_ns = (u64)drv->states[i].target_residency_ns; + limit_ns = drv->states[i].target_residency_ns; break; }