xref: /linux/drivers/net/wireless/ath/ath12k/dp_peer.c (revision fab183d632628381b466a41479489541ac0e29a0)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5  */
6 
7 #include "core.h"
8 #include "dp_peer.h"
9 #include "debug.h"
10 #include "debugfs.h"
11 
ath12k_dp_link_peer_free(struct ath12k_dp_link_peer * peer)12 void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer)
13 {
14 	list_del(&peer->list);
15 
16 	kfree(peer->peer_stats.rx_stats);
17 	kfree(peer);
18 }
19 
20 struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp * dp,int vdev_id,const u8 * addr)21 ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp *dp,
22 					  int vdev_id, const u8 *addr)
23 {
24 	struct ath12k_dp_link_peer *peer;
25 
26 	lockdep_assert_held(&dp->dp_lock);
27 
28 	list_for_each_entry(peer, &dp->peers, list) {
29 		if (peer->vdev_id != vdev_id)
30 			continue;
31 		if (!ether_addr_equal(peer->addr, addr))
32 			continue;
33 
34 		return peer;
35 	}
36 
37 	return NULL;
38 }
39 
40 struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp * dp,u8 pdev_idx,const u8 * addr)41 ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx,
42 					  const u8 *addr)
43 {
44 	struct ath12k_dp_link_peer *peer;
45 
46 	lockdep_assert_held(&dp->dp_lock);
47 
48 	list_for_each_entry(peer, &dp->peers, list) {
49 		if (peer->pdev_idx != pdev_idx)
50 			continue;
51 		if (!ether_addr_equal(peer->addr, addr))
52 			continue;
53 
54 		return peer;
55 	}
56 
57 	return NULL;
58 }
59 
60 struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_addr(struct ath12k_dp * dp,const u8 * addr)61 ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr)
62 {
63 	lockdep_assert_held(&dp->dp_lock);
64 
65 	return rhashtable_lookup_fast(dp->rhead_peer_addr, addr,
66 				      dp->rhash_peer_addr_param);
67 }
68 EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_addr);
69 
70 static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp * dp,int ml_peer_id)71 ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp *dp, int ml_peer_id)
72 {
73 	struct ath12k_dp_link_peer *peer;
74 
75 	lockdep_assert_held(&dp->dp_lock);
76 
77 	list_for_each_entry(peer, &dp->peers, list)
78 		if (ml_peer_id == peer->ml_id)
79 			return peer;
80 
81 	return NULL;
82 }
83 
84 static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_search_by_id(struct ath12k_dp * dp,int peer_id)85 ath12k_dp_link_peer_search_by_id(struct ath12k_dp *dp, int peer_id)
86 {
87 	struct ath12k_dp_link_peer *peer;
88 
89 	lockdep_assert_held(&dp->dp_lock);
90 
91 	if (peer_id == HAL_INVALID_PEERID)
92 		return NULL;
93 
94 	if (peer_id & ATH12K_PEER_ML_ID_VALID)
95 		return ath12k_dp_link_peer_find_by_ml_id(dp, peer_id);
96 
97 	list_for_each_entry(peer, &dp->peers, list)
98 		if (peer_id == peer->peer_id)
99 			return peer;
100 
101 	return NULL;
102 }
103 
ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp * dp,int vdev_id)104 bool ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp *dp, int vdev_id)
105 {
106 	struct ath12k_dp_link_peer *peer;
107 
108 	spin_lock_bh(&dp->dp_lock);
109 
110 	list_for_each_entry(peer, &dp->peers, list) {
111 		if (vdev_id == peer->vdev_id) {
112 			spin_unlock_bh(&dp->dp_lock);
113 			return true;
114 		}
115 	}
116 	spin_unlock_bh(&dp->dp_lock);
117 	return false;
118 }
119 
120 struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ast(struct ath12k_dp * dp,int ast_hash)121 ath12k_dp_link_peer_find_by_ast(struct ath12k_dp *dp, int ast_hash)
122 {
123 	struct ath12k_dp_link_peer *peer;
124 
125 	lockdep_assert_held(&dp->dp_lock);
126 
127 	list_for_each_entry(peer, &dp->peers, list)
128 		if (ast_hash == peer->ast_hash)
129 			return peer;
130 
131 	return NULL;
132 }
133 
ath12k_dp_link_peer_unmap_event(struct ath12k_base * ab,u16 peer_id)134 void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id)
135 {
136 	struct ath12k_dp_link_peer *peer;
137 	struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
138 
139 	spin_lock_bh(&dp->dp_lock);
140 
141 	peer = ath12k_dp_link_peer_search_by_id(dp, peer_id);
142 	if (!peer) {
143 		ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
144 			    peer_id);
145 		goto exit;
146 	}
147 
148 	ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
149 		   peer->vdev_id, peer->addr, peer_id);
150 
151 	ath12k_dp_link_peer_free(peer);
152 	wake_up(&ab->peer_mapping_wq);
153 
154 exit:
155 	spin_unlock_bh(&dp->dp_lock);
156 }
157 
ath12k_dp_link_peer_map_event(struct ath12k_base * ab,u8 vdev_id,u16 peer_id,u8 * mac_addr,u16 ast_hash,u16 hw_peer_id)158 void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
159 				   u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
160 {
161 	struct ath12k_dp_link_peer *peer;
162 	struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
163 	struct ath12k *ar;
164 
165 	spin_lock_bh(&dp->dp_lock);
166 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
167 	if (!peer) {
168 		peer = kzalloc_obj(*peer, GFP_ATOMIC);
169 		if (!peer)
170 			goto exit;
171 
172 		peer->vdev_id = vdev_id;
173 		peer->peer_id = peer_id;
174 		peer->ast_hash = ast_hash;
175 		peer->hw_peer_id = hw_peer_id;
176 		ether_addr_copy(peer->addr, mac_addr);
177 
178 		rcu_read_lock();
179 		ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
180 		if (ar && ath12k_debugfs_is_extd_rx_stats_enabled(ar) &&
181 		    !peer->peer_stats.rx_stats) {
182 			peer->peer_stats.rx_stats = kzalloc_obj(*peer->peer_stats.rx_stats,
183 								GFP_ATOMIC);
184 		}
185 		rcu_read_unlock();
186 
187 		list_add(&peer->list, &dp->peers);
188 		wake_up(&ab->peer_mapping_wq);
189 		ewma_avg_rssi_init(&peer->avg_rssi);
190 	}
191 	ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
192 		   vdev_id, mac_addr, peer_id);
193 
194 exit:
195 	spin_unlock_bh(&dp->dp_lock);
196 }
197 
ath12k_dp_link_peer_to_link_sta(struct ath12k_base * ab,struct ath12k_dp_link_peer * peer)198 struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab,
199 							struct ath12k_dp_link_peer *peer)
200 {
201 	struct ath12k_sta *ahsta;
202 	struct ath12k_link_sta *arsta;
203 
204 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
205 			 "ath12k_dp_link_peer to ath12k_link_sta called without rcu lock");
206 
207 	if (!peer->sta)
208 		return NULL;
209 
210 	ahsta = ath12k_sta_to_ahsta(peer->sta);
211 	if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) {
212 		if (!(ahsta->links_map & BIT(peer->link_id))) {
213 			ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n",
214 				    peer->addr, peer->peer_id, peer->link_id,
215 				    ahsta->links_map);
216 			return NULL;
217 		}
218 		arsta = rcu_dereference(ahsta->link[peer->link_id]);
219 		if (!arsta)
220 			return NULL;
221 	} else {
222 		arsta =  &ahsta->deflink;
223 	}
224 	return arsta;
225 }
226 
ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp * dp)227 static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp)
228 {
229 	struct ath12k_base *ab = dp->ab;
230 	struct rhashtable_params *param;
231 	struct rhashtable *rhash_addr_tbl;
232 	int ret;
233 
234 	lockdep_assert_held(&dp->link_peer_rhash_tbl_lock);
235 
236 	rhash_addr_tbl = kzalloc_obj(*dp->rhead_peer_addr);
237 	if (!rhash_addr_tbl)
238 		return -ENOMEM;
239 
240 	param = &dp->rhash_peer_addr_param;
241 
242 	param->key_offset = offsetof(struct ath12k_dp_link_peer, addr);
243 	param->head_offset = offsetof(struct ath12k_dp_link_peer, rhash_addr);
244 	param->key_len = sizeof_field(struct ath12k_dp_link_peer, addr);
245 	param->automatic_shrinking = true;
246 	param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab);
247 
248 	ret = rhashtable_init(rhash_addr_tbl, param);
249 	if (ret) {
250 		ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
251 		goto err_free;
252 	}
253 
254 	dp->rhead_peer_addr = rhash_addr_tbl;
255 
256 	return 0;
257 
258 err_free:
259 	kfree(rhash_addr_tbl);
260 
261 	return ret;
262 }
263 
ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp * dp)264 int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp)
265 {
266 	int ret;
267 
268 	mutex_lock(&dp->link_peer_rhash_tbl_lock);
269 	ret = ath12k_dp_link_peer_rhash_addr_tbl_init(dp);
270 	mutex_unlock(&dp->link_peer_rhash_tbl_lock);
271 
272 	return ret;
273 }
274 
ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp * dp)275 void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp)
276 {
277 	guard(mutex)(&dp->link_peer_rhash_tbl_lock);
278 
279 	if (!dp->rhead_peer_addr)
280 		return;
281 
282 	rhashtable_destroy(dp->rhead_peer_addr);
283 	kfree(dp->rhead_peer_addr);
284 	dp->rhead_peer_addr = NULL;
285 }
286 
ath12k_dp_link_peer_rhash_insert(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)287 static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
288 					    struct ath12k_dp_link_peer *peer)
289 {
290 	struct ath12k_dp_link_peer *tmp;
291 
292 	lockdep_assert_held(&dp->dp_lock);
293 
294 	tmp = rhashtable_lookup_get_insert_fast(dp->rhead_peer_addr, &peer->rhash_addr,
295 						dp->rhash_peer_addr_param);
296 	if (!tmp)
297 		return 0;
298 	else if (IS_ERR(tmp))
299 		return PTR_ERR(tmp);
300 	else
301 		return -EEXIST;
302 }
303 
ath12k_dp_link_peer_rhash_remove(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)304 static int ath12k_dp_link_peer_rhash_remove(struct ath12k_dp *dp,
305 					    struct ath12k_dp_link_peer *peer)
306 {
307 	int ret;
308 
309 	lockdep_assert_held(&dp->dp_lock);
310 
311 	ret = rhashtable_remove_fast(dp->rhead_peer_addr, &peer->rhash_addr,
312 				     dp->rhash_peer_addr_param);
313 	if (ret && ret != -ENOENT)
314 		return ret;
315 
316 	return 0;
317 }
318 
ath12k_dp_link_peer_rhash_add(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)319 int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp,
320 				  struct ath12k_dp_link_peer *peer)
321 {
322 	int ret;
323 
324 	lockdep_assert_held(&dp->dp_lock);
325 
326 	ret = ath12k_dp_link_peer_rhash_insert(dp, peer);
327 	if (ret)
328 		ath12k_warn(dp, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
329 			    peer->addr, peer->peer_id, ret);
330 
331 	return ret;
332 }
333 
ath12k_dp_link_peer_rhash_delete(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)334 void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp,
335 				      struct ath12k_dp_link_peer *peer)
336 {
337 	/* No failure handling and hence return type is void */
338 	int ret;
339 
340 	lockdep_assert_held(&dp->dp_lock);
341 
342 	ret = ath12k_dp_link_peer_rhash_remove(dp, peer);
343 	if (ret)
344 		ath12k_warn(dp, "failed to remove peer %pM with id %d in rhash_addr ret %d\n",
345 			    peer->addr, peer->peer_id, ret);
346 }
347 
ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw * dp_hw,u8 * addr)348 struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw *dp_hw, u8 *addr)
349 {
350 	struct ath12k_dp_peer *peer;
351 
352 	lockdep_assert_held(&dp_hw->peer_lock);
353 
354 	list_for_each_entry(peer, &dp_hw->dp_peers_list, list) {
355 		if (ether_addr_equal(peer->addr, addr))
356 			return peer;
357 	}
358 
359 	return NULL;
360 }
361 EXPORT_SYMBOL(ath12k_dp_peer_find_by_addr);
362 
ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta)363 struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw *dp_hw,
364 							   u8 *addr,
365 							   struct ieee80211_sta *sta)
366 {
367 	struct ath12k_dp_peer *dp_peer;
368 
369 	lockdep_assert_held(&dp_hw->peer_lock);
370 
371 	list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
372 		if (ether_addr_equal(dp_peer->addr, addr) && (dp_peer->sta == sta))
373 			return dp_peer;
374 	}
375 
376 	return NULL;
377 }
378 
ath12k_dp_peer_create_find(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta,bool mlo_peer)379 static struct ath12k_dp_peer *ath12k_dp_peer_create_find(struct ath12k_dp_hw *dp_hw,
380 							 u8 *addr,
381 							 struct ieee80211_sta *sta,
382 							 bool mlo_peer)
383 {
384 	struct ath12k_dp_peer *dp_peer;
385 
386 	lockdep_assert_held(&dp_hw->peer_lock);
387 
388 	list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
389 		if (ether_addr_equal(dp_peer->addr, addr)) {
390 			if (!sta || mlo_peer || dp_peer->is_mlo ||
391 			    dp_peer->sta == sta)
392 				return dp_peer;
393 		}
394 	}
395 
396 	return NULL;
397 }
398 
399 /*
400  * Index of ath12k_dp_peer for MLO client is same as peer id of ath12k_dp_peer,
401  * while for ath12k_dp_link_peer(mlo and non-mlo) and ath12k_dp_peer for
402  * Non-MLO client it is derived as ((DEVICE_ID << 10) | (10 bits of peer id)).
403  *
404  * This is done because ml_peer_id and peer_id_table are at hw granularity,
405  * while link_peer_id is at device granularity, hence in order to avoid
406  * conflict this approach is followed.
407  */
408 #define ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT        10
409 
ath12k_dp_peer_get_peerid_index(struct ath12k_dp * dp,u16 peer_id)410 u16 ath12k_dp_peer_get_peerid_index(struct ath12k_dp *dp, u16 peer_id)
411 {
412 	return (peer_id & ATH12K_PEER_ML_ID_VALID) ? peer_id :
413 		((dp->device_id << ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT) | peer_id);
414 }
415 
ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp * dp_pdev,u16 peer_id)416 struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev,
417 						     u16 peer_id)
418 {
419 	u16 index;
420 	struct ath12k_dp *dp = dp_pdev->dp;
421 
422 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
423 			 "ath12k dp peer find by peerid index called without rcu lock");
424 
425 	if (peer_id >= ATH12K_DP_PEER_ID_INVALID)
426 		return NULL;
427 
428 	index = ath12k_dp_peer_get_peerid_index(dp, peer_id);
429 
430 	return rcu_dereference(dp_pdev->dp_hw->dp_peers[index]);
431 }
432 EXPORT_SYMBOL(ath12k_dp_peer_find_by_peerid);
433 
434 struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp * dp_pdev,u16 peer_id)435 ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id)
436 {
437 	struct ath12k_dp_peer *dp_peer = NULL;
438 	u8 link_id;
439 
440 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
441 			 "ath12k dp link peer find by peerid index called without rcu lock");
442 
443 	if (dp_pdev->hw_link_id >= ATH12K_GROUP_MAX_RADIO)
444 		return NULL;
445 
446 	dp_peer = ath12k_dp_peer_find_by_peerid(dp_pdev, peer_id);
447 	if (!dp_peer)
448 		return NULL;
449 
450 	link_id = dp_peer->hw_links[dp_pdev->hw_link_id];
451 
452 	return rcu_dereference(dp_peer->link_peers[link_id]);
453 }
454 EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_peerid);
455 
ath12k_dp_peer_create(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ath12k_dp_peer_create_params * params)456 int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
457 			  struct ath12k_dp_peer_create_params *params)
458 {
459 	struct ath12k_dp_peer *dp_peer;
460 
461 	spin_lock_bh(&dp_hw->peer_lock);
462 	dp_peer = ath12k_dp_peer_create_find(dp_hw, addr, params->sta, params->is_mlo);
463 	if (dp_peer) {
464 		spin_unlock_bh(&dp_hw->peer_lock);
465 		return -EEXIST;
466 	}
467 	spin_unlock_bh(&dp_hw->peer_lock);
468 
469 	dp_peer = kzalloc_obj(*dp_peer, GFP_ATOMIC);
470 	if (!dp_peer)
471 		return -ENOMEM;
472 
473 	ether_addr_copy(dp_peer->addr, addr);
474 	dp_peer->sta = params->sta;
475 	dp_peer->is_mlo = params->is_mlo;
476 
477 	/*
478 	 * For MLO client, the ML peer ID, either known or PENDING, needs to be
479 	 * initialized here since the following logic depends on it.
480 	 *
481 	 * For non-MLO client, host gets link peer ID from firmware and will be
482 	 * assigned at the time of link peer creation
483 	 */
484 	dp_peer->peer_id = params->is_mlo ? params->peer_id : ATH12K_DP_PEER_ID_INVALID;
485 	dp_peer->ucast_ra_only = params->ucast_ra_only;
486 
487 	dp_peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
488 	dp_peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
489 	dp_peer->ucast_ra_only = params->ucast_ra_only;
490 
491 	spin_lock_bh(&dp_hw->peer_lock);
492 
493 	list_add(&dp_peer->list, &dp_hw->dp_peers_list);
494 
495 	/*
496 	 * For an MLO client whose ML peer ID is allocated by the host, the
497 	 * peer_id is known here and the dp_peer can be added to the RCU
498 	 * table using it. For an MLO client on chips where the firmware
499 	 * allocates the ID, peer_id is ATH12K_MLO_PEER_ID_PENDING and the
500 	 * RCU table publish is deferred to the
501 	 * HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For a non-MLO client
502 	 * the publish happens later, at the time of assignment of
503 	 * ath12k_dp_link_peer to ath12k_dp_peer.
504 	 */
505 	if (dp_peer->is_mlo &&
506 	    dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
507 		rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
508 
509 	spin_unlock_bh(&dp_hw->peer_lock);
510 
511 	return 0;
512 }
513 
ath12k_dp_peer_delete(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta)514 void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
515 			   struct ieee80211_sta *sta)
516 {
517 	struct ath12k_dp_peer *dp_peer;
518 
519 	spin_lock_bh(&dp_hw->peer_lock);
520 
521 	dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, addr, sta);
522 	if (!dp_peer) {
523 		spin_unlock_bh(&dp_hw->peer_lock);
524 		return;
525 	}
526 
527 	if (dp_peer->is_mlo &&
528 	    dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
529 		rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
530 
531 	list_del(&dp_peer->list);
532 
533 	spin_unlock_bh(&dp_hw->peer_lock);
534 
535 	synchronize_rcu();
536 	kfree(dp_peer);
537 }
538 
ath12k_dp_link_peer_assign(struct ath12k_dp * dp,struct ath12k_dp_hw * dp_hw,u8 vdev_id,struct ieee80211_sta * sta,u8 * addr,u8 link_id,u32 hw_link_id)539 int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
540 			       u8 vdev_id, struct ieee80211_sta *sta, u8 *addr,
541 			       u8 link_id, u32 hw_link_id)
542 {
543 	struct ath12k_dp_peer *dp_peer;
544 	struct ath12k_dp_link_peer *peer, *temp_peer;
545 	u16 peerid_index;
546 	int ret = -EINVAL;
547 	u8 *dp_peer_mac = !sta ? addr : sta->addr;
548 
549 	spin_lock_bh(&dp->dp_lock);
550 
551 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
552 	if (!peer) {
553 		ath12k_warn(dp, "failed to find dp_link_peer with mac %pM on vdev %u\n",
554 			    addr, vdev_id);
555 		ret = -ENOENT;
556 		goto err_peer;
557 	}
558 
559 	spin_lock_bh(&dp_hw->peer_lock);
560 
561 	dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, dp_peer_mac, sta);
562 	if (!dp_peer) {
563 		ath12k_warn(dp, "failed to find dp_peer with mac %pM\n", dp_peer_mac);
564 		ret = -ENOENT;
565 		goto err_dp_peer;
566 	}
567 
568 	/*
569 	 * Set peer_id in dp_peer for non-mlo client, peer_id for mlo client is
570 	 * set during dp_peer create
571 	 */
572 	if (!dp_peer->is_mlo)
573 		dp_peer->peer_id = peer->peer_id;
574 
575 	peer->dp_peer = dp_peer;
576 	peer->hw_link_id = hw_link_id;
577 
578 	dp_peer->hw_links[peer->hw_link_id] = link_id;
579 
580 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
581 
582 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
583 	WRITE_ONCE(dp_peer->link_peers_map,
584 		   READ_ONCE(dp_peer->link_peers_map) | BIT(peer->link_id));
585 
586 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
587 
588 	spin_unlock_bh(&dp_hw->peer_lock);
589 
590 	/*
591 	 * In case of Split PHY and roaming scenario, pdev idx
592 	 * might differ but both the pdev will share same rhash
593 	 * table. In that case update the rhash table if link_peer is
594 	 * already present
595 	 */
596 	temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
597 	if (temp_peer && temp_peer->hw_link_id != hw_link_id)
598 		ath12k_dp_link_peer_rhash_delete(dp, temp_peer);
599 
600 	ret = ath12k_dp_link_peer_rhash_add(dp, peer);
601 	if (ret) {
602 		/*
603 		 * If new entry addition failed, add back old entry
604 		 * If old entry addition also fails, then nothing
605 		 * can be done, simply proceed
606 		 */
607 		if (temp_peer)
608 			ath12k_dp_link_peer_rhash_add(dp, temp_peer);
609 	}
610 
611 	spin_unlock_bh(&dp->dp_lock);
612 
613 	return ret;
614 
615 err_dp_peer:
616 	spin_unlock_bh(&dp_hw->peer_lock);
617 
618 err_peer:
619 	spin_unlock_bh(&dp->dp_lock);
620 
621 	return ret;
622 }
623 
ath12k_dp_link_peer_unassign(struct ath12k_dp * dp,struct ath12k_dp_hw * dp_hw,u8 vdev_id,u8 * addr,u32 hw_link_id)624 void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
625 				  u8 vdev_id, u8 *addr, u32 hw_link_id)
626 {
627 	struct ath12k_dp_peer *dp_peer;
628 	struct ath12k_dp_link_peer *peer, *temp_peer;
629 	u16 peerid_index;
630 
631 	spin_lock_bh(&dp->dp_lock);
632 
633 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
634 	if (!peer || !peer->dp_peer) {
635 		spin_unlock_bh(&dp->dp_lock);
636 		return;
637 	}
638 
639 	spin_lock_bh(&dp_hw->peer_lock);
640 
641 	dp_peer = peer->dp_peer;
642 	dp_peer->hw_links[peer->hw_link_id] = 0;
643 
644 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
645 
646 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
647 	WRITE_ONCE(dp_peer->link_peers_map,
648 		   READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
649 
650 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
651 
652 	spin_unlock_bh(&dp_hw->peer_lock);
653 
654 	/* To handle roaming and split phy scenario */
655 	temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
656 	if (temp_peer && temp_peer->hw_link_id == hw_link_id)
657 		ath12k_dp_link_peer_rhash_delete(dp, peer);
658 
659 	spin_unlock_bh(&dp->dp_lock);
660 
661 	synchronize_rcu();
662 }
663 
664 void
ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp * dp,const u8 * addr,struct ath12k_dp_link_peer_rate_info * info)665 ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr,
666 					    struct ath12k_dp_link_peer_rate_info *info)
667 {
668 	struct ath12k_dp_link_peer *link_peer;
669 
670 	guard(spinlock_bh)(&dp->dp_lock);
671 
672 	link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
673 	if (!link_peer)
674 		return;
675 
676 	info->rx_duration = link_peer->rx_duration;
677 	info->tx_duration = link_peer->tx_duration;
678 	info->txrate.legacy = link_peer->txrate.legacy;
679 	info->txrate.mcs = link_peer->txrate.mcs;
680 	info->txrate.nss = link_peer->txrate.nss;
681 	info->txrate.bw = link_peer->txrate.bw;
682 	info->txrate.he_gi = link_peer->txrate.he_gi;
683 	info->txrate.he_dcm = link_peer->txrate.he_dcm;
684 	info->txrate.he_ru_alloc = link_peer->txrate.he_ru_alloc;
685 	info->txrate.flags = link_peer->txrate.flags;
686 	info->rssi_comb = link_peer->rssi_comb;
687 	info->signal_avg = ewma_avg_rssi_read(&link_peer->avg_rssi);
688 }
689 
ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp * dp,const u8 * addr)690 void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
691 {
692 	struct ath12k_rx_peer_stats *rx_stats;
693 	struct ath12k_dp_link_peer *link_peer;
694 
695 	guard(spinlock_bh)(&dp->dp_lock);
696 
697 	link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
698 	if (!link_peer || !link_peer->peer_stats.rx_stats)
699 		return;
700 
701 	rx_stats = link_peer->peer_stats.rx_stats;
702 	if (rx_stats)
703 		memset(rx_stats, 0, sizeof(*rx_stats));
704 }
705 
ath12k_dp_peer_fixup_peer_id(struct ath12k_base * ab,const u8 * peer_addr,u16 peer_id)706 int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab,
707 				 const u8 *peer_addr, u16 peer_id)
708 {
709 	struct ath12k_dp_link_peer *link_peer;
710 	struct ath12k_dp_peer *dp_peer = NULL;
711 	struct ath12k_hw_group *ag = ab->ag;
712 	struct ath12k_dp_hw *dp_hw = NULL;
713 	struct ath12k_hw *ah;
714 	int i;
715 
716 	if (peer_id >= (ATH12K_PEER_ML_ID_VALID | ATH12K_MAX_MLO_PEERS))
717 		return -EINVAL;
718 
719 	for (i = 0; i < ag->num_hw; i++) {
720 		ah = ag->ah[i];
721 		if (!ah)
722 			continue;
723 
724 		spin_lock_bh(&ah->dp_hw.peer_lock);
725 		dp_peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw,
726 						      (u8 *)peer_addr);
727 		if (dp_peer) {
728 			dp_hw = &ah->dp_hw;
729 			break;
730 		}
731 		spin_unlock_bh(&ah->dp_hw.peer_lock);
732 	}
733 
734 	if (!dp_peer)
735 		return -ENOENT;
736 
737 	/* dp_hw->peer_lock is held */
738 
739 	dp_peer->peer_id = peer_id;
740 	rcu_assign_pointer(dp_hw->dp_peers[peer_id], dp_peer);
741 
742 	for (i = 0; i < ATH12K_NUM_MAX_LINKS; i++) {
743 		link_peer = rcu_dereference_protected(dp_peer->link_peers[i],
744 						      lockdep_is_held(&dp_hw->peer_lock));
745 		if (link_peer)
746 			link_peer->ml_id = peer_id;
747 	}
748 
749 	ath12k_sta_to_ahsta(dp_peer->sta)->ml_peer_id = peer_id;
750 
751 	spin_unlock_bh(&dp_hw->peer_lock);
752 
753 	complete(&ah->peer_ml_id_done);
754 
755 	return 0;
756 }
757