]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: ath12k: keep ATH12K_PEER_ML_ID_VALID set in ath12k_sta::ml_peer_id
authorBaochen Qiang <baochen.qiang@oss.qualcomm.com>
Mon, 20 Jul 2026 06:43:24 +0000 (14:43 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 27 Jul 2026 15:00:42 +0000 (08:00 -0700)
Several pieces of host bookkeeping for MLD peer IDs encode the
same fact in different ways:

  - ath12k_sta::ml_peer_id stores the raw ID in [0, ATH12K_MAX_MLO_PEERS);
  - ath12k_dp_peer::peer_id, ath12k_dp_link_peer::ml_id and the index used
    on ath12k_dp_hw::dp_peers[] always carry the ATH12K_PEER_ML_ID_VALID
    bit (BIT(13)) when the ID is real;
  - WMI_MLO_PEER_ASSOC_PARAMS::ml_peer_id sent down to firmware is
    raw, without the bookkeeping bit.

The mismatch leaks into call sites that have to remember to OR
the bit in (ath12k_peer_create(), ath12k_mac_op_sta_state()) or
remember not to (ath12k_peer_assoc_h_mlo()).

Make ath12k_sta::ml_peer_id carry the VALID bit when valid, the same
way ath12k_dp_peer::peer_id and ath12k_dp_link_peer::ml_id do:

  - ath12k_peer_ml_alloc() OR-s the bit in once on the way out;
    the internal bitmap stays raw [0, ATH12K_MAX_MLO_PEERS);
  - ath12k_peer_create() and ath12k_mac_op_sta_state() drop the
    explicit OR;
  - ath12k_peer_assoc_h_mlo() masks the bit off when populating
    the WMI ml_peer_id;

While there, introduce ath12k_peer_ml_free() to mirror
ath12k_peer_ml_alloc(), which helps avoid code duplication.

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

Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Link: https://patch.msgid.link/20260720-ath12k-fw-allocated-ml-peer-id-v2-3-630632758a80@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/peer.c
drivers/net/wireless/ath/ath12k/peer.h

index b4df222f0c19a936d7abf61e7244cc3ac5554b2a..06f1a1ba994ad0ca82be6dc234917eb9c5a3f082 100644 (file)
@@ -1282,16 +1282,15 @@ void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah)
        struct ath12k_dp_peer *dp_peer, *tmp;
        struct ath12k_dp_hw *dp_hw = &ah->dp_hw;
 
+       lockdep_assert_wiphy(ah->hw->wiphy);
+
        INIT_LIST_HEAD(&peers);
 
        spin_lock_bh(&dp_hw->peer_lock);
        list_for_each_entry_safe(dp_peer, tmp, &dp_hw->dp_peers_list, list) {
                if (dp_peer->is_mlo) {
-                       struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(dp_peer->sta);
-
                        rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
-                       clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
-                       ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
+                       ath12k_peer_ml_free(ah, ath12k_sta_to_ahsta(dp_peer->sta));
                }
 
                list_move(&dp_peer->list, &peers);
@@ -3551,7 +3550,11 @@ static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta,
 
        ether_addr_copy(ml->mld_addr, sta->addr);
        ml->logical_link_idx = arsta->link_idx;
-       ml->ml_peer_id = ahsta->ml_peer_id;
+       /*
+        * WMI_MLO_PEER_ASSOC_PARAMS expects the raw ML peer ID without
+        * the host-side ATH12K_PEER_ML_ID_VALID bookkeeping bit.
+        */
+       ml->ml_peer_id = ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID;
        ml->ieee_link_id = arsta->link_id;
        ml->num_partner_links = 0;
        ml->eml_cap = sta->eml_cap;
@@ -7268,10 +7271,8 @@ static void ath12k_mac_ml_station_remove(struct ath12k_vif *ahvif,
                ath12k_mac_free_unassign_link_sta(ah, ahsta, link_id);
        }
 
-       if (sta->mlo) {
-               clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
-               ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
-       }
+       if (sta->mlo)
+               ath12k_peer_ml_free(ah, ahsta);
 }
 
 static int ath12k_mac_handle_link_sta_state(struct ieee80211_hw *hw,
@@ -7743,7 +7744,7 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
                        }
 
                        dp_params.is_mlo = true;
-                       dp_params.peer_id = ahsta->ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+                       dp_params.peer_id = ahsta->ml_peer_id;
                }
 
                dp_params.sta = sta;
@@ -7880,10 +7881,8 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
 peer_delete:
        ath12k_dp_peer_delete(&ah->dp_hw, sta->addr, sta);
 ml_peer_id_clear:
-       if (sta->mlo) {
-               clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
-               ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
-       }
+       if (sta->mlo)
+               ath12k_peer_ml_free(ah, ahsta);
 exit:
        /* update the state if everything went well */
        if (!ret)
index 2681a047d4d51968d44c29240369256dbacbfe5f..5dd7c6470219e9afb87c9c7006f049192b6476da 100644 (file)
@@ -230,7 +230,7 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
                /* Fill ML info into created peer */
                if (sta->mlo) {
                        ml_peer_id = ahsta->ml_peer_id;
-                       peer->ml_id = ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+                       peer->ml_id = ml_peer_id;
                        ether_addr_copy(peer->ml_addr, sta->addr);
 
                        /* the assoc link is considered primary for now */
@@ -276,9 +276,20 @@ u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
        }
 
        if (ml_peer_id == ATH12K_MAX_MLO_PEERS)
-               ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
+               return ATH12K_MLO_PEER_ID_INVALID;
 
-       return ml_peer_id;
+       return ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+}
+
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta)
+{
+       lockdep_assert_wiphy(ah->hw->wiphy);
+
+       if (ahsta->ml_peer_id <
+           (ATH12K_MAX_MLO_PEERS | ATH12K_PEER_ML_ID_VALID))
+               clear_bit(ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID,
+                         ah->free_ml_peer_id_map);
+       ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
 }
 
 int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta)
index 49d89796bc46e2b3122b85097ebf4bb0dbd33590..0f7f25b8e89c038e4bba5f00af50b7963adeb89c 100644 (file)
@@ -26,4 +26,5 @@ int ath12k_link_sta_rhash_add(struct ath12k_base *ab, struct ath12k_link_sta *ar
 struct ath12k_link_sta *ath12k_link_sta_find_by_addr(struct ath12k_base *ab,
                                                     const u8 *addr);
 u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah);
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta);
 #endif /* _PEER_H_ */