]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: Extend beacon miss handling for MLO non-AP STA
authorMaharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Tue, 12 Aug 2025 11:17:08 +0000 (16:47 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 18 Sep 2025 23:43:49 +0000 (16:43 -0700)
Currently, ath12k_mac_handle_beacon_miss() does not handle the beacon
miss for the MLO case.

In MLO scenarios, the host fails to process the beacon miss because the
vdev_id comparison in ath12k_mac_handle_beacon_miss_iter() does not match.
This mismatch occurs since arvif always points to ahvif->deflink, which may
not correspond to the actual vdev_id associated with the event.

Fix this by retrieving arvif from vdev_id instead of ahvif->deflink which
will work for both MLO and Non-MLO case.

Also refactor the ath12k_mac_handle_beacon_miss(), by passing arvif
directly instead of vdev_id and remove ath12k_mac_handle_beacon_miss_iter()
which is no longer needed.

ath12k_mac_handle_beacon_miss() is called from ath12k_roam_event() for WCN
chipsets and ath12k_peer_sta_kickout_event() for QCN chipsets.

So, refactor the ath12k_roam_event() to pass arvif instead vdev_id to the
ath12k_mac_handle_beacon_miss() function to align with the
ath12k_peer_sta_kickout_event() and change the rcu_read_lock() to
guard(rcu)() in the same function ath12k_roam_event().

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1

Co-developed-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
Signed-off-by: Aditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250812111708.3686-4-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/mac.h
drivers/net/wireless/ath/ath12k/wmi.c

index 222513cef1541a7cad140d34a916b3e26c410cd7..1d7b60aa5cb09a7f1d6b6ff4cca6181f4ddd2f76 100644 (file)
@@ -1822,22 +1822,16 @@ void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb)
                                                   skb);
 }
 
-static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
-                                              struct ieee80211_vif *vif)
+void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
+                                  struct ath12k_link_vif *arvif)
 {
-       u32 *vdev_id = data;
-       struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
-       struct ath12k_link_vif *arvif = &ahvif->deflink;
-       struct ieee80211_hw *hw;
-
-       if (!arvif->is_created || arvif->vdev_id != *vdev_id)
-               return;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
+       struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
 
-       if (!arvif->is_up)
+       if (!(arvif->is_created && arvif->is_up))
                return;
 
        ieee80211_beacon_loss(vif);
-       hw = ath12k_ar_to_hw(arvif->ar);
 
        /* Firmware doesn't report beacon loss events repeatedly. If AP probe
         * (done by mac80211) succeeds but beacons do not resume then it
@@ -1848,14 +1842,6 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
                                     ATH12K_CONNECTION_LOSS_HZ);
 }
 
-void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id)
-{
-       ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar),
-                                                  IEEE80211_IFACE_ITER_NORMAL,
-                                                  ath12k_mac_handle_beacon_miss_iter,
-                                                  &vdev_id);
-}
-
 static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
 {
        struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif,
index 18c79d4002cb5a5e4bffc354086f909a2becf930..c05af40bd7a20103deab30c0edb7cb54b739bec2 100644 (file)
@@ -168,7 +168,8 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
 int ath12k_mac_rfkill_config(struct ath12k *ar);
 int ath12k_mac_wait_tx_complete(struct ath12k *ar);
 void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb);
-void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id);
+void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
+                                  struct ath12k_link_vif *arvif);
 int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
                                 enum wmi_sta_keepalive_method method,
                                 u32 interval);
index 918d5b505179277867e397bdb64cf70eb6e961c7..ff6b3d4ea8208459f4e7bcf4475d386adce2d120 100644 (file)
@@ -7308,6 +7308,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
        struct ath12k_link_vif *arvif;
        struct ieee80211_sta *sta;
        struct ath12k_peer *peer;
+       unsigned int link_id;
        struct ath12k *ar;
 
        if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {
@@ -7336,11 +7337,23 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
 
        ar = arvif->ar;
 
-       sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
-                                          arg.mac_addr, NULL);
+       if (peer->mlo) {
+               sta = ieee80211_find_sta_by_link_addrs(ath12k_ar_to_hw(ar),
+                                                      arg.mac_addr,
+                                                      NULL, &link_id);
+               if (peer->link_id != link_id) {
+                       ath12k_warn(ab,
+                                   "Spurious quick kickout for MLO STA %pM with invalid link_id, peer: %d, sta: %d\n",
+                                   arg.mac_addr, peer->link_id, link_id);
+                       goto exit;
+               }
+       } else {
+               sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
+                                                  arg.mac_addr, NULL);
+       }
        if (!sta) {
-               ath12k_warn(ab, "Spurious quick kickout for STA %pM\n",
-                           arg.mac_addr);
+               ath12k_warn(ab, "Spurious quick kickout for %sSTA %pM\n",
+                           peer->mlo ? "MLO " : "", arg.mac_addr);
                goto exit;
        }
 
@@ -7351,7 +7364,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
        switch (arg.reason) {
        case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY:
                if (arvif->ahvif->vif->type == NL80211_IFTYPE_STATION) {
-                       ath12k_mac_handle_beacon_miss(ar, peer->vdev_id);
+                       ath12k_mac_handle_beacon_miss(ar, arvif);
                        break;
                }
                fallthrough;
@@ -7366,6 +7379,7 @@ exit:
 
 static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
 {
+       struct ath12k_link_vif *arvif;
        struct wmi_roam_event roam_ev = {};
        struct ath12k *ar;
        u32 vdev_id;
@@ -7384,21 +7398,22 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
                   "wmi roam event vdev %u reason %d rssi %d\n",
                   vdev_id, roam_reason, roam_ev.rssi);
 
-       rcu_read_lock();
-       ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
-       if (!ar) {
+       guard(rcu)();
+       arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_id);
+       if (!arvif) {
                ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id);
-               rcu_read_unlock();
                return;
        }
 
+       ar = arvif->ar;
+
        if (roam_reason >= WMI_ROAM_REASON_MAX)
                ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",
                            roam_reason, vdev_id);
 
        switch (roam_reason) {
        case WMI_ROAM_REASON_BEACON_MISS:
-               ath12k_mac_handle_beacon_miss(ar, vdev_id);
+               ath12k_mac_handle_beacon_miss(ar, arvif);
                break;
        case WMI_ROAM_REASON_BETTER_AP:
        case WMI_ROAM_REASON_LOW_RSSI:
@@ -7408,8 +7423,6 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
                            roam_reason, vdev_id);
                break;
        }
-
-       rcu_read_unlock();
 }
 
 static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)