From 108d3967eac4ba3a6e0f508d865a5f221b49079d Mon Sep 17 00:00:00 2001 Message-ID: <108d3967eac4ba3a6e0f508d865a5f221b49079d.1776940528.git.fritsche.markus@gmail.com> In-Reply-To: References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:37:45 +0200 Subject: [PATCH 4/7] bes2600: gate device LP-mode entry on successful per-VIF firmware handshake bes2600_pwr_enter_lp_mode() drives the transition to low-power for each associated STA VIF: it pushes wsm_set_pm(), waits up to 5 seconds on pm_enter_cmpl for the firmware to acknowledge, then unconditionally calls bes2600_pwr_device_enter_lp_mode() to drop the device end of the bus. Two bugs: 1. A failed wsm_set_pm() only logs an error, then still falls into wait_for_completion_timeout() on a completion the firmware will never post (the set-mode command never reached it). The loop therefore always blocks the full 5 s, logs a second error, and proceeds. 2. A genuine wait-timeout (firmware received the set-mode command but never posted the indication) also only logs a warning. The code then drops to bes2600_pwr_device_enter_lp_mode(), handing the device subsystem an inconsistent view of mac-layer state. On PineTab2 (BES2600WM + RK3566) the second bug is the recurring root-cause of the 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' message flooding dmesg every 5-10 s when the interface is associated and idle. Sending the device to LP in that state cascades into the SDIO TX path as the 'bes_sdio_memcpy_to_io_helper / sdio_tx_work' WARN splat. Fix: - Add a 'timeouts' counter; bump it on both failure paths. - Skip the wait_for_completion entirely when wsm_set_pm() failed (there is no completion to wait for). - Only call bes2600_pwr_device_enter_lp_mode() when every per-VIF handshake reached firmware-ACKed completion; otherwise return -ETIMEDOUT and leave the device in its current power state. Tested-on: PineTab2 running linux-pinetab2 6.19.10-danctnix1-1. Post-patch the handshake still fails on this particular firmware revision (separate root-cause investigation outside this patch), but the driver now returns -ETIMEDOUT cleanly instead of flooding dmesg and destabilising the SDIO path. Signed-off-by: Markus Fritsche --- bes2600/bes_pwr.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/bes2600/bes_pwr.c b/bes2600/bes_pwr.c index e7a1045..f62ae22 100644 --- a/bes2600/bes_pwr.c +++ b/bes2600/bes_pwr.c @@ -472,6 +472,7 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv) int i = 0; struct bes2600_vif *priv; int ret = 0; + int timeouts = 0; char ip_str[20]; unsigned long status = 0; @@ -528,22 +529,35 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv) if (ret) { atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); bes_err("%s, set operation mode fail\n", __func__); + timeouts++; + continue; } /* wait power save mode changed indication */ status = wait_for_completion_timeout(&hw_priv->bes_power.pm_enter_cmpl, 5 * HZ); atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); reinit_completion(&hw_priv->bes_power.pm_enter_cmpl); - if (!status) + if (!status) { bes_err("%s, wait pm ind timeout\n", __func__); + timeouts++; + } } else { bes_devel("skip enter lp mode\n"); } } } - /* set device low power configuration */ - bes2600_pwr_device_enter_lp_mode(hw_priv); + /* + * Enter the device-end of the LP transition only if every per-VIF + * mac80211 handshake reached firmware-ACKed completion. Doing the + * device-LP setup while any VIF is still pending leaves the driver + * in an inconsistent state that cascades into SDIO TX errors on + * the BES2600. + */ + if (timeouts == 0) + bes2600_pwr_device_enter_lp_mode(hw_priv); + else + ret = -ETIMEDOUT; return ret; } -- 2.53.0