* [PATCH v2 0/3] wifi: ath12k: fixes to improve MLO station stability
@ 2026-08-04 17:49 Jose Ignacio Tornos Martinez
2026-08-04 17:49 ` [PATCH v2 1/3] wifi: ath12k: fix MLO station firmware crash recovery Jose Ignacio Tornos Martinez
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-08-04 17:49 UTC (permalink / raw)
To: jjohnson
Cc: ath11k, ath12k, linux-wireless, linux-kernel,
Jose Ignacio Tornos Martinez
This series improves firmware crash recovery and connection stability
for MLO (Wi-Fi 7) stations on ath12k. Both work correctly for non-MLO
(Wi-Fi 6) stations, where the driver handles the full teardown and
reconnect cycle without issues and maintains stable connections. This
series brings MLO to the same level.
Without these fixes, a firmware crash during an active MLO connection
results in kernel warnings, NULL pointer dereferences, 20+ second
recovery delays, and periodic disconnections both after recovery and
during normal operation under heavy traffic.
Patches 1-2 fix firmware crash recovery:
Patch 1 moves the RECOVERY flag clear to reconfig_complete and adds
CRASH_FLUSH guards to prevent operations on dead firmware.
Patch 2 prevents scans during recovery to avoid NULL dereferences.
Patch 3 fixes MLO beacon miss handling:
Patch 3 skips connection_loss_work for MLO entirely, since its
cancellation mechanism is unreliable and the mac80211 probe
triggered by ieee80211_beacon_loss() is sufficient to detect
real AP unreachability, as done by other MLO-capable drivers
such as mt76 and rtw89.
Tested on WCN7850 with MLO (Wi-Fi 7).
Firmware crashes were observed to occur spontaneously during normal
MLO operation with intense traffic testing, though rarely.
The debugfs simulate_fw_crash interface was used for systematic testing
and reproduction during active MLO connections with traffic.
Note: I will have limited availability from mid-August to
mid-September. I will address any review feedback before then
or promptly after returning.
v2:
- Rebased on ath/main (requested by Jeff Johnson).
- Patch 1: rebase and address comments from Baochen Qiang:
- Remove CRASH_FLUSH guards from HAL srng source ring helpers
(ath12k_hal_srng_src_num_free, ath12k_hal_srng_src_get_next_entry,
ath12k_hal_srng_access_end). They were a layering violation — the
HAL should not know about device crash semantics. They were added
as a precautionary measure to abort as soon as possible, but
ath12k_wifi7_dp_tx() already has a CRASH_FLUSH check before any
HAL call.
- Fix radio[0] usage in change_vif_links, sta_state, and
peer_mlo_link_peers_delete to use per-radio ab.
- Patch 2: fix radio[0] usage
- Drop v1 patch 3 (fix MLO dp_peer ID desync with firmware):
already fixed by Baochen Qiang's ML peer ID series in ath.git
- Drop v1 patch 4 (fix MLO beacon handling using per-link
addressing): patch 3 (v1 patch 5) skips connection_loss_work for
MLO entirely, making the per-link beacon matching and cancellation
in v1 patch 4 unreachable (Baochen Qiang comment).
- No modification for v1 patch 5, now v2 patch 3.
v1: https://lore.kernel.org/all/20260727162748.963275-1-jtornosm@redhat.com/
Jose Ignacio Tornos Martinez (3):
wifi: ath12k: fix MLO station firmware crash recovery
wifi: ath12k: prevent scan during firmware recovery
wifi: ath12k: skip connection_loss_work for MLO beacon miss
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] wifi: ath12k: fix MLO station firmware crash recovery
2026-08-04 17:49 [PATCH v2 0/3] wifi: ath12k: fixes to improve MLO station stability Jose Ignacio Tornos Martinez
@ 2026-08-04 17:49 ` Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 2/3] wifi: ath12k: prevent scan during firmware recovery Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 3/3] wifi: ath12k: skip connection_loss_work for MLO beacon miss Jose Ignacio Tornos Martinez
2 siblings, 0 replies; 4+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-08-04 17:49 UTC (permalink / raw)
To: jjohnson
Cc: ath11k, ath12k, linux-wireless, linux-kernel,
Jose Ignacio Tornos Martinez
ATH12K_FLAG_RECOVERY is cleared too early in
ath12k_core_reconfigure_on_crash(), before mac80211 runs
ieee80211_reconfig(). By the time mac80211 calls back into the driver
(sta_state, change_vif_links, set_key), the RECOVERY flag is already false,
so the driver treats recovery callbacks as normal operations.
This causes several problems during MLO recovery:
- ath12k_mac_op_sta_state() tries to activate MLO links during the
AUTH->ASSOC transition, calling ieee80211_set_active_links()
recursively, which triggers a WARNING at net/mac80211/link.c.
- ath12k_mac_op_change_vif_links() processes link removal during
reconfig, causing inconsistent state.
- ath12k_mac_set_key() fails with "cannot install key for non-existent
peer" because peers do not exist yet during reconfig. Keys will be
re-established during normal reconnection after
ieee80211_hw_restart_disconnect() triggers a fresh association.
- ath12k_mac_flush() waits for pending TX to complete, but after a
firmware crash the TX will never complete, causing a 20 second timeout.
- ath12k_mac_station_remove() calls ath12k_bss_disassoc() and
ath12k_mac_vdev_stop() which send WMI commands to dead firmware,
causing timeouts that delay recovery.
- ath12k_clear_peer_keys() tries to look up and clear peer keys, but
peers are already gone after firmware crash.
- ath12k_dp_rx_ampdu_stop() dereferences per-link station state that
may not be valid during crash teardown.
- ath12k_peer_mlo_link_peers_delete() sends WMI peer delete commands
for each MLO link peer. With dead firmware these time out and can
trigger cascading resets.
These issues were observed during sporadic firmware crashes in MLO
operation. To allow systematic testing and reproduction, the debugfs
simulate_fw_crash interface was used to trigger controlled firmware
crashes during active MLO connections with traffic.
Fix by moving clear_bit(ATH12K_FLAG_RECOVERY) from
ath12k_core_reconfigure_on_crash() to ath12k_mac_op_reconfig_complete(),
so the flag stays set through the entire mac80211 reconfig phase. Add
ATH12K_FLAG_RECOVERY checks in change_vif_links, set_key, and sta_state
to skip operations that are invalid during recovery. Add
ATH12K_FLAG_CRASH_FLUSH checks in mac_flush, station_remove,
clear_peer_keys, dp_rx_ampdu_stop, and peer_mlo_link_peers_delete to
return immediately when the firmware is dead.
Tested on WCN7850 with MLO (Wi-Fi 7).
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v2: Rebase and address comments from Baochen Qiang:
- Remove CRASH_FLUSH guards from HAL srng source ring helpers
(ath12k_hal_srng_src_num_free, ath12k_hal_srng_src_get_next_entry,
ath12k_hal_srng_access_end). They were a layering violation — the
HAL should not know about device crash semantics. They were added
as a precautionary measure to abort as soon as possible, but
ath12k_wifi7_dp_tx() already has a CRASH_FLUSH check before any
HAL call.
- Fix radio[0] usage in change_vif_links, sta_state, and
peer_mlo_link_peers_delete to use per-radio ab.
v1: https://lore.kernel.org/all/20260727162748.963275-2-jtornosm@redhat.com/
drivers/net/wireless/ath/ath12k/core.c | 2 --
drivers/net/wireless/ath/ath12k/dp_rx.c | 3 +++
drivers/net/wireless/ath/ath12k/mac.c | 27 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/peer.c | 6 ++++++
4 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 262a2045309b..5c0ee74808cd 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1391,8 +1391,6 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
if (ret)
goto err_hal_srng_deinit;
- clear_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
-
return 0;
err_hal_srng_deinit:
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 8fa0e90b4531..473855ded8a7 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -751,6 +751,9 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+ if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+ return 0;
+
arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
ahsta->link[link_id]);
if (!arsta)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 99bf5cf79d10..7b7110ca6428 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4341,12 +4341,22 @@ ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw,
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
unsigned long to_remove = old_links & ~new_links;
unsigned long to_add = ~old_links & new_links;
+ unsigned long existing = old_links;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k_link_vif *arvif;
u8 link_id;
lockdep_assert_wiphy(hw->wiphy);
+ if (old_links) {
+ for_each_set_bit(link_id, &existing, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ if (arvif && arvif->ar &&
+ test_bit(ATH12K_FLAG_RECOVERY, &arvif->ar->ab->dev_flags))
+ return -EINVAL;
+ }
+ }
+
ath12k_generic_dbg(ATH12K_DBG_MAC,
"mac vif link changed for MLD %pM old_links 0x%x new_links 0x%x\n",
vif->addr, old_links, new_links);
@@ -6025,6 +6035,9 @@ static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif,
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+ if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+ return 0;
+
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id, addr);
if (!peer || !peer->dp_peer) {
@@ -6100,6 +6113,8 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
spin_unlock_bh(&dp->dp_lock);
if (cmd == SET_KEY) {
+ if (test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags))
+ return 0;
ath12k_warn(ab, "cannot install key for non-existent peer %pM\n",
peer_addr);
return -EOPNOTSUPP;
@@ -7100,7 +7115,8 @@ static int ath12k_mac_station_remove(struct ath12k *ar,
wiphy_work_cancel(ar->ah->hw->wiphy, &arsta->update_wk);
- if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
+ !test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) {
ath12k_bss_disassoc(ar, arvif);
ret = ath12k_mac_vdev_stop(arvif);
if (ret)
@@ -7861,6 +7877,10 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
* MLO case. Other cases would be handled in the future.
*/
ab = ah->radio[0].ab;
+ if (test_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags)) {
+ ret = 0;
+ goto exit;
+ }
if (ab->ag->num_devices == 1) {
ret = ath12k_mac_select_links(ab, vif, hw, &selected_links);
if (ret) {
@@ -12661,6 +12681,9 @@ static int ath12k_mac_flush(struct ath12k *ar)
long time_left;
int ret = 0;
+ if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+ return -ESHUTDOWN;
+
time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
(atomic_read(&ar->dp.num_tx_pending) == 0),
ATH12K_FLUSH_TIMEOUT);
@@ -13559,6 +13582,8 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
for_each_ar(ah, ar, i) {
ab = ar->ab;
+ clear_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
+
ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
ar->pdev->pdev_id);
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 80edebf0e364..d64e62192cd7 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -376,12 +376,18 @@ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_st
unsigned long links;
struct ath12k *ar;
u8 link_id;
+ int i;
lockdep_assert_wiphy(ah->hw->wiphy);
if (!sta->mlo)
return -EINVAL;
+ for_each_ar(ah, ar, i) {
+ if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+ return 0;
+ }
+
struct ath12k_peer_delete_wait *waits __free(kfree) =
kzalloc_objs(*waits, IEEE80211_MLD_MAX_NUM_LINKS);
if (!waits)
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] wifi: ath12k: prevent scan during firmware recovery
2026-08-04 17:49 [PATCH v2 0/3] wifi: ath12k: fixes to improve MLO station stability Jose Ignacio Tornos Martinez
2026-08-04 17:49 ` [PATCH v2 1/3] wifi: ath12k: fix MLO station firmware crash recovery Jose Ignacio Tornos Martinez
@ 2026-08-04 17:50 ` Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 3/3] wifi: ath12k: skip connection_loss_work for MLO beacon miss Jose Ignacio Tornos Martinez
2 siblings, 0 replies; 4+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-08-04 17:50 UTC (permalink / raw)
To: jjohnson
Cc: ath11k, ath12k, linux-wireless, linux-kernel,
Jose Ignacio Tornos Martinez
When firmware crashes while wpa_supplicant has an active connection,
wpa_supplicant may immediately attempt a scan via nl80211 while the
firmware is still powering on through MHI. ath12k_mac_op_hw_scan()
proceeds without checking the recovery state, accessing partially
initialized radio structures which leads to a NULL pointer dereference:
BUG: unable to handle page fault for address: 0000000000001508
RIP: ath12k_mac_op_hw_scan+0x148/0x2b0 [ath12k]
Call Trace:
drv_hw_scan+0x88/0x140 [mac80211]
__ieee80211_start_scan+0x2bc/0x6b0 [mac80211]
nl80211_trigger_scan+0x54a/0x9f0 [cfg80211]
Fix by checking ATH12K_FLAG_RECOVERY at the start of
ath12k_mac_op_hw_scan() and returning -EBUSY. mac80211 will retry the
scan after the recovery completes.
Tested on WCN7850 with MLO (Wi-Fi 7).
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v2: Fix radio[0] usage
v1: https://lore.kernel.org/all/20260727162748.963275-3-jtornosm@redhat.com/
drivers/net/wireless/ath/ath12k/mac.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 7b7110ca6428..a57c2e91be84 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5783,6 +5783,11 @@ int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
lockdep_assert_wiphy(hw->wiphy);
+ for_each_ar(ah, ar, i) {
+ if (test_bit(ATH12K_FLAG_RECOVERY, &ar->ab->dev_flags))
+ return -EBUSY;
+ }
+
chan_list = kzalloc_objs(*chan_list, hw_req->req.n_channels);
if (!chan_list)
return -ENOMEM;
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] wifi: ath12k: skip connection_loss_work for MLO beacon miss
2026-08-04 17:49 [PATCH v2 0/3] wifi: ath12k: fixes to improve MLO station stability Jose Ignacio Tornos Martinez
2026-08-04 17:49 ` [PATCH v2 1/3] wifi: ath12k: fix MLO station firmware crash recovery Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 2/3] wifi: ath12k: prevent scan during firmware recovery Jose Ignacio Tornos Martinez
@ 2026-08-04 17:50 ` Jose Ignacio Tornos Martinez
2 siblings, 0 replies; 4+ messages in thread
From: Jose Ignacio Tornos Martinez @ 2026-08-04 17:50 UTC (permalink / raw)
To: jjohnson
Cc: ath11k, ath12k, linux-wireless, linux-kernel,
Jose Ignacio Tornos Martinez
When firmware reports a beacon miss, ath12k queues connection_loss_work
as a 3-second backup timer that forces a full VIF disconnect via
ieee80211_connection_loss(). This work can only be cancelled when a
beacon frame arrives through WMI in ath12k_mac_handle_beacon_iter().
In MLO, this mechanism causes periodic spurious disconnections because
the firmware does not reliably forward beacon frames to the host via
WMI, making the cancellation path ineffective. The result is a full
VIF disconnect every ~16 seconds during normal MLO operation, easily
reproducible under heavy traffic.
Skip queueing connection_loss_work for MLO VIFs. The mac80211 AP probe
triggered by ieee80211_beacon_loss() is sufficient to detect real AP
unreachability. Other MLO-capable drivers such as mt76 and rtw89
similarly rely on ieee80211_beacon_loss() without adding a backup
disconnect timer.
Tested on WCN7850 with MLO (Wi-Fi 7).
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
v2: No modification
v1: https://lore.kernel.org/all/20260727162748.963275-6-jtornosm@redhat.com/
drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index af09153ad9d9..dfd69822c5ce 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2008,9 +2008,16 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
* (done by mac80211) succeeds but beacons do not resume then it
* doesn't make sense to continue operation. Queue connection loss work
* which can be cancelled when beacon is received.
+ *
+ * Skip for MLO because connection_loss_work disconnects the entire
+ * VIF based on a single link's beacon miss, and its cancellation
+ * mechanism (beacon reception via WMI) is unreliable. The mac80211
+ * probe triggered by ieee80211_beacon_loss() above is sufficient
+ * to detect real AP unreachability.
*/
- ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
- ATH12K_CONNECTION_LOSS_HZ);
+ if (!ieee80211_vif_is_mld(vif))
+ ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
+ ATH12K_CONNECTION_LOSS_HZ);
}
static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-04 17:50 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 17:49 [PATCH v2 0/3] wifi: ath12k: fixes to improve MLO station stability Jose Ignacio Tornos Martinez
2026-08-04 17:49 ` [PATCH v2 1/3] wifi: ath12k: fix MLO station firmware crash recovery Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 2/3] wifi: ath12k: prevent scan during firmware recovery Jose Ignacio Tornos Martinez
2026-08-04 17:50 ` [PATCH v2 3/3] wifi: ath12k: skip connection_loss_work for MLO beacon miss Jose Ignacio Tornos Martinez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox