From d31609d8dd8e044ecf0bc3f0c2c9aab788a7e696 Mon Sep 17 00:00:00 2001 From: Felipe Moura Date: Sat, 19 Sep 2026 17:56:39 -0300 Subject: [PATCH] esp32s3/esp32s3_idle.c: unwedge the PM state machine after the first wakeup up_idlepm() put the domain back in PM_NORMAL with pm_changestate() but left its local oldstate holding whatever it was before sleeping, usually PM_STANDBY. The pm_checkstate() below then returned PM_STANDBY again, the "newstate != oldstate" test compared PM_STANDBY against a stale PM_STANDBY, and the whole block was skipped -- including the esp_pmstandby() call that is the only thing in here that ever sleeps. So after the very first wakeup the board reported PM_NORMAL essentially forever, and light-slept only when something else happened to perturb oldstate, such as an application taking and releasing a PM_IDLE wakelock around a transmission window. Measured on the esp32s3-xiao collar before this fix: 4.1 s of actual light sleep in 2 h of near-total idleness, a 1780:1 awake-to-asleep ratio. After it: ~13.5% of wall time asleep, thousands of sleeps, no storms. The dead "newstate = PM_NORMAL" assignment that used to sit here was presumably meant to be this; it is overwritten by pm_checkstate() a few lines below and never had any effect. Note that fixing this is what exposed two further bugs that had been dormant behind a board that never slept: the systimer double-count in esp_pmstandby(), and I2C transfers being cut in half by sleep. Both are fixed in their own commits. Signed-off-by: Felipe Moura Assisted-by: Claude:claude-opus-5 --- arch/xtensa/src/esp32s3/esp32s3_idle.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/src/esp32s3/esp32s3_idle.c b/arch/xtensa/src/esp32s3/esp32s3_idle.c index 7b4da12a3e3..e441a7eade5 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_idle.c +++ b/arch/xtensa/src/esp32s3/esp32s3_idle.c @@ -104,7 +104,12 @@ static void up_idlepm(void) /* Release the stay above: it only forces this one state change. */ pm_relax(PM_IDLE_DOMAIN, PM_NORMAL); - newstate = PM_NORMAL; + + /* Without this, oldstate goes stale after the first wakeup and the + * state machine wedges in PM_NORMAL forever -- see commit message. + */ + + oldstate = PM_NORMAL; } /* Decide, which power saving level can be obtained */