[PATCH 2/2] pmdomain: core: Initialize state_idx to deepest state for OFF domains

Maulik Shah <[email protected]>
Newsgroups org.kernel.vger.linux-pm,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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

Fixes: e7d90cfac551 ("PM: domains: Prevent power off for parent unless child is in deepest state")
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Maulik Shah <[email protected]>
---
 drivers/pmdomain/core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 842c4169e290..5d96d9eabc1f 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -2409,6 +2409,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	atomic_set(&genpd->sd_count, 0);
 	genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
+	if (is_off && genpd->state_count)
+		genpd->state_idx = genpd->state_count - 1;
 	genpd_set_stay_on(genpd, is_off);
 	genpd->sync_state = GENPD_SYNC_STATE_OFF;
 	genpd->device_count = 0;

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.