From 94ccf2d4ef1a67bf751d6c8fbd98a948b659dcca Mon Sep 17 00:00:00 2001 From: deck Date: Fri, 7 Aug 2026 07:24:56 +0100 Subject: [PATCH] fix: restore radio power mode and calibration on resume xone_mt76_resume_radio() only cleared wake-on-wireless, switched channel, re-enabled beacons and set MAC RX/TX. It never returned the MCU to MT_RADIO_ON and never redid the RXDCOC/RC/temperature calibrations that init_radio() performs via calibrate_radio(). The MAC layer survives a system suspend, so after resume the dongle still beacons and a controller still associates - but the uncalibrated RF path cannot sustain the link. It collapses a few seconds later and the controller reassociates roughly every 10 seconds indefinitely. Only a full USB re-enumeration (which reruns init_radio) recovered it. Mirror init_radio() in the resume path: set_power_mode(MT_RADIO_ON), calibrate_radio(), then the existing channel switch plus the mandatory post-channel-change delay. This affects the .resume path only. The .reset_resume path already reinitialises via xone_dongle_init(). --- transport/mt76.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/transport/mt76.c b/transport/mt76.c index ecdbde4..c90ed75 100644 --- a/transport/mt76.c +++ b/transport/mt76.c @@ -1075,10 +1075,33 @@ int xone_mt76_resume_radio(struct xone_mt76 *mt) if (err) return err; + /* + * The RF front end does not survive a system suspend: the MCU leaves + * MT_RADIO_ON and the RXDCOC/RC/temperature calibrations applied by + * init_radio() are lost. The MAC layer does survive, so the dongle + * still beacons and a controller still associates - but an + * uncalibrated RF path cannot sustain the link, so it collapses a few + * seconds later and the controller reassociates every ~10s forever. + * + * Restore the radio power mode and redo the calibration, mirroring + * init_radio(). calibrate_radio() leaves MT_MAC_SYS_CTRL with RX and + * TX enabled; it is re-applied below after the channel switch. + */ + err = xone_mt76_set_power_mode(mt, MT_RADIO_ON); + if (err) + return err; + + err = xone_mt76_calibrate_radio(mt); + if (err) + return err; + err = xone_mt76_switch_channel(mt, mt->channel); if (err) return err; + /* mandatory delay after channel change */ + msleep(1000); + err = xone_mt76_set_pairing(mt, false); if (err) return err;