Skip to content

Commit a3ac7de

Browse files
author
Venkat Chimata
committed
This is a work in progress patch.
num_peers was decremented at one place and list_del was called at another place. There are chances that they miss sync. So reset num_peers when out of sync Signed-off-by: Venkat Chimata <[email protected]>
1 parent 50eee0e commit a3ac7de

File tree

1 file changed

+264
-0
lines changed

1 file changed

+264
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
From 625b8692332ee44e514be88400646e900710644b Mon Sep 17 00:00:00 2001
2+
From: Venkat Chimata <[email protected]>
3+
Date: Tue, 25 Nov 2025 20:34:34 +0530
4+
Subject: [PATCH] This is a work in progress patch.
5+
6+
num_peers was decremented at one place and list_del was called at another place.
7+
There are chances that they miss sync.
8+
9+
So reset num_peers when out of sync
10+
11+
Signed-off-by: Venkat Chimata <[email protected]>
12+
---
13+
drivers/net/wireless/ath/ath11k/mac.c | 39 ++++++++----
14+
drivers/net/wireless/ath/ath11k/peer.c | 82 +++++++++++++++++++++++---
15+
2 files changed, 102 insertions(+), 19 deletions(-)
16+
17+
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
18+
index f300c4f..a3eeac8 100644
19+
--- a/drivers/net/wireless/ath/ath11k/mac.c
20+
+++ b/drivers/net/wireless/ath/ath11k/mac.c
21+
@@ -5383,6 +5383,8 @@ static int ath11k_mac_station_add(struct ath11k *ar,
22+
peer_param.peer_addr = sta->addr;
23+
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
24+
25+
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
26+
+ sta->addr, arvif->vdev_id);
27+
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
28+
if (ret) {
29+
ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
30+
@@ -5457,7 +5459,13 @@ free_tx_stats:
31+
kfree(arsta->wbm_tx_stats);
32+
arsta->wbm_tx_stats = NULL;
33+
free_peer:
34+
- ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
35+
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
36+
+ if (ret)
37+
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
38+
+ sta->addr, arvif->vdev_id);
39+
+ else
40+
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
41+
+ sta->addr, arvif->vdev_id);
42+
free_rx_stats:
43+
kfree(arsta->rx_stats);
44+
arsta->rx_stats = NULL;
45+
@@ -5735,18 +5743,15 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
46+
ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n",
47+
sta->addr, arvif->vdev_id);
48+
else
49+
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "Removed peer: %pM for VDEV: %d\n",
50+
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
51+
sta->addr, arvif->vdev_id);
52+
53+
ath11k_mac_dec_num_stations(arvif, sta);
54+
mutex_lock(&ar->ab->tbl_mtx_lock);
55+
spin_lock_bh(&ar->ab->base_lock);
56+
peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
57+
- /* Skip if peer deletion already in progress to prevent
58+
- * double-delete and num_peers underflow
59+
- */
60+
- if (peer && peer->sta == sta && !peer->delete_in_progress) {
61+
- ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
62+
+ if (peer && peer->sta == sta) {
63+
+ ath11k_warn(ar->ab, "%s: Found peer entry %pM n vdev %i after it was supposedly removed\n", __func__,
64+
vif->addr, arvif->vdev_id);
65+
ath11k_peer_rhash_delete(ar->ab, peer);
66+
peer->sta = NULL;
67+
@@ -7746,6 +7751,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
68+
peer_param.vdev_id = arvif->vdev_id;
69+
peer_param.peer_addr = vif->addr;
70+
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
71+
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
72+
+ vif->addr, arvif->vdev_id);
73+
ret = ath11k_peer_create(ar, arvif, NULL, &peer_param);
74+
if (ret) {
75+
ath11k_warn(ab, "failed to vdev %d create peer for AP: %d\n",
76+
@@ -7947,8 +7954,11 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
77+
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
78+
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
79+
if (ret)
80+
- ath11k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
81+
+ ath11k_warn(ab, "%s: failed to submit AP self-peer removal on vdev %d: %d\n", __func__,
82+
arvif->vdev_id, ret);
83+
+ else
84+
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
85+
+ vif->addr, arvif->vdev_id);
86+
87+
list_for_each_entry_safe(ap_vlan_arvif, tmp, &arvif->ap_vlan_arvifs,
88+
list) {
89+
@@ -9305,6 +9315,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
90+
param.peer_type = WMI_PEER_TYPE_DEFAULT;
91+
param.peer_addr = ar->mac_addr;
92+
93+
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
94+
+ ar->mac_addr, arvif->vdev_id);
95+
ret = ath11k_peer_create(ar, arvif, NULL, &param);
96+
if (ret) {
97+
ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
98+
@@ -9380,8 +9392,15 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
99+
100+
if (ab->hw_params.vdev_start_delay &&
101+
arvif->vdev_type == WMI_VDEV_TYPE_MONITOR &&
102+
- ath11k_peer_find_by_addr(ab, ar->mac_addr))
103+
- ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
104+
+ ath11k_peer_find_by_addr(ab, ar->mac_addr)) {
105+
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
106+
+ if (ret)
107+
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
108+
+ ar->mac_addr, arvif->vdev_id);
109+
+ else
110+
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
111+
+ ar->mac_addr, arvif->vdev_id);
112+
+ }
113+
114+
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
115+
ret = ath11k_mac_monitor_stop(ar);
116+
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
117+
index 877ea30..9ec297f 100644
118+
--- a/drivers/net/wireless/ath/ath11k/peer.c
119+
+++ b/drivers/net/wireless/ath/ath11k/peer.c
120+
@@ -457,8 +457,8 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
121+
goto exit;
122+
}
123+
124+
- if (peer->peer_logging_enabled)
125+
- ath11k_dbg(ab, ATH11K_DBG_PEER, "peer unmap vdev %d peer %pM id %d\n",
126+
+// if (peer->peer_logging_enabled)
127+
+ ath11k_warn(ab, "peer unmap vdev %d peer %pM id %d\n",
128+
peer->vdev_id, peer->addr, peer_id);
129+
130+
/* Don't decrement num_peers here - it's already decremented in
131+
@@ -466,6 +466,7 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
132+
*/
133+
list_del(&peer->list);
134+
kfree(peer);
135+
+ ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
136+
wake_up(&ab->peer_mapping_wq);
137+
138+
exit:
139+
@@ -617,7 +618,14 @@ void ath11k_peer_map_v2_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
140+
peer_free:
141+
spin_unlock_bh(&ab->base_lock);
142+
mutex_lock(&ar->conf_mutex);
143+
- ath11k_peer_delete(ar, vdev_id, mac_addr);
144+
+ ret = ath11k_peer_delete(ar, vdev_id, mac_addr);
145+
+ if (ret)
146+
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
147+
+ mac_addr, vdev_id);
148+
+ else
149+
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
150+
+ mac_addr, vdev_id);
151+
+
152+
mutex_unlock(&ar->conf_mutex);
153+
exit:
154+
rcu_read_unlock();
155+
@@ -893,9 +901,16 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
156+
list_del(&peer->list);
157+
kfree(peer);
158+
ar->num_peers--;
159+
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
160+
+ ath11k_warn(ar->ab,
161+
"%s peer deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
162+
__func__, addr, vdev_id, ar->num_peers);
163+
+ } else {
164+
+ // Peer already deleted
165+
+ // Who deleted it? Firmware unmap event after the timeout?
166+
+ ar->num_peers--;
167+
+ ath11k_warn(ar->ab,
168+
+ "%s peer already deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
169+
+ __func__, addr, vdev_id, ar->num_peers);
170+
}
171+
spin_unlock_bh(&ar->ab->base_lock);
172+
mutex_unlock(&ar->ab->tbl_mtx_lock);
173+
@@ -911,13 +926,13 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
174+
list_del(&peer->list);
175+
kfree(peer);
176+
ar->num_peers--;
177+
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
178+
+ ath11k_warn(ar->ab,
179+
"%s peer deleted (no unmap event) %pM vdev_id: %d num_peers: %d\n",
180+
__func__, addr, vdev_id, ar->num_peers);
181+
} else {
182+
/* Peer already removed by unmap event - still need to decrement */
183+
ar->num_peers--;
184+
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
185+
+ ath11k_warn(ar->ab,
186+
"%s peer deleted (via unmap event) %pM vdev_id: %d num_peers: %d\n",
187+
__func__, addr, vdev_id, ar->num_peers);
188+
}
189+
@@ -933,6 +948,31 @@ static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8
190+
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
191+
}
192+
193+
+static int ath11k_get_peer_count(struct rhashtable *ht)
194+
+{
195+
+ struct rhashtable_iter iter;
196+
+ struct rhash_head *pos;
197+
+ int count = 0;
198+
+
199+
+ rhashtable_walk_enter(ht, &iter);
200+
+ rhashtable_walk_start(&iter);
201+
+
202+
+ while ((pos = rhashtable_walk_next(&iter))) {
203+
+ if (IS_ERR(pos)) {
204+
+ if (PTR_ERR(pos) == -EAGAIN)
205+
+ continue; // retry due to resize
206+
+ break; // some other error
207+
+ }
208+
+ count++;
209+
+ }
210+
+
211+
+ rhashtable_walk_stop(&iter);
212+
+ rhashtable_walk_exit(&iter);
213+
+
214+
+ return count;
215+
+}
216+
+
217+
+
218+
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
219+
struct ieee80211_sta *sta, struct peer_create_params *param)
220+
{
221+
@@ -941,13 +981,37 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
222+
struct ath11k_sta *arsta;
223+
int ret, fbret;
224+
u8 vdev_id = 0;
225+
+ int rhash_count;
226+
227+
lockdep_assert_held(&ar->conf_mutex);
228+
229+
- if (ar->num_peers > (ar->max_num_peers - 1)) {
230+
+ mutex_lock(&ar->ab->tbl_mtx_lock);
231+
+ spin_lock_bh(&ar->ab->base_lock);
232+
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
233+
+ spin_unlock_bh(&ar->ab->base_lock);
234+
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
235+
+ ath11k_warn(ar->ab, "address = %pM rhash_count = %d ar->num_peers = %d "
236+
+ "ar->max_num_peers = %d ar->num_stations = %d\n", param->peer_addr, rhash_count, ar->num_peers, ar->max_num_peers, ar->num_stations);
237+
+ // Check for peer count desynchronization
238+
+ // If num_peers is negative or exceeds max_num_peers -1, recalculate from rhashtable
239+
+ if ((ar->num_peers < 0) || (ar->num_peers > (ar->max_num_peers - 1))) {
240+
+ // This can happen if rhash table and num_peers get out of sync
241+
+ // e.g. during peer delete for some unknown reason
242+
+ // Recalculate num_peers from rhash table
243+
ath11k_warn(ar->ab,
244+
- "failed to create peer due to insufficient peer entry resource in firmware\n");
245+
- return -ENOBUFS;
246+
+ "failed to create peer due to insufficient peer entry resource in firmware ar->num_peers = %d "
247+
+ "ar->max_num_peers = %d ar->num_stations = %d\n", ar->num_peers, ar->max_num_peers, ar->num_stations);
248+
+ mutex_lock(&ar->ab->tbl_mtx_lock);
249+
+ spin_lock_bh(&ar->ab->base_lock);
250+
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
251+
+ spin_unlock_bh(&ar->ab->base_lock);
252+
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
253+
+ if (rhash_count > ar->max_num_peers -1 ) {
254+
+ ath11k_warn(ar->ab,
255+
+ "rhash_count %d exceeds max_num_peers %d\n", rhash_count, ar->max_num_peers);
256+
+ return -ENOBUFS;
257+
+ }
258+
+ ar->num_peers = rhash_count;
259+
}
260+
261+
mutex_lock(&ar->ab->tbl_mtx_lock);
262+
--
263+
2.34.1
264+

0 commit comments

Comments
 (0)