|
| 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, ¶m); |
| 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