[PATCH ath-next v3 13/13] wifi: ath12k: ng: use global dp peer id for REO TID setup

From: Pradeep Kumar Chitrapu

Date: Tue Nov 03 2026 - 20:18:50 EST


Wi-Fi 8 link peers can keep the firmware peer id invalid while the REO
queue LUT is indexed by the host-allocated global dp_peer id.

If RX TID setup uses only the link peer id, station add can fail before
REOQ LUT programming. Thread the resolved dp_peer through peer setup and
RX TID setup, prefer the global dp_peer id on global-peer-id devices, and
keep the pending REO update cleanup keyed by the same id.

Cache the Wi-Fi 8 dp_peer on ath12k_sta with RCU accessors so later RX
TID operations can find the global peer directly, and clear it during peer
delete. Preserve the Wi-Fi 8 stale saved link descriptor guard too.

Signed-off-by: Pradeep Kumar Chitrapu <pradeep.chitrapu@xxxxxxxxxxxxxxxx>
---
drivers/net/wireless/ath/ath12k/core.h | 2 +
drivers/net/wireless/ath/ath12k/dp.c | 10 ++-
drivers/net/wireless/ath/ath12k/dp.h | 4 +-
drivers/net/wireless/ath/ath12k/dp_cmn.h | 6 ++
drivers/net/wireless/ath/ath12k/dp_peer.c | 14 +++
drivers/net/wireless/ath/ath12k/dp_peer.h | 4 +-
drivers/net/wireless/ath/ath12k/dp_rx.c | 108 +++++++++++++++++++-----
drivers/net/wireless/ath/ath12k/dp_rx.h | 8 +-
drivers/net/wireless/ath/ath12k/mac.c | 15 +++-
drivers/net/wireless/ath/ath12k/wifi8/dp_peer.c | 16 +++-
drivers/net/wireless/ath/ath12k/wifi8/dp_rx.c | 15 +++-
11 files changed, 169 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 337cb4b1c386..1cd388f613f1 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -537,6 +537,8 @@ struct ath12k_sta {
u8 assoc_link_id;
u16 ml_peer_id;
u16 dp_peer_id;
+ /* Opaque RCU pointer to ath12k_dp_peer */
+ void __rcu *dp_peer;
bool is_mlo;
u16 free_logical_link_idx_map;

diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index 4ab5daccd4f2..496eabe61119 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -44,7 +44,8 @@ void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr)
spin_unlock_bh(&dp->dp_lock);
}

-int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
+int ath12k_dp_peer_setup(struct ath12k *ar, struct ath12k_dp_peer *dp_peer,
+ int vdev_id, const u8 *addr)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_dp_link_peer *peer;
@@ -52,6 +53,9 @@ int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
int ret = 0, tid;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);

+ if (!dp_peer)
+ return -ENOENT;
+
/* NOTE: reo_dest ring id starts from 1 unlike mac_id which starts from 0 */
reo_dest = ar->dp.mac_id + 1;
ret = ath12k_wmi_set_peer_param(ar, addr, vdev_id,
@@ -65,8 +69,8 @@ int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
}

for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) {
- ret = ath12k_dp_rx_peer_tid_setup(ar, addr, vdev_id, tid, 1, 0,
- HAL_PN_TYPE_NONE);
+ ret = ath12k_dp_rx_peer_tid_setup(ar, dp_peer, addr, vdev_id,
+ tid, 1, 0, HAL_PN_TYPE_NONE);
if (ret) {
ath12k_warn(ab, "failed to setup rxd tid queue for tid %d: %d\n",
tid, ret);
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 9dba68f78808..36e2704f309b 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -17,6 +17,7 @@
struct ath12k_base;
struct ath12k_hw;
struct ath12k_dp_link_peer;
+struct ath12k_dp_peer;
struct ath12k_dp;
struct ath12k_vif;
struct ath12k_link_vif;
@@ -969,7 +970,8 @@ static inline void ath12k_dp_arch_dp_link_vif_configure(struct ath12k_dp *dp,
void ath12k_dp_partner_cc_init(struct ath12k_base *ab);
int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
void ath12k_dp_pdev_pre_alloc(struct ath12k *ar);
-int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr);
+int ath12k_dp_peer_setup(struct ath12k *ar, struct ath12k_dp_peer *dp_peer,
+ int vdev_id, const u8 *addr);
void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr);
void ath12k_dp_srng_cleanup(struct ath12k_base *ab, struct dp_srng *ring);
int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring,
diff --git a/drivers/net/wireless/ath/ath12k/dp_cmn.h b/drivers/net/wireless/ath/ath12k/dp_cmn.h
index 7075963251d2..79a3ad05900c 100644
--- a/drivers/net/wireless/ath/ath12k/dp_cmn.h
+++ b/drivers/net/wireless/ath/ath12k/dp_cmn.h
@@ -12,6 +12,9 @@
#define ATH12K_DP_REO_DST_RING_MAX MIN(NR_CPUS, 5)

struct ath12k_hw_group;
+struct ath12k_dp_peer;
+struct ath12k_sta;
+struct wiphy;

/*
* ML Peer IDs start from 8192, assuming max SLO clients count 1536,
@@ -145,4 +148,7 @@ ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr
void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr);
u16 ath12k_dp_peer_get_peer_id(struct ath12k_dp_hw *dp_hw, u8 *addr);
u16 ath12k_dp_peer_get_sta_id(struct ath12k_dp_hw *dp_hw, u8 *addr);
+struct ath12k_dp_peer *
+ath12k_sta_get_dp_peer_wiphy_locked(struct wiphy *wiphy,
+ struct ath12k_sta *ahsta);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c
index 58b8b3ab5f4b..e4e2eb0719e8 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
@@ -522,6 +522,11 @@ int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
* For WiFi7, peer_id is assigned by firmware via the HTT peer map
* event before this point.
*/
+ if (dp->global_peer_id_supported && dp_peer->is_mlo) {
+ peer->ml_id = dp_peer->peer_id;
+ peer->mlo = true;
+ }
+
if (peer->peer_id != ATH12K_MLO_PEER_ID_INVALID) {
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
@@ -655,6 +660,15 @@ void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
memset(rx_stats, 0, sizeof(*rx_stats));
}

+struct ath12k_dp_peer *
+ath12k_sta_get_dp_peer_wiphy_locked(struct wiphy *wiphy,
+ struct ath12k_sta *ahsta)
+{
+ lockdep_assert_wiphy(wiphy);
+
+ return wiphy_dereference(wiphy, ahsta->dp_peer);
+}
+
/**
* ath12k_dp_peer_cleanup_all() - Clean up all datapath link peers for a radio.
* @ar: radio instance whose peers to clean up
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 5ef14ed24113..19f6a47acbb1 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -159,8 +159,8 @@ struct ath12k_dp_peer {
/* Info used in MMIC verification of * RX fragments */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
- struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
- struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
+ struct ath12k_reoq_buf reoq_bufs[ATH12K_MAX_TIDS];
+ struct ath12k_dp_rx_tid rx_tid[ATH12K_MAX_TIDS];
struct ath12k_dp_peer_ext_ctx *peer_ext_ctx;

bool is_vdev_peer;
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 47a7ec58446a..14755f653f38 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -13,6 +13,7 @@
#include "hw.h"
#include "dp_rx.h"
#include "dp_tx.h"
+#include "dp_cmn.h"
#include "peer.h"
#include "dp_mon.h"
#include "debugfs_htt_stats.h"
@@ -529,6 +530,50 @@ static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab,
return ath12k_dp_arch_rx_tid_delete_handler(dp, rx_tid);
}

+static bool ath12k_dp_rx_peer_id_valid(u16 peer_id)
+{
+ return peer_id != ATH12K_MLO_PEER_ID_INVALID;
+}
+
+static u16 ath12k_dp_rx_tid_peer_id(struct ath12k_dp *dp,
+ struct ath12k_dp_peer *dp_peer,
+ struct ath12k_dp_link_peer *peer)
+{
+ if (dp->global_peer_id_supported) {
+ if (dp_peer && ath12k_dp_rx_peer_id_valid(dp_peer->peer_id))
+ return dp_peer->peer_id;
+
+ if (peer->dp_peer &&
+ ath12k_dp_rx_peer_id_valid(peer->dp_peer->peer_id))
+ return peer->dp_peer->peer_id;
+
+ if (peer->mlo && ath12k_dp_rx_peer_id_valid(peer->ml_id))
+ return peer->ml_id;
+ }
+
+ if (peer->peer_id != ATH12K_MLO_PEER_ID_INVALID)
+ return peer->peer_id;
+
+ if (dp_peer && ath12k_dp_rx_peer_id_valid(dp_peer->peer_id))
+ return dp_peer->peer_id;
+
+ if (peer->dp_peer && ath12k_dp_rx_peer_id_valid(peer->dp_peer->peer_id))
+ return peer->dp_peer->peer_id;
+
+ return ATH12K_MLO_PEER_ID_INVALID;
+}
+
+static u16 ath12k_dp_rx_reo_peer_id(struct ath12k_dp *dp,
+ struct ath12k_dp_peer *dp_peer,
+ struct ath12k_dp_link_peer *peer)
+{
+ if (!dp->global_peer_id_supported && peer->mlo &&
+ peer->ml_id != ATH12K_MLO_PEER_ID_INVALID)
+ return peer->ml_id;
+
+ return ath12k_dp_rx_tid_peer_id(dp, dp_peer, peer);
+}
+
void ath12k_dp_mark_tid_as_inactive(struct ath12k_dp *dp, int peer_id, u8 tid)
{
struct dp_reo_update_rx_queue_elem *elem;
@@ -573,6 +618,7 @@ void ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_dp_link_peer
}

static int ath12k_dp_prepare_reo_update_elem(struct ath12k_dp *dp,
+ struct ath12k_dp_peer *dp_peer,
struct ath12k_dp_link_peer *peer,
struct ath12k_dp_rx_tid *rx_tid)
{
@@ -587,9 +633,11 @@ static int ath12k_dp_prepare_reo_update_elem(struct ath12k_dp *dp,
if (!elem)
return -ENOMEM;

- elem->peer_id = peer->peer_id;
- elem->is_ml_peer = peer->mlo;
- elem->ml_peer_id = peer->ml_id;
+ elem->peer_id = ath12k_dp_rx_tid_peer_id(dp, dp_peer, peer);
+ elem->is_ml_peer = !dp->global_peer_id_supported && peer->mlo &&
+ peer->ml_id != ATH12K_MLO_PEER_ID_INVALID;
+ elem->ml_peer_id = elem->is_ml_peer ? peer->ml_id :
+ ATH12K_MLO_PEER_ID_INVALID;

ath12k_dp_init_rx_tid_rxq(&elem->rx_tid, rx_tid,
(peer->rx_tid_active_bitmask & (1 << rx_tid->tid)));
@@ -601,8 +649,10 @@ static int ath12k_dp_prepare_reo_update_elem(struct ath12k_dp *dp,
return 0;
}

-int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
- u8 tid, u32 ba_win_sz, u16 ssn,
+int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar,
+ struct ath12k_dp_peer *dp_peer,
+ const u8 *peer_mac, int vdev_id, u8 tid,
+ u32 ba_win_sz, u16 ssn,
enum hal_pn_type pn_type)
{
struct ath12k_base *ab = ar->ab;
@@ -610,17 +660,27 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_
struct ath12k_dp_link_peer *peer;
struct ath12k_dp_rx_tid *rx_tid;
dma_addr_t paddr_aligned;
+ u16 reo_peer_id;
int ret;

spin_lock_bh(&dp->dp_lock);

peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, peer_mac);
- if (!peer || !peer->dp_peer) {
+ if (!peer) {
spin_unlock_bh(&dp->dp_lock);
ath12k_warn(ab, "failed to find the peer to set up rx tid\n");
return -ENOENT;
}

+ if (!dp_peer)
+ dp_peer = peer->dp_peer;
+
+ if (!dp_peer) {
+ spin_unlock_bh(&dp->dp_lock);
+ ath12k_warn(ab, "failed to find dp peer to set up rx tid\n");
+ return -ENOENT;
+ }
+
if (ab->hw_params->dp_primary_link_only &&
!peer->primary_link) {
spin_unlock_bh(&dp->dp_lock);
@@ -634,14 +694,22 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_
return -EINVAL;
}

- if (peer->peer_id > DP_MAX_PEER_ID || tid > IEEE80211_NUM_TIDS) {
- ath12k_warn(ab, "peer id of peer %d or tid %d doesn't allow reoq setup\n",
- peer->peer_id, tid);
+ reo_peer_id = ath12k_dp_rx_reo_peer_id(dp, dp_peer, peer);
+
+ if ((reo_peer_id & ~ATH12K_PEER_ML_ID_VALID) > DP_MAX_PEER_ID ||
+ tid > IEEE80211_NUM_TIDS) {
+ ath12k_warn(ab,
+ "reo peer id %d or tid %d doesn't allow reoq setup global %d dp_peer_id %u link_dp_peer_id %u link_peer_id %u ml_id %u mlo %d primary %d\n",
+ reo_peer_id, tid, dp->global_peer_id_supported,
+ dp_peer ? dp_peer->peer_id : ATH12K_MLO_PEER_ID_INVALID,
+ peer->dp_peer ? peer->dp_peer->peer_id :
+ ATH12K_MLO_PEER_ID_INVALID,
+ peer->peer_id, peer->ml_id, peer->mlo, peer->primary_link);
spin_unlock_bh(&dp->dp_lock);
return -EINVAL;
}

- rx_tid = &peer->dp_peer->rx_tid[tid];
+ rx_tid = &dp_peer->rx_tid[tid];
/* Update the tid queue if it is already setup */
if (peer->rx_tid_active_bitmask & (1 << tid)) {
ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, rx_tid,
@@ -672,7 +740,7 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_

rx_tid->ba_win_sz = ba_win_sz;

- ret = ath12k_dp_arch_rx_assign_reoq(dp, peer->dp_peer, rx_tid, ssn, pn_type);
+ ret = ath12k_dp_arch_rx_assign_reoq(dp, dp_peer, rx_tid, ssn, pn_type);
if (ret) {
spin_unlock_bh(&dp->dp_lock);
ath12k_warn(ab, "failed to assign reoq buf for rx tid %u\n", tid);
@@ -686,7 +754,7 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_
* allocating during tid delete is that, if any alloc fail in update_rxq_list
* we may not be able to delete the tid vaddr/paddr and may lead to leak
*/
- ret = ath12k_dp_prepare_reo_update_elem(dp, peer, rx_tid);
+ ret = ath12k_dp_prepare_reo_update_elem(dp, dp_peer, peer, rx_tid);
if (ret) {
ath12k_warn(ab, "failed to alloc update_rxq_list for rx tid %u\n", tid);
ath12k_dp_rx_tid_cleanup(ab, &rx_tid->qbuf);
@@ -699,12 +767,8 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_
/* Update the REO queue LUT at the corresponding peer id
* and tid with qaddr.
*/
- if (peer->mlo)
- ath12k_dp_arch_peer_rx_tid_qref_setup(dp, peer->ml_id, tid,
- paddr_aligned);
- else
- ath12k_dp_arch_peer_rx_tid_qref_setup(dp, peer->peer_id, tid,
- paddr_aligned);
+ ath12k_dp_arch_peer_rx_tid_qref_setup(dp, reo_peer_id, tid,
+ paddr_aligned);

spin_unlock_bh(&dp->dp_lock);
} else {
@@ -724,6 +788,7 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ath12k_base *ab = ar->ab;
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta);
struct ath12k_link_sta *arsta;
+ struct ath12k_dp_peer *dp_peer;
int vdev_id;
int ret;

@@ -736,7 +801,12 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar,

vdev_id = arsta->arvif->vdev_id;

- ret = ath12k_dp_rx_peer_tid_setup(ar, arsta->addr, vdev_id,
+ dp_peer = ath12k_sta_get_dp_peer_wiphy_locked(ath12k_ar_to_hw(ar)->wiphy,
+ ahsta);
+ if (!dp_peer)
+ return -ENOENT;
+
+ ret = ath12k_dp_rx_peer_tid_setup(ar, dp_peer, arsta->addr, vdev_id,
params->tid, params->buf_size,
params->ssn, arsta->ahsta->pn_type);
if (ret)
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index f523ac48747f..a76b79549924 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -10,8 +10,10 @@
#include "debug.h"

#define DP_MAX_NWIFI_HDR_LEN 30
+#define ATH12K_MAX_TIDS (IEEE80211_NUM_TIDS + 1)

struct hal_reo_status;
+struct ath12k_dp_peer;

struct ath12k_reoq_buf {
void *vaddr;
@@ -232,8 +234,10 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
void ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_dp_link_peer *peer);
void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar,
struct ath12k_dp_link_peer *peer, u8 tid);
-int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
- u8 tid, u32 ba_win_sz, u16 ssn,
+int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar,
+ struct ath12k_dp_peer *dp_peer,
+ const u8 *peer_mac, int vdev_id, u8 tid,
+ u32 ba_win_sz, u16 ssn,
enum hal_pn_type pn_type);
int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab,
struct dp_rxdma_ring *rx_ring);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 77343469ccca..37c17a97d5aa 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -7177,6 +7177,7 @@ static int ath12k_mac_station_add(struct ath12k *ar,
struct ath12k_wmi_peer_create_arg peer_param = {};
int ret;
struct ath12k_link_sta *temp_arsta;
+ struct ath12k_dp_peer *dp_peer;

lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);

@@ -7235,7 +7236,19 @@ static int ath12k_mac_station_add(struct ath12k *ar,
}
}

- ret = ath12k_dp_peer_setup(ar, arvif->vdev_id, arsta->addr);
+ dp_peer = ath12k_sta_get_dp_peer_wiphy_locked(ath12k_ar_to_hw(ar)->wiphy,
+ arsta->ahsta);
+ if (!dp_peer || dp_peer->peer_id == ATH12K_MLO_PEER_ID_INVALID) {
+ spin_lock_bh(&ar->ah->dp_hw.peer_lock);
+ dp_peer = ath12k_dp_peer_find_by_addr_and_sta(&ar->ah->dp_hw,
+ sta->addr, sta);
+ if (!dp_peer)
+ dp_peer = ath12k_dp_peer_find_by_addr_and_sta(&ar->ah->dp_hw,
+ arsta->addr,
+ sta);
+ spin_unlock_bh(&ar->ah->dp_hw.peer_lock);
+ }
+ ret = ath12k_dp_peer_setup(ar, dp_peer, arvif->vdev_id, arsta->addr);
if (ret) {
ath12k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
arsta->addr, arvif->vdev_id, ret);
diff --git a/drivers/net/wireless/ath/ath12k/wifi8/dp_peer.c b/drivers/net/wireless/ath/ath12k/wifi8/dp_peer.c
index a89086ca15c1..2006a862feb2 100644
--- a/drivers/net/wireless/ath/ath12k/wifi8/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/wifi8/dp_peer.c
@@ -319,7 +319,8 @@ int ath12k_wifi8_dp_peer_create(struct ath12k_hw *ah, u8 *addr,
struct ath12k_dp_hw *dp_hw = &ah->dp_hw;
struct ath12k_sta *ahsta = NULL;

- ahsta = ath12k_sta_to_ahsta(params->sta);
+ if (params->sta)
+ ahsta = ath12k_sta_to_ahsta(params->sta);

spin_lock_bh(&dp_hw->peer_lock);
dp_peer = ath12k_dp_peer_find_by_addr(dp_hw, addr);
@@ -375,7 +376,10 @@ int ath12k_wifi8_dp_peer_create(struct ath12k_hw *ah, u8 *addr,
dp_peer->hw_link_id = params->hw_link_id;
} else {
dp_peer->assoc_hw_link_id = params->hw_link_id;
- ahsta->dp_peer_id = dp_peer->peer_id;
+ if (ahsta) {
+ ahsta->dp_peer_id = dp_peer->peer_id;
+ rcu_assign_pointer(ahsta->dp_peer, dp_peer);
+ }
}

dp_peer->is_sta_bss_peer = params->is_sta_bss_peer;
@@ -410,15 +414,19 @@ void ath12k_wifi8_dp_peer_delete(struct ath12k_dp *dp, struct ath12k_hw *ah, u8
struct ath12k_base *central_ab = NULL;
struct ath12k_dp_wifi8 *dp_wifi8 = NULL;
struct hal_srng *srng = NULL;
+ struct ath12k_sta *ahsta;
int i, ret;

dp_hw_grp_wifi8 = ath12k_get_dp_hw_group_wifi8(dp->dp_hw_grp);

spin_lock_bh(&dp_hw->peer_lock);
- if (sta)
+ if (sta) {
+ ahsta = ath12k_sta_to_ahsta(sta);
+ rcu_assign_pointer(ahsta->dp_peer, NULL);
dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, addr, sta);
- else
+ } else {
dp_peer = ath12k_dp_peer_find_by_addr(dp_hw, addr);
+ }

if (!dp_peer) {
spin_unlock_bh(&dp_hw->peer_lock);
diff --git a/drivers/net/wireless/ath/ath12k/wifi8/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi8/dp_rx.c
index 0b8a9d32e125..c74f070c0d88 100644
--- a/drivers/net/wireless/ath/ath12k/wifi8/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi8/dp_rx.c
@@ -364,11 +364,18 @@ void ath12k_wifi8_dp_rx_peer_tid_delete(struct ath12k_base *ab,
u8 tid)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
+ u16 peer_id = peer->peer_id;

if (!(peer->rx_tid_active_bitmask & BIT(tid)))
return;

- ath12k_dp_mark_tid_as_inactive(dp, peer->peer_id, tid);
+ if (peer_id == ATH12K_MLO_PEER_ID_INVALID && peer->dp_peer)
+ peer_id = peer->dp_peer->peer_id;
+
+ if (peer_id == ATH12K_MLO_PEER_ID_INVALID)
+ return;
+
+ ath12k_dp_mark_tid_as_inactive(dp, peer_id, tid);
ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(dp);
}

@@ -517,6 +524,11 @@ void ath12k_wifi8_dp_rx_frags_cleanup(struct ath12k_dp_rx_tid *rx_tid,
lockdep_assert_held(&dp->dp_lock);

if (rx_tid->dst_ring_desc) {
+ if ((unsigned long)rx_tid->dst_ring_desc < PAGE_SIZE) {
+ rx_tid->dst_ring_desc = NULL;
+ goto clear;
+ }
+
if (rel_link_desc) {
buf_addr_info = &rx_tid->dst_ring_desc->buf_addr_info;
ath12k_wifi8_dp_rx_link_desc_return(dp, buf_addr_info,
@@ -527,6 +539,7 @@ void ath12k_wifi8_dp_rx_frags_cleanup(struct ath12k_dp_rx_tid *rx_tid,
rx_tid->dst_ring_desc = NULL;
}

+clear:
rx_tid->cur_sn = 0;
rx_tid->last_frag_no = 0;
rx_tid->rx_frag_bitmap = 0;

--
2.43.0