From a3ac7deced8b87f8a14ebe07da43e7bd7d20719d Mon Sep 17 00:00:00 2001 From: Venkat Chimata Date: Tue, 25 Nov 2025 20:36:30 +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 --- ...103-This-is-a-work-in-progress-patch.patch | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 feeds/ipq807x_v5.4/mac80211/patches/pending/a-103-This-is-a-work-in-progress-patch.patch diff --git a/feeds/ipq807x_v5.4/mac80211/patches/pending/a-103-This-is-a-work-in-progress-patch.patch b/feeds/ipq807x_v5.4/mac80211/patches/pending/a-103-This-is-a-work-in-progress-patch.patch new file mode 100644 index 000000000..cd70fdcc7 --- /dev/null +++ b/feeds/ipq807x_v5.4/mac80211/patches/pending/a-103-This-is-a-work-in-progress-patch.patch @@ -0,0 +1,264 @@ +From 625b8692332ee44e514be88400646e900710644b Mon Sep 17 00:00:00 2001 +From: Venkat Chimata +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 +--- + 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, ¶m); + 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 +