]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Skip DP peer creation for scan vdev
authorRipan Deuri <quic_rdeuri@quicinc.com>
Sun, 7 Dec 2025 07:27:17 +0000 (12:57 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Tue, 9 Dec 2025 18:18:44 +0000 (10:18 -0800)
Consider a multi-link AP configuration:

    MLD vif (MAC addr: aa:bb)
        |-- 2.4 GHz link (BSSID: aa:bb)
        |-- 5 GHz link   (BSSID: cc:dd)

For AP vdevs, ath12k creates a DP peer using the arvif's BSSID and stores
it in dp_hw->dp_peers_list. During scan operations, the driver assigns an
arvif to the scan vdev and uses the vif's MAC address as its BSSID. In
the above scenario, the scan vdev MAC address (aa:bb) matches the BSSID
of the 2.4 GHz AP link, causing a duplicate entry in dp_hw->dp_peers_list
and leading to scan vdev creation failure.

Failure in vif bringup sequence:
1. Create AP vdev for 2.4 GHz link:
   - Assign arvif with BSSID = aa:bb and link_id = 0.
   - Create DP peer with address aa:bb and add to dp_hw->dp_peers_list.

2. Create scan vdev for 5 GHz link:
   - Assign arvif with BSSID = aa:bb (same as vif MAC address) and
     link_id = 15.
   - Attempt to create another DP peer with address aa:bb.
   - Operation fails because aa:bb already exists in dp_hw->dp_peers_list,
     resulting in duplicate entry conflict.

3. Delete scan vdev for 5 GHz link.
4. Create AP vdev for 5 GHz link.

Since DP peer is not needed for scan operations, identify scan vdev using
arvif->link_id >= IEEE80211_MLD_MAX_NUM_LINKS and skip DP peer creation
and deletion.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1

Signed-off-by: Ripan Deuri <quic_rdeuri@quicinc.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20251207072717.95542-1-quic_rdeuri@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/peer.c

index 3649f58fef8488397186cbca6a52d1c84e6092f5..42e75037692676ff190e19ff8c6e572c53eb5130 100644 (file)
@@ -1229,7 +1229,8 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
 
        /* Delete all the self dp_peers on asserted radio */
        list_for_each_entry_safe_reverse(arvif, tmp_vif, &ar->arvifs, list) {
-               if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               if ((arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) &&
+                   (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS)) {
                        ath12k_dp_peer_delete(dp_hw, arvif->bssid, NULL);
                        arvif->num_stations = 0;
                }
@@ -4031,7 +4032,8 @@ static void ath12k_mac_remove_link_interface(struct ieee80211_hw *hw,
                        ath12k_warn(ar->ab, "failed to submit AP self-peer removal on vdev %d link id %d: %d",
                                    arvif->vdev_id, arvif->link_id, ret);
 
-               ath12k_dp_peer_delete(&ah->dp_hw, arvif->bssid, NULL);
+               if (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS)
+                       ath12k_dp_peer_delete(&ah->dp_hw, arvif->bssid, NULL);
        }
        ath12k_mac_vdev_delete(ar, arvif);
 }
@@ -9720,6 +9722,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
        u8 link_id;
        struct ath12k_dp_link_vif *dp_link_vif = NULL;
        struct ath12k_dp_peer_create_params params = {};
+       bool dp_peer_created = false;
 
        lockdep_assert_wiphy(hw->wiphy);
 
@@ -9805,11 +9808,14 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
        case WMI_VDEV_TYPE_AP:
                params.ucast_ra_only = true;
 
-               ret = ath12k_dp_peer_create(&ah->dp_hw, arvif->bssid, &params);
-               if (ret) {
-                       ath12k_warn(ab, "failed to vdev %d create dp_peer for AP: %d\n",
-                                   arvif->vdev_id, ret);
-                       goto err_vdev_del;
+               if (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
+                       ret = ath12k_dp_peer_create(&ah->dp_hw, arvif->bssid, &params);
+                       if (ret) {
+                               ath12k_warn(ab, "failed to vdev %d create dp_peer for AP: %d\n",
+                                           arvif->vdev_id, ret);
+                               goto err_vdev_del;
+                       }
+                       dp_peer_created = true;
                }
 
                peer_param.vdev_id = arvif->vdev_id;
@@ -9925,7 +9931,7 @@ err_peer_del:
        }
 
 err_dp_peer_del:
-       if (ahvif->vdev_type == WMI_VDEV_TYPE_AP)
+       if (dp_peer_created)
                ath12k_dp_peer_delete(&ah->dp_hw, arvif->bssid, NULL);
 
 err_vdev_del:
index c2fb5bbd6ceaed893f3192e65a1b9625b666d8d0..5f3bd3b9a3e97497b7ed91f691f54823ad2920b6 100644 (file)
@@ -241,11 +241,13 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
 
        spin_unlock_bh(&dp->dp_lock);
 
-       ret = ath12k_dp_link_peer_assign(ath12k_ab_to_dp(ar->ab),
-                                        &(ath12k_ar_to_ah(ar)->dp_hw),
-                                        arvif->vdev_id, sta,
-                                        (u8 *)arg->peer_addr, link_id,
-                                        ar->hw_link_id);
+       if (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
+               ret = ath12k_dp_link_peer_assign(ath12k_ab_to_dp(ar->ab),
+                                                &(ath12k_ar_to_ah(ar)->dp_hw),
+                                                arvif->vdev_id, sta,
+                                                (u8 *)arg->peer_addr, link_id,
+                                                ar->hw_link_id);
+       }
 
        return ret;
 }