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

pmdomain: Respect the CPU system wakeup QoS limit for s2idle

A CPU system wakeup QoS limit may have been requested by user space. To
avoid breaking this constraint when entering a low power state during
s2idle through genpd, let's extend the corresponding genpd governor for
CPUs. More precisely, during s2idle let the genpd governor select a
suitable domain idle state, by taking into account the QoS limit.

Reviewed-by: Dhruva Gole <d-gole@ti.com>
Reviewed-by: Kevin Hilman (TI) <khilman@baylibre.com>
Tested-by: Kevin Hilman (TI) <khilman@baylibre.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/20251125112650.329269-3-ulf.hansson@linaro.org
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Ulf Hansson and committed by
Rafael J. Wysocki
8e7de6dc a4e6512a

+36 -2
+8 -2
drivers/pmdomain/core.c
··· 1425 1425 return; 1426 1426 } 1427 1427 1428 - /* Choose the deepest state when suspending */ 1429 - genpd->state_idx = genpd->state_count - 1; 1428 + if (genpd->gov && genpd->gov->system_power_down_ok) { 1429 + if (!genpd->gov->system_power_down_ok(&genpd->domain)) 1430 + return; 1431 + } else { 1432 + /* Default to the deepest state. */ 1433 + genpd->state_idx = genpd->state_count - 1; 1434 + } 1435 + 1430 1436 if (_genpd_power_off(genpd, false)) { 1431 1437 genpd->states[genpd->state_idx].rejected++; 1432 1438 return;
+27
drivers/pmdomain/governor.c
··· 415 415 return false; 416 416 } 417 417 418 + static bool cpu_system_power_down_ok(struct dev_pm_domain *pd) 419 + { 420 + s64 constraint_ns = cpu_wakeup_latency_qos_limit() * NSEC_PER_USEC; 421 + struct generic_pm_domain *genpd = pd_to_genpd(pd); 422 + int state_idx = genpd->state_count - 1; 423 + 424 + if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) { 425 + genpd->state_idx = state_idx; 426 + return true; 427 + } 428 + 429 + /* Find the deepest state for the latency constraint. */ 430 + while (state_idx >= 0) { 431 + s64 latency_ns = genpd->states[state_idx].power_off_latency_ns + 432 + genpd->states[state_idx].power_on_latency_ns; 433 + 434 + if (latency_ns <= constraint_ns) { 435 + genpd->state_idx = state_idx; 436 + return true; 437 + } 438 + state_idx--; 439 + } 440 + 441 + return false; 442 + } 443 + 418 444 struct dev_power_governor pm_domain_cpu_gov = { 419 445 .suspend_ok = default_suspend_ok, 420 446 .power_down_ok = cpu_power_down_ok, 447 + .system_power_down_ok = cpu_system_power_down_ok, 421 448 }; 422 449 #endif 423 450
+1
include/linux/pm_domain.h
··· 153 153 }; 154 154 155 155 struct dev_power_governor { 156 + bool (*system_power_down_ok)(struct dev_pm_domain *domain); 156 157 bool (*power_down_ok)(struct dev_pm_domain *domain); 157 158 bool (*suspend_ok)(struct device *dev); 158 159 };