mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
wifi: ath12k: resolve PENDING ML peer ID from MLO_PEER_MAP HTT event
Add ath12k_dp_peer_fixup_peer_id() and call it from the
HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For devices where the
firmware allocates the MLD peer ID, this is the point at which
all data structures that were left with ATH12K_MLO_PEER_ID_PENDING
or ATH12K_MLO_PEER_ID_INVALID get their real ID:
- dp_peer->peer_id is updated and the dp_peer is published into
dp_hw->dp_peers[];
- every existing dp_link_peer in dp_peer->link_peers[] gets its
ml_id set to the same value;
- ahsta->ml_peer_id is updated to the same value so peer_assoc,
sta_state and cleanup paths see a consistent ID.
Devices with host_alloc_ml_id == true also receive the same HTT
event, but the firmware-reported ID always matches the
host-allocated one and everything has already been populated by
ath12k_dp_peer_create(); Skips the helper entirely on those devices.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221039
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-8-630632758a80@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
committed by
Jeff Johnson
parent
a7619b3bcb
commit
469d7e6077
@@ -1544,6 +1544,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
|
||||
}
|
||||
|
||||
wiphy_unlock(ah->hw->wiphy);
|
||||
|
||||
complete(&ah->peer_ml_id_done);
|
||||
}
|
||||
|
||||
wake_up(&ab->wmi_ab.tx_credits_wq);
|
||||
|
||||
@@ -795,6 +795,7 @@ struct ath12k_hw {
|
||||
bool regd_updated;
|
||||
bool use_6ghz_regd;
|
||||
bool host_alloc_ml_id;
|
||||
struct completion peer_ml_id_done;
|
||||
|
||||
u8 num_radio;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "core.h"
|
||||
#include "peer.h"
|
||||
#include "dp_peer.h"
|
||||
#include "htc.h"
|
||||
#include "dp_htt.h"
|
||||
#include "debugfs_htt_stats.h"
|
||||
@@ -582,6 +583,7 @@ static void ath12k_dp_htt_mlo_peer_map_handler(struct ath12k_base *ab,
|
||||
struct htt_t2h_mlo_peer_map_event *ev = &resp->mlo_peer_map_ev;
|
||||
u16 raw_peer_id, peer_id, addr_h16;
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
int ret;
|
||||
|
||||
if (skb->len < sizeof(*ev)) {
|
||||
ath12k_warn(ab, "unexpected htt mlo peer map event len %u\n",
|
||||
@@ -600,6 +602,23 @@ static void ath12k_dp_htt_mlo_peer_map_handler(struct ath12k_base *ab,
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt mlo peer map peer %pM id %u\n",
|
||||
peer_addr, peer_id);
|
||||
|
||||
/*
|
||||
* Fix up the dp_peer entry created with ATH12K_MLO_PEER_ID_PENDING
|
||||
* earlier; on chips with host_alloc_ml_id == false this is the only
|
||||
* point at which the host learns the firmware-assigned ID. Chips
|
||||
* that allocate the ID on the host also receive this event but the
|
||||
* firmware-reported ID matches the host-allocated one, so there is
|
||||
* nothing to fix up.
|
||||
*/
|
||||
if (!ab->hw_params->host_alloc_ml_id) {
|
||||
ret = ath12k_dp_peer_fixup_peer_id(ab, peer_addr,
|
||||
peer_id);
|
||||
if (ret)
|
||||
ath12k_warn(ab,
|
||||
"failed to fix up peer id %u for dp peer %pM: %d\n",
|
||||
peer_id, peer_addr, ret);
|
||||
}
|
||||
}
|
||||
|
||||
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
|
||||
|
||||
@@ -702,3 +702,55 @@ void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
|
||||
if (rx_stats)
|
||||
memset(rx_stats, 0, sizeof(*rx_stats));
|
||||
}
|
||||
|
||||
int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab,
|
||||
const u8 *peer_addr, u16 peer_id)
|
||||
{
|
||||
struct ath12k_dp_link_peer *link_peer;
|
||||
struct ath12k_dp_peer *dp_peer = NULL;
|
||||
struct ath12k_hw_group *ag = ab->ag;
|
||||
struct ath12k_dp_hw *dp_hw = NULL;
|
||||
struct ath12k_hw *ah;
|
||||
int i;
|
||||
|
||||
if (peer_id >= (ATH12K_PEER_ML_ID_VALID | ATH12K_MAX_MLO_PEERS))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ag->num_hw; i++) {
|
||||
ah = ag->ah[i];
|
||||
if (!ah)
|
||||
continue;
|
||||
|
||||
spin_lock_bh(&ah->dp_hw.peer_lock);
|
||||
dp_peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw,
|
||||
(u8 *)peer_addr);
|
||||
if (dp_peer) {
|
||||
dp_hw = &ah->dp_hw;
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ah->dp_hw.peer_lock);
|
||||
}
|
||||
|
||||
if (!dp_peer)
|
||||
return -ENOENT;
|
||||
|
||||
/* dp_hw->peer_lock is held */
|
||||
|
||||
dp_peer->peer_id = peer_id;
|
||||
rcu_assign_pointer(dp_hw->dp_peers[peer_id], dp_peer);
|
||||
|
||||
for (i = 0; i < ATH12K_NUM_MAX_LINKS; i++) {
|
||||
link_peer = rcu_dereference_protected(dp_peer->link_peers[i],
|
||||
lockdep_is_held(&dp_hw->peer_lock));
|
||||
if (link_peer)
|
||||
link_peer->ml_id = peer_id;
|
||||
}
|
||||
|
||||
ath12k_sta_to_ahsta(dp_peer->sta)->ml_peer_id = peer_id;
|
||||
|
||||
spin_unlock_bh(&dp_hw->peer_lock);
|
||||
|
||||
complete(&ah->peer_ml_id_done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -181,4 +181,6 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p
|
||||
struct ath12k_dp_link_peer *
|
||||
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id);
|
||||
void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer);
|
||||
int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab, const u8 *peer_addr,
|
||||
u16 peer_id);
|
||||
#endif
|
||||
|
||||
@@ -3859,9 +3859,11 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar,
|
||||
static int ath12k_mac_peer_assoc(struct ath12k *ar,
|
||||
struct ath12k_wmi_peer_assoc_arg *peer_arg)
|
||||
{
|
||||
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
|
||||
int ret;
|
||||
|
||||
reinit_completion(&ar->peer_assoc_done);
|
||||
reinit_completion(&ah->peer_ml_id_done);
|
||||
|
||||
ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
|
||||
if (ret) {
|
||||
@@ -3876,6 +3878,27 @@ static int ath12k_mac_peer_assoc(struct ath12k *ar,
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* For devices where the firmware allocates the MLD peer ID, the host
|
||||
* learns the real ID only from the MLO_RX_PEER_MAP HTT event, which is
|
||||
* handled in a softirq (BH workqueue) context that cannot take the
|
||||
* wiphy lock. Block here, while still holding the wiphy lock, until
|
||||
* that event has fixed up the ID. This serialises the fixup against
|
||||
* all other wiphy-locked ml_peer_id accesses.
|
||||
*
|
||||
* The firmware sends the event only once, in response to the assoc-link
|
||||
* peer assoc, so block only for that link.
|
||||
*/
|
||||
if (!ah->host_alloc_ml_id &&
|
||||
peer_arg->is_assoc &&
|
||||
peer_arg->ml.enabled &&
|
||||
peer_arg->ml.assoc_link &&
|
||||
!wait_for_completion_timeout(&ah->peer_ml_id_done, 1 * HZ)) {
|
||||
ath12k_warn(ar->ab, "failed to get MLO peer map event for %pM vdev %i\n",
|
||||
peer_arg->peer_mac, peer_arg->vdev_id);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -15335,6 +15358,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
|
||||
ah->num_radio = num_pdev_map;
|
||||
|
||||
mutex_init(&ah->hw_mutex);
|
||||
init_completion(&ah->peer_ml_id_done);
|
||||
|
||||
spin_lock_init(&ah->dp_hw.peer_lock);
|
||||
INIT_LIST_HEAD(&ah->dp_hw.dp_peers_list);
|
||||
|
||||
Reference in New Issue
Block a user