]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: fix station lookup failure when disconnecting from AP
authorBaochen Qiang <baochen.qiang@oss.qualcomm.com>
Thu, 29 Jan 2026 02:24:06 +0000 (10:24 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 26 Feb 2026 15:18:32 +0000 (07:18 -0800)
In ath12k_wmi_tlv_fw_stats_data_parse() and
ath12k_wmi_tlv_rssi_chain_parse(), the driver uses
ieee80211_find_sta_by_ifaddr() to look up the station associated with the
incoming firmware statistics. This works under normal conditions but fails
during AP disconnection, resulting in log messages like:

 wlan0: deauthenticating from xxxxxx by local choice (Reason: 3=DEAUTH_LEAVING)
 wlan0: moving STA xxxxxx to state 3
 wlan0: moving STA xxxxxx to state 2
 wlan0: moving STA xxxxxx to state 1
 ath12k_pci 0000:02:00.0: not found station bssid xxxxxx for vdev stat
 ath12k_pci 0000:02:00.0: not found station of bssid xxxxxx for rssi chain
 ath12k_pci 0000:02:00.0: failed to pull fw stats: -71
 ath12k_pci 0000:02:00.0: time out while waiting for get fw stats
 wlan0: Removed STA xxxxxx
 wlan0: Destroyed STA xxxxxx

The failure happens because the station has already been removed from
ieee80211_local::sta_hash by the time firmware statistics are requested
through drv_sta_statistics().

Switch the lookup to ath12k_link_sta_find_by_addr(), which searches the
driver's link station hash table that still has the station recorded
at that time.  This also implicitly fixes another issue: the current code
always uses deflink regardless of which link the statistics belong to,
which is incorrect in MLO scenarios. The new helper returns the correct
link station.

Additionally, raise the log level on lookup failures. With the updated
helper, such failures should no longer occur under normal conditions.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3

Fixes: 79e7b04b5388 ("wifi: ath12k: report station mode signal strength")
Fixes: 6af5bc381b36 ("wifi: ath12k: report station mode per-chain signal strength")
Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20260129-ath12k-fw-stats-fixes-v1-2-55d66064f4d5@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/wmi.c

index 7617fc3a2479cbe3dd64e0d95841e5afee80b627..404f031a3c8738d50a0010b2ee2eed894453db00 100644 (file)
@@ -8241,8 +8241,6 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
        struct ath12k_fw_stats *stats = parse->stats;
        struct ath12k *ar;
        struct ath12k_link_vif *arvif;
-       struct ieee80211_sta *sta;
-       struct ath12k_sta *ahsta;
        struct ath12k_link_sta *arsta;
        int i, ret = 0;
        const void *data = ptr;
@@ -8278,21 +8276,19 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
 
                arvif = ath12k_mac_get_arvif(ar, le32_to_cpu(src->vdev_id));
                if (arvif) {
-                       sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
-                                                          arvif->bssid,
-                                                          NULL);
-                       if (sta) {
-                               ahsta = ath12k_sta_to_ahsta(sta);
-                               arsta = &ahsta->deflink;
+                       spin_lock_bh(&ab->base_lock);
+                       arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+                       if (arsta) {
                                arsta->rssi_beacon = le32_to_cpu(src->beacon_snr);
                                ath12k_dbg(ab, ATH12K_DBG_WMI,
                                           "wmi stats vdev id %d snr %d\n",
                                           src->vdev_id, src->beacon_snr);
                        } else {
-                               ath12k_dbg(ab, ATH12K_DBG_WMI,
-                                          "not found station bssid %pM for vdev stat\n",
-                                          arvif->bssid);
+                               ath12k_warn(ab,
+                                           "not found link sta with bssid %pM for vdev stat\n",
+                                           arvif->bssid);
                        }
+                       spin_unlock_bh(&ab->base_lock);
                }
 
                data += sizeof(*src);
@@ -8363,8 +8359,6 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
        struct ath12k_fw_stats *stats = parse->stats;
        struct ath12k_link_vif *arvif;
        struct ath12k_link_sta *arsta;
-       struct ieee80211_sta *sta;
-       struct ath12k_sta *ahsta;
        struct ath12k *ar;
        int vdev_id;
        int j;
@@ -8400,19 +8394,15 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
                   "stats bssid %pM vif %p\n",
                   arvif->bssid, arvif->ahvif->vif);
 
-       sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
-                                          arvif->bssid,
-                                          NULL);
-       if (!sta) {
-               ath12k_dbg(ab, ATH12K_DBG_WMI,
-                          "not found station of bssid %pM for rssi chain\n",
-                          arvif->bssid);
+       guard(spinlock_bh)(&ab->base_lock);
+       arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+       if (!arsta) {
+               ath12k_warn(ab,
+                           "not found link sta with bssid %pM for rssi chain\n",
+                           arvif->bssid);
                return -EPROTO;
        }
 
-       ahsta = ath12k_sta_to_ahsta(sta);
-       arsta = &ahsta->deflink;
-
        BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
                     ARRAY_SIZE(stats_rssi->rssi_avg_beacon));