Tool/software:
I want to keep the WiFi connection alive, so I enabled WoWLAN. However, when I wake up the system using other sources, such as the RTC or the serial port, the WiFi interface does not resume properly.
Upon checking the kernel logs, I observed the following message:
[ 84.413671] wlcore: flushing tx buffer: 3 0 [ 84.453673] wlcore: flushing tx buffer: 3 0 [ 84.493674] wlcore: WARNING Unable to flush all TX buffers, timed out (timeout 500 ms [ 84.507403] wlcore: flushing remaining works [ 84.512096] CVTE::imx_thermal_suspend - temp=41277 [ 84.521364] PM: suspend devices took 1.130 seconds [ 84.528715] PM: pm_system_irq_wakeup: 43 triggered rtc alarm [ 84.541226] CVTE::imx_thermal_resume - temp=38197 [ 84.546341] wlcore: mac80211 resume wow=1 [ 84.552052] PM: dpm_run_callback(): wiphy_resume+0x0/0x218 [cfg80211] returns -1662942080 [ 84.560358] PM: Device phy0 failed to resume async: error -1662942080 [ 84.567606] PM: resume devices took 0.030 seconds [ 84.572329] OOM killer enabled. [ 84.575637] Restarting tasks ... done. [ 84.606268] Resume caused by IRQ 43, rtc alarm [ 84.614251] PM: suspend exit
The resume callback function returns an unexpectedly large value
[ 84.552052] PM: dpm_run_callback(): wiphy_resume+0x0/0x218 [cfg80211] returns -1662942080 [ 84.560358] PM: Device phy0 failed to resume async: error -1662942080
So I checked the source code and found that the variable ret
was not initialized, so the function returned an uninitialized value.
Here is the code after my edit:
static int __maybe_unused cc33xx_op_resume(struct ieee80211_hw *hw) { struct cc33xx *wl = hw->priv; struct cc33xx_vif *wlvif; unsigned long flags; bool run_irq_work = false, pending_recovery; int ret = 0;// -----------------------------------here cc33xx_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->keep_device_power); WARN_ON(!wl->keep_device_power); /* * re-enable irq_work enqueuing, and call irq_work directly if * there is a pending work. */ spin_lock_irqsave(&wl->wl_lock, flags); clear_bit(CC33XX_FLAG_SUSPENDED, &wl->flags); run_irq_work = test_and_clear_bit(CC33XX_FLAG_PENDING_WORK, &wl->flags); spin_unlock_irqrestore(&wl->wl_lock, flags); mutex_lock(&wl->mutex); /* test the recovery flag before calling any SDIO functions */ pending_recovery = test_bit(CC33XX_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); if (run_irq_work) { cc33xx_debug(DEBUG_MAC80211, "run postponed irq_work directly"); /* don't talk to the HW if recovery is pending */ if (!pending_recovery) { ret = wlcore_irq_locked(wl); if (ret) cc33xx_queue_recovery_work(wl); } wlcore_enable_interrupts(wl); } if (pending_recovery) { cc33xx_warning("queuing forgotten recovery on resume"); ieee80211_queue_work(wl->hw, &wl->recovery_work); goto out; } cc33xx_for_each_wlvif(wl, wlvif) { if (wlcore_is_p2p_mgmt(wlvif)) continue; cc33xx_configure_resume(wl, wlvif); } out: wl->keep_device_power = false; /* * Set a flag to re-init the watchdog on the first Tx after resume. * That way we avoid possible conditions where Tx-complete interrupts * fail to arrive and we perform a spurious recovery. */ set_bit(CC33XX_FLAG_REINIT_TX_WDOG, &wl->flags); mutex_unlock(&wl->mutex); return ret; }