wifi: ath12k: defer dp_peer registration when firmware allocates MLD peer ID

For chips with host_alloc_ml_id=true (QCN9274 etc.), the host allocates
the MLD peer ID up front; ath12k_dp_peer_create() publishes the dp_peer
into dp_hw->dp_peers[] using that ID immediately. WCN7850/QCC2072 does
not work that way: the firmware picks the ID and only tells the host
afterwards via HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP, so the publication has
to be delayed until the event arrives.

Introduce ATH12K_MLO_PEER_ID_PENDING (0xFFFE) as a sentinel for "is_mlo,
but ID not yet known". On the firmware-allocates path:

  - ath12k_mac_op_sta_state(NOTEXIST->NONE) skips ath12k_peer_ml_alloc()
    and stores PENDING in ahsta->ml_peer_id and dp_params.peer_id;
  - ath12k_dp_peer_create() skips dp_peer registration until a real ID is
    known;
  - ath12k_peer_create() leaves peer->ml_id at INVALID so consumer sites
    do not treat PENDING as a real ID;
  - ath12k_peer_ml_free() and ath12k_mac_dp_peer_cleanup() skip the
    dp_peers[] write and the free_ml_peer_id_map clear when
    host_alloc_ml_id is false or the ID is still PENDING.

The HTT handler change that resolves the PENDING ID is added in a
follow-up patch.

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-7-630632758a80@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
Baochen Qiang 2026-07-20 14:43:28 +08:00 committed by Jeff Johnson
parent 1726a7a10c
commit a7619b3bcb
4 changed files with 49 additions and 17 deletions

View File

@ -72,6 +72,7 @@
#define ATH12K_MAX_MLO_PEERS 256
#define ATH12K_MLO_PEER_ID_INVALID 0xFFFF
#define ATH12K_MLO_PEER_ID_PENDING 0xFFFE
#define ATH12K_INVALID_RSSI_FULL -1
#define ATH12K_INVALID_RSSI_EMPTY -128

View File

@ -475,7 +475,9 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
dp_peer->is_mlo = params->is_mlo;
/*
* For MLO client, the host assigns the ML peer ID, so set peer_id in dp_peer
* For MLO client, the ML peer ID, either known or PENDING, needs to be
* initialized here since the following logic depends on it.
*
* For non-MLO client, host gets link peer ID from firmware and will be
* assigned at the time of link peer creation
*/
@ -491,13 +493,17 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
list_add(&dp_peer->list, &dp_hw->dp_peers_list);
/*
* For MLO client, the peer_id for ath12k_dp_peer is allocated by host
* and that peer_id is known at this point, and hence this ath12k_dp_peer
* can be added to the RCU table using the peer_id.
* For non-MLO client, this addition to RCU table shall be done at the
* time of assignment of ath12k_dp_link_peer to ath12k_dp_peer.
* For an MLO client whose ML peer ID is allocated by the host, the
* peer_id is known here and the dp_peer can be added to the RCU
* table using it. For an MLO client on chips where the firmware
* allocates the ID, peer_id is ATH12K_MLO_PEER_ID_PENDING and the
* RCU table publish is deferred to the
* HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For a non-MLO client
* the publish happens later, at the time of assignment of
* ath12k_dp_link_peer to ath12k_dp_peer.
*/
if (dp_peer->is_mlo)
if (dp_peer->is_mlo &&
dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
spin_unlock_bh(&dp_hw->peer_lock);
@ -518,7 +524,8 @@ void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
return;
}
if (dp_peer->is_mlo)
if (dp_peer->is_mlo &&
dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
list_del(&dp_peer->list);

View File

@ -1289,7 +1289,9 @@ void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah)
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) {
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
if (dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id],
NULL);
ath12k_peer_ml_free(ah, ath12k_sta_to_ahsta(dp_peer->sta));
}
@ -7750,11 +7752,19 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
/* ML sta */
if (sta->mlo && !ahsta->links_map &&
(hweight16(sta->valid_links) == 1)) {
ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
sta->addr);
goto exit;
if (ah->host_alloc_ml_id) {
ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
sta->addr);
goto exit;
}
} else {
/*
* firmware allocates the ML peer ID and notifies
* the host via HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP
*/
ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_PENDING;
}
dp_params.is_mlo = true;

View File

@ -230,7 +230,16 @@ 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;
/*
* For chips where firmware allocates the ML peer ID,
* ml_peer_id is ATH12K_MLO_PEER_ID_PENDING here. The
* MLO_RX_PEER_MAP HTT event handler fixes up
* peer->ml_id once the ID is known.
*/
if (ml_peer_id == ATH12K_MLO_PEER_ID_PENDING)
peer->ml_id = ATH12K_MLO_PEER_ID_INVALID;
else
peer->ml_id = ml_peer_id;
ether_addr_copy(peer->ml_addr, sta->addr);
/* the assoc link is considered primary for now */
@ -285,8 +294,13 @@ 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))
/*
* Only devices that allocate the ID on the host own a slot in
* free_ml_peer_id_map.
*/
if (ah->host_alloc_ml_id &&
(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;