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 <venkat@nearhop.com>
This commit is contained in:
Venkat Chimata
2025-11-25 20:36:30 +05:30
parent 50eee0ef3c
commit a3ac7deced

View File

@@ -0,0 +1,264 @@
From 625b8692332ee44e514be88400646e900710644b Mon Sep 17 00:00:00 2001
From: Venkat Chimata <venkat@nearhop.com>
Date: Tue, 25 Nov 2025 20:34:34 +0530
Subject: [PATCH] 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 <venkat@nearhop.com>
---
drivers/net/wireless/ath/ath11k/mac.c | 39 ++++++++----
drivers/net/wireless/ath/ath11k/peer.c | 82 +++++++++++++++++++++++---
2 files changed, 102 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index f300c4f..a3eeac8 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -5383,6 +5383,8 @@ static int ath11k_mac_station_add(struct ath11k *ar,
peer_param.peer_addr = sta->addr;
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
+ sta->addr, arvif->vdev_id);
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
if (ret) {
ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
@@ -5457,7 +5459,13 @@ free_tx_stats:
kfree(arsta->wbm_tx_stats);
arsta->wbm_tx_stats = NULL;
free_peer:
- ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ if (ret)
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
+ sta->addr, arvif->vdev_id);
+ else
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
+ sta->addr, arvif->vdev_id);
free_rx_stats:
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
@@ -5735,18 +5743,15 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
else
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "Removed peer: %pM for VDEV: %d\n",
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
sta->addr, arvif->vdev_id);
ath11k_mac_dec_num_stations(arvif, sta);
mutex_lock(&ar->ab->tbl_mtx_lock);
spin_lock_bh(&ar->ab->base_lock);
peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
- /* Skip if peer deletion already in progress to prevent
- * double-delete and num_peers underflow
- */
- if (peer && peer->sta == sta && !peer->delete_in_progress) {
- ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
+ if (peer && peer->sta == sta) {
+ ath11k_warn(ar->ab, "%s: Found peer entry %pM n vdev %i after it was supposedly removed\n", __func__,
vif->addr, arvif->vdev_id);
ath11k_peer_rhash_delete(ar->ab, peer);
peer->sta = NULL;
@@ -7746,6 +7751,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
peer_param.vdev_id = arvif->vdev_id;
peer_param.peer_addr = vif->addr;
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
+ vif->addr, arvif->vdev_id);
ret = ath11k_peer_create(ar, arvif, NULL, &peer_param);
if (ret) {
ath11k_warn(ab, "failed to vdev %d create peer for AP: %d\n",
@@ -7947,8 +7954,11 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
if (ret)
- ath11k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
+ ath11k_warn(ab, "%s: failed to submit AP self-peer removal on vdev %d: %d\n", __func__,
arvif->vdev_id, ret);
+ else
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
+ vif->addr, arvif->vdev_id);
list_for_each_entry_safe(ap_vlan_arvif, tmp, &arvif->ap_vlan_arvifs,
list) {
@@ -9305,6 +9315,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
param.peer_type = WMI_PEER_TYPE_DEFAULT;
param.peer_addr = ar->mac_addr;
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
+ ar->mac_addr, arvif->vdev_id);
ret = ath11k_peer_create(ar, arvif, NULL, &param);
if (ret) {
ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
@@ -9380,8 +9392,15 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (ab->hw_params.vdev_start_delay &&
arvif->vdev_type == WMI_VDEV_TYPE_MONITOR &&
- ath11k_peer_find_by_addr(ab, ar->mac_addr))
- ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
+ ath11k_peer_find_by_addr(ab, ar->mac_addr)) {
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
+ if (ret)
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
+ ar->mac_addr, arvif->vdev_id);
+ else
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
+ ar->mac_addr, arvif->vdev_id);
+ }
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ret = ath11k_mac_monitor_stop(ar);
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
index 877ea30..9ec297f 100644
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -457,8 +457,8 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
goto exit;
}
- if (peer->peer_logging_enabled)
- ath11k_dbg(ab, ATH11K_DBG_PEER, "peer unmap vdev %d peer %pM id %d\n",
+// if (peer->peer_logging_enabled)
+ ath11k_warn(ab, "peer unmap vdev %d peer %pM id %d\n",
peer->vdev_id, peer->addr, peer_id);
/* Don't decrement num_peers here - it's already decremented in
@@ -466,6 +466,7 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
*/
list_del(&peer->list);
kfree(peer);
+ ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
wake_up(&ab->peer_mapping_wq);
exit:
@@ -617,7 +618,14 @@ void ath11k_peer_map_v2_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
peer_free:
spin_unlock_bh(&ab->base_lock);
mutex_lock(&ar->conf_mutex);
- ath11k_peer_delete(ar, vdev_id, mac_addr);
+ ret = ath11k_peer_delete(ar, vdev_id, mac_addr);
+ if (ret)
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
+ mac_addr, vdev_id);
+ else
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
+ mac_addr, vdev_id);
+
mutex_unlock(&ar->conf_mutex);
exit:
rcu_read_unlock();
@@ -893,9 +901,16 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
list_del(&peer->list);
kfree(peer);
ar->num_peers--;
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
+ ath11k_warn(ar->ab,
"%s peer deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
__func__, addr, vdev_id, ar->num_peers);
+ } else {
+ // Peer already deleted
+ // Who deleted it? Firmware unmap event after the timeout?
+ ar->num_peers--;
+ ath11k_warn(ar->ab,
+ "%s peer already deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
+ __func__, addr, vdev_id, ar->num_peers);
}
spin_unlock_bh(&ar->ab->base_lock);
mutex_unlock(&ar->ab->tbl_mtx_lock);
@@ -911,13 +926,13 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
list_del(&peer->list);
kfree(peer);
ar->num_peers--;
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
+ ath11k_warn(ar->ab,
"%s peer deleted (no unmap event) %pM vdev_id: %d num_peers: %d\n",
__func__, addr, vdev_id, ar->num_peers);
} else {
/* Peer already removed by unmap event - still need to decrement */
ar->num_peers--;
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
+ ath11k_warn(ar->ab,
"%s peer deleted (via unmap event) %pM vdev_id: %d num_peers: %d\n",
__func__, addr, vdev_id, ar->num_peers);
}
@@ -933,6 +948,31 @@ static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
}
+static int ath11k_get_peer_count(struct rhashtable *ht)
+{
+ struct rhashtable_iter iter;
+ struct rhash_head *pos;
+ int count = 0;
+
+ rhashtable_walk_enter(ht, &iter);
+ rhashtable_walk_start(&iter);
+
+ while ((pos = rhashtable_walk_next(&iter))) {
+ if (IS_ERR(pos)) {
+ if (PTR_ERR(pos) == -EAGAIN)
+ continue; // retry due to resize
+ break; // some other error
+ }
+ count++;
+ }
+
+ rhashtable_walk_stop(&iter);
+ rhashtable_walk_exit(&iter);
+
+ return count;
+}
+
+
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
struct ieee80211_sta *sta, struct peer_create_params *param)
{
@@ -941,13 +981,37 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
struct ath11k_sta *arsta;
int ret, fbret;
u8 vdev_id = 0;
+ int rhash_count;
lockdep_assert_held(&ar->conf_mutex);
- if (ar->num_peers > (ar->max_num_peers - 1)) {
+ mutex_lock(&ar->ab->tbl_mtx_lock);
+ spin_lock_bh(&ar->ab->base_lock);
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
+ spin_unlock_bh(&ar->ab->base_lock);
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
+ ath11k_warn(ar->ab, "address = %pM rhash_count = %d ar->num_peers = %d "
+ "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);
+ // Check for peer count desynchronization
+ // If num_peers is negative or exceeds max_num_peers -1, recalculate from rhashtable
+ if ((ar->num_peers < 0) || (ar->num_peers > (ar->max_num_peers - 1))) {
+ // This can happen if rhash table and num_peers get out of sync
+ // e.g. during peer delete for some unknown reason
+ // Recalculate num_peers from rhash table
ath11k_warn(ar->ab,
- "failed to create peer due to insufficient peer entry resource in firmware\n");
- return -ENOBUFS;
+ "failed to create peer due to insufficient peer entry resource in firmware ar->num_peers = %d "
+ "ar->max_num_peers = %d ar->num_stations = %d\n", ar->num_peers, ar->max_num_peers, ar->num_stations);
+ mutex_lock(&ar->ab->tbl_mtx_lock);
+ spin_lock_bh(&ar->ab->base_lock);
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
+ spin_unlock_bh(&ar->ab->base_lock);
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
+ if (rhash_count > ar->max_num_peers -1 ) {
+ ath11k_warn(ar->ab,
+ "rhash_count %d exceeds max_num_peers %d\n", rhash_count, ar->max_num_peers);
+ return -ENOBUFS;
+ }
+ ar->num_peers = rhash_count;
}
mutex_lock(&ar->ab->tbl_mtx_lock);
--
2.34.1