cpuidle/pmdomain: Correctly track state of excluded CPU clusters - #1671
cpuidle/pmdomain: Correctly track state of excluded CPU clusters#1671maulik-k-shah wants to merge 2 commits into
Conversation
psci_pd_init() always calls pm_genpd_init() with is_off=false, so a CPU-cluster pmdomain is marked ON at creation regardless of whether any CPU has actually powered it on yet. The pmdomain's own status tracking (and the power-on notifier chain fired from _genpd_power_on()) is therefore wrong from the outset for OSI mode. A concrete example: hamoa has 3 CPU clusters, each with 4 CPUs, under a single parent system-level pmdomain. Passing "maxcpus=4" on the kernel command line limits boot to the first 4 CPUs, so only cluster0 is ever actually powered on. Without this fix, cluster1 and cluster2 are still marked ON at creation regardless, since is_off is always false. Because none of their CPUs ever come online, neither dt_idle_attach_cpu() nor psci_idle_cpuhp_up() ever fires for them, so nothing subsequently drives those two domains to OFF - they stay marked ON for as long as the system runs. When cluster0's CPUs go idle and its pmdomain is powered off, the parent system-level pmdomain still sees cluster1 and cluster2 as ON and therefore never selects a system-level idle state, even though no CPU in those two clusters ever executed. Starting the domain OFF is safe under OSI: - For CPUs already online by the time this driver probes, dt_idle_attach_cpu() explicitly checks cpu_online() and calls pm_runtime_get_sync() on the CPU's attach device, which resolves to this same pmdomain and drives a real power-on immediately. This runs from psci_cpuidle_probe(), a device_initcall, strictly after psci_idle_init_domains()'s core_initcall has already created and marked off every pmdomain, so there is no window where an online CPU's domain is left off with nothing left to turn it on. - For CPUs that come online later, psci_idle_cpuhp_up() (registered via cpuhp_setup_state_nocalls(), which never invokes the callback for already-online CPUs at registration time) powers the domain on through the normal cpuhp AP_ONLINE path. Gate this on use_osi rather than applying it unconditionally: in non-OSI mode psci_pd_init() sets GENPD_FLAG_ALWAYS_ON, which independently blocks genpd_power_off() regardless of is_off, so the domain can never really be off there and marking it is_off=true would be misleading noise with no effect. Link: https://lore.kernel.org/linux-arm-msm/20260811-domain_off_ss3-v1-0-6a0a0fc023f5@oss.qualcomm.com/T/#m2ca7c431b37ac9431179d8f21c3134a1823a00c7 Fixes: a65a397 ("cpuidle: psci: Add support for PM domains by using genpd") Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com>
…FF domains
pm_genpd_init() sets genpd->status from is_off but never touches state_idx,
which stays at its kzalloc'd value of 0 (dt_idle_pd_alloc()) regardless of
is_off. A domain that starts OFF without ever having gone through an actual
power-off sequence is therefore left looking like it's parked at its
shallowest idle state (state_idx=0) instead of its deepest one, even though
it is fully powered down.
This is visible on hamoa, where cluster0/1/2 each expose two idle states,
CL4 (state_idx=0) and CL5 (state_idx=1, the deepest). When CPU-cluster
genpds are initialised directly into GENPD_STATE_OFF under OSI mode
("cpuidle: psci: Start CPU-cluster pmdomain OFF when OSI is used"),
clusters whose CPUs are excluded at boot (e.g. maxcpus=4, leaving clusters
1 and 2 untouched) never go through a power-off path, so their state_idx
remains 0 instead of the deepest 1. debugfs reports this as "off-0",
meaning the domain is off but parked at idle-state 0 (CL4) rather than
"off-1", idle-state 1 (CL5):
genpd_power_off() and genpd_sync_power_off() both gate parent power-off on
every child being at its deepest state index:
if (child->state_idx < child->state_count - 1)
return;
so the parent's check treats these fully-off children as "not yet at
deepest state" and refuses to power off, blocking the deepest system-level
low-power mode (SS3) from ever being entered.
Without this change:
$ cat .../power-domain-cpu-cluster1/current_state
off-0
$ cat /sys/kernel/debug/qcom_stats/apss
Count: 0
Last Entered At: 0
Last Exited At: 0
Accumulated Duration: 0
Fix this at the source: when a domain is initialised OFF, set its state_idx
to its deepest state (state_count - 1) instead of leaving it at 0. This
makes genpd's reported state consistent with reality for every is_off=true
caller of pm_genpd_init(), not just the PSCI CPU-cluster case, and requires
no special-casing in the parent power-off checks.
With this change, the domain correctly reports its deepest state and SS3
is entered normally:
$ cat .../power-domain-cpu-cluster1/current_state
off-1
$ cat /sys/kernel/debug/qcom_stats/apss
Count: 218
Last Entered At: 726792712
Last Exited At: 726950687
Accumulated Duration: 199888773
Link: https://lore.kernel.org/linux-arm-msm/20260811-domain_off_ss3-v1-0-6a0a0fc023f5@oss.qualcomm.com/T/#m6c0e0622ef5514fba8ec7a7b41b69e5e90e21fb0
Fixes: e7d90cf ("PM: domains: Prevent power off for parent unless child is in deepest state")
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com>
PR #1671 — validate-patchPR: #1671
Final Summary
|
PR #1671 — checker-log-analyzerPR: #1671
Detailed report: Full report
|
Merge https://lore.kernel.org/linux-arm-msm/20260811-domain_off_ss3-v1-0-6a0a0fc023f5@oss.qualcomm.com/T/#mfdbefe6efdfc0596ba81f194ef5102d6a0f7348c
This allows pmdomain to start with OFF state instead of ON state helping on monaco single core boot up.
CRs-Fixed: 4428933