xref: /linux/drivers/net/wireless/ath/ath12k/dp_peer.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
107174dc9SHarsh Kumar Bijlani // SPDX-License-Identifier: BSD-3-Clause-Clear
207174dc9SHarsh Kumar Bijlani /*
307174dc9SHarsh Kumar Bijlani  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
407174dc9SHarsh Kumar Bijlani  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
507174dc9SHarsh Kumar Bijlani  */
607174dc9SHarsh Kumar Bijlani 
707174dc9SHarsh Kumar Bijlani #include "core.h"
807174dc9SHarsh Kumar Bijlani #include "dp_peer.h"
907174dc9SHarsh Kumar Bijlani #include "debug.h"
1035fcf4faSHarsh Kumar Bijlani #include "debugfs.h"
1107174dc9SHarsh Kumar Bijlani 
ath12k_dp_link_peer_free(struct ath12k_dp_link_peer * peer)1205774dffSPavankumar Nandeshwar void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer)
1305774dffSPavankumar Nandeshwar {
1405774dffSPavankumar Nandeshwar 	list_del(&peer->list);
1505774dffSPavankumar Nandeshwar 
1605774dffSPavankumar Nandeshwar 	kfree(peer->peer_stats.rx_stats);
1705774dffSPavankumar Nandeshwar 	kfree(peer);
1805774dffSPavankumar Nandeshwar }
1905774dffSPavankumar Nandeshwar 
209e0b56a3SHarsh Kumar Bijlani struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp * dp,int vdev_id,const u8 * addr)210cafe8ccSHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp *dp,
229e0b56a3SHarsh Kumar Bijlani 					  int vdev_id, const u8 *addr)
2307174dc9SHarsh Kumar Bijlani {
249e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
2507174dc9SHarsh Kumar Bijlani 
260cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
2707174dc9SHarsh Kumar Bijlani 
280cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list) {
2907174dc9SHarsh Kumar Bijlani 		if (peer->vdev_id != vdev_id)
3007174dc9SHarsh Kumar Bijlani 			continue;
3107174dc9SHarsh Kumar Bijlani 		if (!ether_addr_equal(peer->addr, addr))
3207174dc9SHarsh Kumar Bijlani 			continue;
3307174dc9SHarsh Kumar Bijlani 
3407174dc9SHarsh Kumar Bijlani 		return peer;
3507174dc9SHarsh Kumar Bijlani 	}
3607174dc9SHarsh Kumar Bijlani 
3707174dc9SHarsh Kumar Bijlani 	return NULL;
3807174dc9SHarsh Kumar Bijlani }
3907174dc9SHarsh Kumar Bijlani 
409e0b56a3SHarsh Kumar Bijlani struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp * dp,u8 pdev_idx,const u8 * addr)410cafe8ccSHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx,
429e0b56a3SHarsh Kumar Bijlani 					  const u8 *addr)
4307174dc9SHarsh Kumar Bijlani {
449e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
4507174dc9SHarsh Kumar Bijlani 
460cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
4707174dc9SHarsh Kumar Bijlani 
480cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list) {
4907174dc9SHarsh Kumar Bijlani 		if (peer->pdev_idx != pdev_idx)
5007174dc9SHarsh Kumar Bijlani 			continue;
5107174dc9SHarsh Kumar Bijlani 		if (!ether_addr_equal(peer->addr, addr))
5207174dc9SHarsh Kumar Bijlani 			continue;
5307174dc9SHarsh Kumar Bijlani 
5407174dc9SHarsh Kumar Bijlani 		return peer;
5507174dc9SHarsh Kumar Bijlani 	}
5607174dc9SHarsh Kumar Bijlani 
5707174dc9SHarsh Kumar Bijlani 	return NULL;
5807174dc9SHarsh Kumar Bijlani }
5907174dc9SHarsh Kumar Bijlani 
609e0b56a3SHarsh Kumar Bijlani struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_addr(struct ath12k_dp * dp,const u8 * addr)610cafe8ccSHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr)
6207174dc9SHarsh Kumar Bijlani {
630cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
6407174dc9SHarsh Kumar Bijlani 
65a88cf5f7SHarsh Kumar Bijlani 	return rhashtable_lookup_fast(dp->rhead_peer_addr, addr,
66a88cf5f7SHarsh Kumar Bijlani 				      dp->rhash_peer_addr_param);
6707174dc9SHarsh Kumar Bijlani }
689e0b56a3SHarsh Kumar Bijlani EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_addr);
6907174dc9SHarsh Kumar Bijlani 
709e0b56a3SHarsh Kumar Bijlani static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp * dp,int ml_peer_id)710cafe8ccSHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp *dp, int ml_peer_id)
7207174dc9SHarsh Kumar Bijlani {
739e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
7407174dc9SHarsh Kumar Bijlani 
750cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
7607174dc9SHarsh Kumar Bijlani 
770cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list)
7807174dc9SHarsh Kumar Bijlani 		if (ml_peer_id == peer->ml_id)
7907174dc9SHarsh Kumar Bijlani 			return peer;
8007174dc9SHarsh Kumar Bijlani 
8107174dc9SHarsh Kumar Bijlani 	return NULL;
8207174dc9SHarsh Kumar Bijlani }
8307174dc9SHarsh Kumar Bijlani 
8411157e09SHarsh Kumar Bijlani static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_search_by_id(struct ath12k_dp * dp,int peer_id)8511157e09SHarsh Kumar Bijlani ath12k_dp_link_peer_search_by_id(struct ath12k_dp *dp, int peer_id)
8607174dc9SHarsh Kumar Bijlani {
879e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
8807174dc9SHarsh Kumar Bijlani 
890cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
9007174dc9SHarsh Kumar Bijlani 
9107174dc9SHarsh Kumar Bijlani 	if (peer_id == HAL_INVALID_PEERID)
9207174dc9SHarsh Kumar Bijlani 		return NULL;
9307174dc9SHarsh Kumar Bijlani 
9407174dc9SHarsh Kumar Bijlani 	if (peer_id & ATH12K_PEER_ML_ID_VALID)
950cafe8ccSHarsh Kumar Bijlani 		return ath12k_dp_link_peer_find_by_ml_id(dp, peer_id);
9607174dc9SHarsh Kumar Bijlani 
970cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list)
9807174dc9SHarsh Kumar Bijlani 		if (peer_id == peer->peer_id)
9907174dc9SHarsh Kumar Bijlani 			return peer;
10007174dc9SHarsh Kumar Bijlani 
10107174dc9SHarsh Kumar Bijlani 	return NULL;
10207174dc9SHarsh Kumar Bijlani }
10307174dc9SHarsh Kumar Bijlani 
ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp * dp,int vdev_id)1040cafe8ccSHarsh Kumar Bijlani bool ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp *dp, int vdev_id)
10507174dc9SHarsh Kumar Bijlani {
1069e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
10707174dc9SHarsh Kumar Bijlani 
1080cafe8ccSHarsh Kumar Bijlani 	spin_lock_bh(&dp->dp_lock);
10907174dc9SHarsh Kumar Bijlani 
1100cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list) {
11107174dc9SHarsh Kumar Bijlani 		if (vdev_id == peer->vdev_id) {
1120cafe8ccSHarsh Kumar Bijlani 			spin_unlock_bh(&dp->dp_lock);
11307174dc9SHarsh Kumar Bijlani 			return true;
11407174dc9SHarsh Kumar Bijlani 		}
11507174dc9SHarsh Kumar Bijlani 	}
1160cafe8ccSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
11707174dc9SHarsh Kumar Bijlani 	return false;
11807174dc9SHarsh Kumar Bijlani }
11907174dc9SHarsh Kumar Bijlani 
1209e0b56a3SHarsh Kumar Bijlani struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ast(struct ath12k_dp * dp,int ast_hash)1210cafe8ccSHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_ast(struct ath12k_dp *dp, int ast_hash)
12207174dc9SHarsh Kumar Bijlani {
1239e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
12407174dc9SHarsh Kumar Bijlani 
1250cafe8ccSHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
12607174dc9SHarsh Kumar Bijlani 
1270cafe8ccSHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp->peers, list)
12807174dc9SHarsh Kumar Bijlani 		if (ast_hash == peer->ast_hash)
12907174dc9SHarsh Kumar Bijlani 			return peer;
13007174dc9SHarsh Kumar Bijlani 
13107174dc9SHarsh Kumar Bijlani 	return NULL;
13207174dc9SHarsh Kumar Bijlani }
13307174dc9SHarsh Kumar Bijlani 
ath12k_dp_link_peer_unmap_event(struct ath12k_base * ab,u16 peer_id)1349e0b56a3SHarsh Kumar Bijlani void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id)
13507174dc9SHarsh Kumar Bijlani {
1369e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
1370cafe8ccSHarsh Kumar Bijlani 	struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
13807174dc9SHarsh Kumar Bijlani 
1390cafe8ccSHarsh Kumar Bijlani 	spin_lock_bh(&dp->dp_lock);
14007174dc9SHarsh Kumar Bijlani 
14111157e09SHarsh Kumar Bijlani 	peer = ath12k_dp_link_peer_search_by_id(dp, peer_id);
14207174dc9SHarsh Kumar Bijlani 	if (!peer) {
14307174dc9SHarsh Kumar Bijlani 		ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
14407174dc9SHarsh Kumar Bijlani 			    peer_id);
14507174dc9SHarsh Kumar Bijlani 		goto exit;
14607174dc9SHarsh Kumar Bijlani 	}
14707174dc9SHarsh Kumar Bijlani 
14807174dc9SHarsh Kumar Bijlani 	ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
14907174dc9SHarsh Kumar Bijlani 		   peer->vdev_id, peer->addr, peer_id);
15007174dc9SHarsh Kumar Bijlani 
15105774dffSPavankumar Nandeshwar 	ath12k_dp_link_peer_free(peer);
15207174dc9SHarsh Kumar Bijlani 	wake_up(&ab->peer_mapping_wq);
15307174dc9SHarsh Kumar Bijlani 
15407174dc9SHarsh Kumar Bijlani exit:
1550cafe8ccSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
15607174dc9SHarsh Kumar Bijlani }
15707174dc9SHarsh Kumar Bijlani 
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)1589e0b56a3SHarsh Kumar Bijlani void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
15907174dc9SHarsh Kumar Bijlani 				   u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
16007174dc9SHarsh Kumar Bijlani {
1619e0b56a3SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer;
1620cafe8ccSHarsh Kumar Bijlani 	struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
16335fcf4faSHarsh Kumar Bijlani 	struct ath12k *ar;
16407174dc9SHarsh Kumar Bijlani 
1650cafe8ccSHarsh Kumar Bijlani 	spin_lock_bh(&dp->dp_lock);
1660cafe8ccSHarsh Kumar Bijlani 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
16707174dc9SHarsh Kumar Bijlani 	if (!peer) {
16869050f8dSKees Cook 		peer = kzalloc_obj(*peer, GFP_ATOMIC);
16907174dc9SHarsh Kumar Bijlani 		if (!peer)
17007174dc9SHarsh Kumar Bijlani 			goto exit;
17107174dc9SHarsh Kumar Bijlani 
17207174dc9SHarsh Kumar Bijlani 		peer->vdev_id = vdev_id;
17307174dc9SHarsh Kumar Bijlani 		peer->peer_id = peer_id;
17407174dc9SHarsh Kumar Bijlani 		peer->ast_hash = ast_hash;
17507174dc9SHarsh Kumar Bijlani 		peer->hw_peer_id = hw_peer_id;
17607174dc9SHarsh Kumar Bijlani 		ether_addr_copy(peer->addr, mac_addr);
17735fcf4faSHarsh Kumar Bijlani 
17835fcf4faSHarsh Kumar Bijlani 		rcu_read_lock();
17935fcf4faSHarsh Kumar Bijlani 		ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
18035fcf4faSHarsh Kumar Bijlani 		if (ar && ath12k_debugfs_is_extd_rx_stats_enabled(ar) &&
18135fcf4faSHarsh Kumar Bijlani 		    !peer->peer_stats.rx_stats) {
18269050f8dSKees Cook 			peer->peer_stats.rx_stats = kzalloc_obj(*peer->peer_stats.rx_stats,
18369050f8dSKees Cook 								GFP_ATOMIC);
18435fcf4faSHarsh Kumar Bijlani 		}
18535fcf4faSHarsh Kumar Bijlani 		rcu_read_unlock();
18635fcf4faSHarsh Kumar Bijlani 
1870cafe8ccSHarsh Kumar Bijlani 		list_add(&peer->list, &dp->peers);
18807174dc9SHarsh Kumar Bijlani 		wake_up(&ab->peer_mapping_wq);
18935fcf4faSHarsh Kumar Bijlani 		ewma_avg_rssi_init(&peer->avg_rssi);
19007174dc9SHarsh Kumar Bijlani 	}
19107174dc9SHarsh Kumar Bijlani 	ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
19207174dc9SHarsh Kumar Bijlani 		   vdev_id, mac_addr, peer_id);
19307174dc9SHarsh Kumar Bijlani 
19407174dc9SHarsh Kumar Bijlani exit:
1950cafe8ccSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
19607174dc9SHarsh Kumar Bijlani }
19707174dc9SHarsh Kumar Bijlani 
ath12k_dp_link_peer_to_link_sta(struct ath12k_base * ab,struct ath12k_dp_link_peer * peer)1989e0b56a3SHarsh Kumar Bijlani struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab,
1999e0b56a3SHarsh Kumar Bijlani 							struct ath12k_dp_link_peer *peer)
20007174dc9SHarsh Kumar Bijlani {
20107174dc9SHarsh Kumar Bijlani 	struct ath12k_sta *ahsta;
20207174dc9SHarsh Kumar Bijlani 	struct ath12k_link_sta *arsta;
20307174dc9SHarsh Kumar Bijlani 
2046633dca5SRipan Deuri 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
2056633dca5SRipan Deuri 			 "ath12k_dp_link_peer to ath12k_link_sta called without rcu lock");
2066633dca5SRipan Deuri 
20707174dc9SHarsh Kumar Bijlani 	if (!peer->sta)
20807174dc9SHarsh Kumar Bijlani 		return NULL;
20907174dc9SHarsh Kumar Bijlani 
21007174dc9SHarsh Kumar Bijlani 	ahsta = ath12k_sta_to_ahsta(peer->sta);
21107174dc9SHarsh Kumar Bijlani 	if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) {
21207174dc9SHarsh Kumar Bijlani 		if (!(ahsta->links_map & BIT(peer->link_id))) {
21307174dc9SHarsh Kumar Bijlani 			ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n",
21407174dc9SHarsh Kumar Bijlani 				    peer->addr, peer->peer_id, peer->link_id,
21507174dc9SHarsh Kumar Bijlani 				    ahsta->links_map);
21607174dc9SHarsh Kumar Bijlani 			return NULL;
21707174dc9SHarsh Kumar Bijlani 		}
21807174dc9SHarsh Kumar Bijlani 		arsta = rcu_dereference(ahsta->link[peer->link_id]);
21907174dc9SHarsh Kumar Bijlani 		if (!arsta)
22007174dc9SHarsh Kumar Bijlani 			return NULL;
22107174dc9SHarsh Kumar Bijlani 	} else {
22207174dc9SHarsh Kumar Bijlani 		arsta =  &ahsta->deflink;
22307174dc9SHarsh Kumar Bijlani 	}
22407174dc9SHarsh Kumar Bijlani 	return arsta;
22507174dc9SHarsh Kumar Bijlani }
226a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp * dp)227a88cf5f7SHarsh Kumar Bijlani static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp)
228a88cf5f7SHarsh Kumar Bijlani {
229a88cf5f7SHarsh Kumar Bijlani 	struct ath12k_base *ab = dp->ab;
230a88cf5f7SHarsh Kumar Bijlani 	struct rhashtable_params *param;
231a88cf5f7SHarsh Kumar Bijlani 	struct rhashtable *rhash_addr_tbl;
232a88cf5f7SHarsh Kumar Bijlani 	int ret;
233a88cf5f7SHarsh Kumar Bijlani 
234a88cf5f7SHarsh Kumar Bijlani 	lockdep_assert_held(&dp->link_peer_rhash_tbl_lock);
235a88cf5f7SHarsh Kumar Bijlani 
236*bf4afc53SLinus Torvalds 	rhash_addr_tbl = kzalloc_obj(*dp->rhead_peer_addr);
237a88cf5f7SHarsh Kumar Bijlani 	if (!rhash_addr_tbl)
238a88cf5f7SHarsh Kumar Bijlani 		return -ENOMEM;
239a88cf5f7SHarsh Kumar Bijlani 
240a88cf5f7SHarsh Kumar Bijlani 	param = &dp->rhash_peer_addr_param;
241a88cf5f7SHarsh Kumar Bijlani 
242a88cf5f7SHarsh Kumar Bijlani 	param->key_offset = offsetof(struct ath12k_dp_link_peer, addr);
243a88cf5f7SHarsh Kumar Bijlani 	param->head_offset = offsetof(struct ath12k_dp_link_peer, rhash_addr);
244a88cf5f7SHarsh Kumar Bijlani 	param->key_len = sizeof_field(struct ath12k_dp_link_peer, addr);
245a88cf5f7SHarsh Kumar Bijlani 	param->automatic_shrinking = true;
246a88cf5f7SHarsh Kumar Bijlani 	param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab);
247a88cf5f7SHarsh Kumar Bijlani 
248a88cf5f7SHarsh Kumar Bijlani 	ret = rhashtable_init(rhash_addr_tbl, param);
249a88cf5f7SHarsh Kumar Bijlani 	if (ret) {
250a88cf5f7SHarsh Kumar Bijlani 		ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
251a88cf5f7SHarsh Kumar Bijlani 		goto err_free;
252a88cf5f7SHarsh Kumar Bijlani 	}
253a88cf5f7SHarsh Kumar Bijlani 
254a88cf5f7SHarsh Kumar Bijlani 	dp->rhead_peer_addr = rhash_addr_tbl;
255a88cf5f7SHarsh Kumar Bijlani 
256a88cf5f7SHarsh Kumar Bijlani 	return 0;
257a88cf5f7SHarsh Kumar Bijlani 
258a88cf5f7SHarsh Kumar Bijlani err_free:
259a88cf5f7SHarsh Kumar Bijlani 	kfree(rhash_addr_tbl);
260a88cf5f7SHarsh Kumar Bijlani 
261a88cf5f7SHarsh Kumar Bijlani 	return ret;
262a88cf5f7SHarsh Kumar Bijlani }
263a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp * dp)264a88cf5f7SHarsh Kumar Bijlani int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp)
265a88cf5f7SHarsh Kumar Bijlani {
266a88cf5f7SHarsh Kumar Bijlani 	int ret;
267a88cf5f7SHarsh Kumar Bijlani 
268a88cf5f7SHarsh Kumar Bijlani 	mutex_lock(&dp->link_peer_rhash_tbl_lock);
269a88cf5f7SHarsh Kumar Bijlani 	ret = ath12k_dp_link_peer_rhash_addr_tbl_init(dp);
270a88cf5f7SHarsh Kumar Bijlani 	mutex_unlock(&dp->link_peer_rhash_tbl_lock);
271a88cf5f7SHarsh Kumar Bijlani 
272a88cf5f7SHarsh Kumar Bijlani 	return ret;
273a88cf5f7SHarsh Kumar Bijlani }
274a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp * dp)275a88cf5f7SHarsh Kumar Bijlani void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp)
276a88cf5f7SHarsh Kumar Bijlani {
277a88cf5f7SHarsh Kumar Bijlani 	mutex_lock(&dp->link_peer_rhash_tbl_lock);
278a88cf5f7SHarsh Kumar Bijlani 	rhashtable_destroy(dp->rhead_peer_addr);
279a88cf5f7SHarsh Kumar Bijlani 	kfree(dp->rhead_peer_addr);
280a88cf5f7SHarsh Kumar Bijlani 	dp->rhead_peer_addr = NULL;
281a88cf5f7SHarsh Kumar Bijlani 	mutex_unlock(&dp->link_peer_rhash_tbl_lock);
282a88cf5f7SHarsh Kumar Bijlani }
283a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_insert(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)284a88cf5f7SHarsh Kumar Bijlani static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
285a88cf5f7SHarsh Kumar Bijlani 					    struct ath12k_dp_link_peer *peer)
286a88cf5f7SHarsh Kumar Bijlani {
287a88cf5f7SHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *tmp;
288a88cf5f7SHarsh Kumar Bijlani 
289a88cf5f7SHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
290a88cf5f7SHarsh Kumar Bijlani 
291a88cf5f7SHarsh Kumar Bijlani 	tmp = rhashtable_lookup_get_insert_fast(dp->rhead_peer_addr, &peer->rhash_addr,
292a88cf5f7SHarsh Kumar Bijlani 						dp->rhash_peer_addr_param);
293a88cf5f7SHarsh Kumar Bijlani 	if (!tmp)
294a88cf5f7SHarsh Kumar Bijlani 		return 0;
295a88cf5f7SHarsh Kumar Bijlani 	else if (IS_ERR(tmp))
296a88cf5f7SHarsh Kumar Bijlani 		return PTR_ERR(tmp);
297a88cf5f7SHarsh Kumar Bijlani 	else
298a88cf5f7SHarsh Kumar Bijlani 		return -EEXIST;
299a88cf5f7SHarsh Kumar Bijlani }
300a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_remove(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)301a88cf5f7SHarsh Kumar Bijlani static int ath12k_dp_link_peer_rhash_remove(struct ath12k_dp *dp,
302a88cf5f7SHarsh Kumar Bijlani 					    struct ath12k_dp_link_peer *peer)
303a88cf5f7SHarsh Kumar Bijlani {
304a88cf5f7SHarsh Kumar Bijlani 	int ret;
305a88cf5f7SHarsh Kumar Bijlani 
306a88cf5f7SHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
307a88cf5f7SHarsh Kumar Bijlani 
308a88cf5f7SHarsh Kumar Bijlani 	ret = rhashtable_remove_fast(dp->rhead_peer_addr, &peer->rhash_addr,
309a88cf5f7SHarsh Kumar Bijlani 				     dp->rhash_peer_addr_param);
310a88cf5f7SHarsh Kumar Bijlani 	if (ret && ret != -ENOENT)
311a88cf5f7SHarsh Kumar Bijlani 		return ret;
312a88cf5f7SHarsh Kumar Bijlani 
313a88cf5f7SHarsh Kumar Bijlani 	return 0;
314a88cf5f7SHarsh Kumar Bijlani }
315a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_add(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)316a88cf5f7SHarsh Kumar Bijlani int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp,
317a88cf5f7SHarsh Kumar Bijlani 				  struct ath12k_dp_link_peer *peer)
318a88cf5f7SHarsh Kumar Bijlani {
319a88cf5f7SHarsh Kumar Bijlani 	int ret;
320a88cf5f7SHarsh Kumar Bijlani 
321a88cf5f7SHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
322a88cf5f7SHarsh Kumar Bijlani 
323a88cf5f7SHarsh Kumar Bijlani 	ret = ath12k_dp_link_peer_rhash_insert(dp, peer);
324a88cf5f7SHarsh Kumar Bijlani 	if (ret)
325a88cf5f7SHarsh Kumar Bijlani 		ath12k_warn(dp, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
326a88cf5f7SHarsh Kumar Bijlani 			    peer->addr, peer->peer_id, ret);
327a88cf5f7SHarsh Kumar Bijlani 
328a88cf5f7SHarsh Kumar Bijlani 	return ret;
329a88cf5f7SHarsh Kumar Bijlani }
330a88cf5f7SHarsh Kumar Bijlani 
ath12k_dp_link_peer_rhash_delete(struct ath12k_dp * dp,struct ath12k_dp_link_peer * peer)331a88cf5f7SHarsh Kumar Bijlani void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp,
332a88cf5f7SHarsh Kumar Bijlani 				      struct ath12k_dp_link_peer *peer)
333a88cf5f7SHarsh Kumar Bijlani {
334a88cf5f7SHarsh Kumar Bijlani 	/* No failure handling and hence return type is void */
335a88cf5f7SHarsh Kumar Bijlani 	int ret;
336a88cf5f7SHarsh Kumar Bijlani 
337a88cf5f7SHarsh Kumar Bijlani 	lockdep_assert_held(&dp->dp_lock);
338a88cf5f7SHarsh Kumar Bijlani 
339a88cf5f7SHarsh Kumar Bijlani 	ret = ath12k_dp_link_peer_rhash_remove(dp, peer);
340a88cf5f7SHarsh Kumar Bijlani 	if (ret)
341a88cf5f7SHarsh Kumar Bijlani 		ath12k_warn(dp, "failed to remove peer %pM with id %d in rhash_addr ret %d\n",
342a88cf5f7SHarsh Kumar Bijlani 			    peer->addr, peer->peer_id, ret);
343a88cf5f7SHarsh Kumar Bijlani }
344ee16dcf5SHarsh Kumar Bijlani 
ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw * dp_hw,u8 * addr)345ee16dcf5SHarsh Kumar Bijlani struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw *dp_hw, u8 *addr)
346ee16dcf5SHarsh Kumar Bijlani {
347ee16dcf5SHarsh Kumar Bijlani 	struct ath12k_dp_peer *peer;
348ee16dcf5SHarsh Kumar Bijlani 
349ee16dcf5SHarsh Kumar Bijlani 	lockdep_assert_held(&dp_hw->peer_lock);
350ee16dcf5SHarsh Kumar Bijlani 
351ee16dcf5SHarsh Kumar Bijlani 	list_for_each_entry(peer, &dp_hw->dp_peers_list, list) {
352ee16dcf5SHarsh Kumar Bijlani 		if (ether_addr_equal(peer->addr, addr))
353ee16dcf5SHarsh Kumar Bijlani 			return peer;
354ee16dcf5SHarsh Kumar Bijlani 	}
355ee16dcf5SHarsh Kumar Bijlani 
356ee16dcf5SHarsh Kumar Bijlani 	return NULL;
357ee16dcf5SHarsh Kumar Bijlani }
358ee16dcf5SHarsh Kumar Bijlani EXPORT_SYMBOL(ath12k_dp_peer_find_by_addr);
359ee16dcf5SHarsh Kumar Bijlani 
ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta)360ee16dcf5SHarsh Kumar Bijlani struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw *dp_hw,
361ee16dcf5SHarsh Kumar Bijlani 							   u8 *addr,
362ee16dcf5SHarsh Kumar Bijlani 							   struct ieee80211_sta *sta)
363ee16dcf5SHarsh Kumar Bijlani {
364ee16dcf5SHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
365ee16dcf5SHarsh Kumar Bijlani 
366ee16dcf5SHarsh Kumar Bijlani 	lockdep_assert_held(&dp_hw->peer_lock);
367ee16dcf5SHarsh Kumar Bijlani 
368ee16dcf5SHarsh Kumar Bijlani 	list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
369ee16dcf5SHarsh Kumar Bijlani 		if (ether_addr_equal(dp_peer->addr, addr) && (dp_peer->sta == sta))
370ee16dcf5SHarsh Kumar Bijlani 			return dp_peer;
371ee16dcf5SHarsh Kumar Bijlani 	}
372ee16dcf5SHarsh Kumar Bijlani 
373ee16dcf5SHarsh Kumar Bijlani 	return NULL;
374ee16dcf5SHarsh Kumar Bijlani }
375ee16dcf5SHarsh Kumar Bijlani 
ath12k_dp_peer_create_find(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta,bool mlo_peer)376ee16dcf5SHarsh Kumar Bijlani static struct ath12k_dp_peer *ath12k_dp_peer_create_find(struct ath12k_dp_hw *dp_hw,
377ee16dcf5SHarsh Kumar Bijlani 							 u8 *addr,
378ee16dcf5SHarsh Kumar Bijlani 							 struct ieee80211_sta *sta,
379ee16dcf5SHarsh Kumar Bijlani 							 bool mlo_peer)
380ee16dcf5SHarsh Kumar Bijlani {
381ee16dcf5SHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
382ee16dcf5SHarsh Kumar Bijlani 
383ee16dcf5SHarsh Kumar Bijlani 	lockdep_assert_held(&dp_hw->peer_lock);
384ee16dcf5SHarsh Kumar Bijlani 
385ee16dcf5SHarsh Kumar Bijlani 	list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
386ee16dcf5SHarsh Kumar Bijlani 		if (ether_addr_equal(dp_peer->addr, addr)) {
387ee16dcf5SHarsh Kumar Bijlani 			if (!sta || mlo_peer || dp_peer->is_mlo ||
388ee16dcf5SHarsh Kumar Bijlani 			    dp_peer->sta == sta)
389ee16dcf5SHarsh Kumar Bijlani 				return dp_peer;
390ee16dcf5SHarsh Kumar Bijlani 		}
391ee16dcf5SHarsh Kumar Bijlani 	}
392ee16dcf5SHarsh Kumar Bijlani 
393ee16dcf5SHarsh Kumar Bijlani 	return NULL;
394ee16dcf5SHarsh Kumar Bijlani }
395ee16dcf5SHarsh Kumar Bijlani 
3965525f12fSHarsh Kumar Bijlani /*
3975525f12fSHarsh Kumar Bijlani  * Index of ath12k_dp_peer for MLO client is same as peer id of ath12k_dp_peer,
3985525f12fSHarsh Kumar Bijlani  * while for ath12k_dp_link_peer(mlo and non-mlo) and ath12k_dp_peer for
3995525f12fSHarsh Kumar Bijlani  * Non-MLO client it is derived as ((DEVICE_ID << 10) | (10 bits of peer id)).
4005525f12fSHarsh Kumar Bijlani  *
4015525f12fSHarsh Kumar Bijlani  * This is done because ml_peer_id and peer_id_table are at hw granularity,
4025525f12fSHarsh Kumar Bijlani  * while link_peer_id is at device granularity, hence in order to avoid
4035525f12fSHarsh Kumar Bijlani  * conflict this approach is followed.
4045525f12fSHarsh Kumar Bijlani  */
4055525f12fSHarsh Kumar Bijlani #define ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT        10
4065525f12fSHarsh Kumar Bijlani 
ath12k_dp_peer_get_peerid_index(struct ath12k_dp * dp,u16 peer_id)4075525f12fSHarsh Kumar Bijlani u16 ath12k_dp_peer_get_peerid_index(struct ath12k_dp *dp, u16 peer_id)
4085525f12fSHarsh Kumar Bijlani {
4095525f12fSHarsh Kumar Bijlani 	return (peer_id & ATH12K_PEER_ML_ID_VALID) ? peer_id :
4105525f12fSHarsh Kumar Bijlani 		((dp->device_id << ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT) | peer_id);
4115525f12fSHarsh Kumar Bijlani }
4125525f12fSHarsh Kumar Bijlani 
ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp * dp_pdev,u16 peer_id)41311157e09SHarsh Kumar Bijlani struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev,
41411157e09SHarsh Kumar Bijlani 						     u16 peer_id)
41511157e09SHarsh Kumar Bijlani {
41611157e09SHarsh Kumar Bijlani 	u16 index;
41711157e09SHarsh Kumar Bijlani 	struct ath12k_dp *dp = dp_pdev->dp;
41811157e09SHarsh Kumar Bijlani 
41911157e09SHarsh Kumar Bijlani 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
42011157e09SHarsh Kumar Bijlani 			 "ath12k dp peer find by peerid index called without rcu lock");
42111157e09SHarsh Kumar Bijlani 
42211157e09SHarsh Kumar Bijlani 	if (!peer_id || peer_id >= ATH12K_DP_PEER_ID_INVALID)
42311157e09SHarsh Kumar Bijlani 		return NULL;
42411157e09SHarsh Kumar Bijlani 
42511157e09SHarsh Kumar Bijlani 	index = ath12k_dp_peer_get_peerid_index(dp, peer_id);
42611157e09SHarsh Kumar Bijlani 
42711157e09SHarsh Kumar Bijlani 	return rcu_dereference(dp_pdev->dp_hw->dp_peers[index]);
42811157e09SHarsh Kumar Bijlani }
429219dd149SPavankumar Nandeshwar EXPORT_SYMBOL(ath12k_dp_peer_find_by_peerid);
43011157e09SHarsh Kumar Bijlani 
43111157e09SHarsh Kumar Bijlani struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp * dp_pdev,u16 peer_id)43211157e09SHarsh Kumar Bijlani ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id)
43311157e09SHarsh Kumar Bijlani {
43411157e09SHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer = NULL;
43511157e09SHarsh Kumar Bijlani 	u8 link_id;
43611157e09SHarsh Kumar Bijlani 
43711157e09SHarsh Kumar Bijlani 	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
43811157e09SHarsh Kumar Bijlani 			 "ath12k dp link peer find by peerid index called without rcu lock");
43911157e09SHarsh Kumar Bijlani 
44011157e09SHarsh Kumar Bijlani 	if (dp_pdev->hw_link_id >= ATH12K_GROUP_MAX_RADIO)
44111157e09SHarsh Kumar Bijlani 		return NULL;
44211157e09SHarsh Kumar Bijlani 
44311157e09SHarsh Kumar Bijlani 	dp_peer = ath12k_dp_peer_find_by_peerid(dp_pdev, peer_id);
44411157e09SHarsh Kumar Bijlani 	if (!dp_peer)
44511157e09SHarsh Kumar Bijlani 		return NULL;
44611157e09SHarsh Kumar Bijlani 
44711157e09SHarsh Kumar Bijlani 	link_id = dp_peer->hw_links[dp_pdev->hw_link_id];
44811157e09SHarsh Kumar Bijlani 
44911157e09SHarsh Kumar Bijlani 	return rcu_dereference(dp_peer->link_peers[link_id]);
45011157e09SHarsh Kumar Bijlani }
451219dd149SPavankumar Nandeshwar EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_peerid);
45211157e09SHarsh Kumar Bijlani 
ath12k_dp_peer_create(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ath12k_dp_peer_create_params * params)453ee16dcf5SHarsh Kumar Bijlani int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
454ee16dcf5SHarsh Kumar Bijlani 			  struct ath12k_dp_peer_create_params *params)
455ee16dcf5SHarsh Kumar Bijlani {
456ee16dcf5SHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
457ee16dcf5SHarsh Kumar Bijlani 
458ee16dcf5SHarsh Kumar Bijlani 	spin_lock_bh(&dp_hw->peer_lock);
459ee16dcf5SHarsh Kumar Bijlani 	dp_peer = ath12k_dp_peer_create_find(dp_hw, addr, params->sta, params->is_mlo);
460ee16dcf5SHarsh Kumar Bijlani 	if (dp_peer) {
461ee16dcf5SHarsh Kumar Bijlani 		spin_unlock_bh(&dp_hw->peer_lock);
462ee16dcf5SHarsh Kumar Bijlani 		return -EEXIST;
463ee16dcf5SHarsh Kumar Bijlani 	}
464ee16dcf5SHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
465ee16dcf5SHarsh Kumar Bijlani 
46669050f8dSKees Cook 	dp_peer = kzalloc_obj(*dp_peer, GFP_ATOMIC);
467ee16dcf5SHarsh Kumar Bijlani 	if (!dp_peer)
468ee16dcf5SHarsh Kumar Bijlani 		return -ENOMEM;
469ee16dcf5SHarsh Kumar Bijlani 
470ee16dcf5SHarsh Kumar Bijlani 	ether_addr_copy(dp_peer->addr, addr);
471ee16dcf5SHarsh Kumar Bijlani 	dp_peer->sta = params->sta;
472ee16dcf5SHarsh Kumar Bijlani 	dp_peer->is_mlo = params->is_mlo;
473ee16dcf5SHarsh Kumar Bijlani 
474ee16dcf5SHarsh Kumar Bijlani 	/*
475ee16dcf5SHarsh Kumar Bijlani 	 * For MLO client, the host assigns the ML peer ID, so set peer_id in dp_peer
476ee16dcf5SHarsh Kumar Bijlani 	 * For non-MLO client, host gets link peer ID from firmware and will be
477ee16dcf5SHarsh Kumar Bijlani 	 * assigned at the time of link peer creation
478ee16dcf5SHarsh Kumar Bijlani 	 */
479ee16dcf5SHarsh Kumar Bijlani 	dp_peer->peer_id = params->is_mlo ? params->peer_id : ATH12K_DP_PEER_ID_INVALID;
480ee16dcf5SHarsh Kumar Bijlani 	dp_peer->ucast_ra_only = params->ucast_ra_only;
481ee16dcf5SHarsh Kumar Bijlani 
482ee16dcf5SHarsh Kumar Bijlani 	dp_peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
483ee16dcf5SHarsh Kumar Bijlani 	dp_peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
48411157e09SHarsh Kumar Bijlani 	dp_peer->ucast_ra_only = params->ucast_ra_only;
485ee16dcf5SHarsh Kumar Bijlani 
486ee16dcf5SHarsh Kumar Bijlani 	spin_lock_bh(&dp_hw->peer_lock);
487ee16dcf5SHarsh Kumar Bijlani 
488ee16dcf5SHarsh Kumar Bijlani 	list_add(&dp_peer->list, &dp_hw->dp_peers_list);
489ee16dcf5SHarsh Kumar Bijlani 
490ee16dcf5SHarsh Kumar Bijlani 	/*
491ee16dcf5SHarsh Kumar Bijlani 	 * For MLO client, the peer_id for ath12k_dp_peer is allocated by host
492ee16dcf5SHarsh Kumar Bijlani 	 * and that peer_id is known at this point, and hence this ath12k_dp_peer
493ee16dcf5SHarsh Kumar Bijlani 	 * can be added to the RCU table using the peer_id.
494ee16dcf5SHarsh Kumar Bijlani 	 * For non-MLO client, this addition to RCU table shall be done at the
495ee16dcf5SHarsh Kumar Bijlani 	 * time of assignment of ath12k_dp_link_peer to ath12k_dp_peer.
496ee16dcf5SHarsh Kumar Bijlani 	 */
497ee16dcf5SHarsh Kumar Bijlani 	if (dp_peer->is_mlo)
498ee16dcf5SHarsh Kumar Bijlani 		rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
499ee16dcf5SHarsh Kumar Bijlani 
500ee16dcf5SHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
501ee16dcf5SHarsh Kumar Bijlani 
502ee16dcf5SHarsh Kumar Bijlani 	return 0;
503ee16dcf5SHarsh Kumar Bijlani }
504ee16dcf5SHarsh Kumar Bijlani 
ath12k_dp_peer_delete(struct ath12k_dp_hw * dp_hw,u8 * addr,struct ieee80211_sta * sta)505ee16dcf5SHarsh Kumar Bijlani void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
506ee16dcf5SHarsh Kumar Bijlani 			   struct ieee80211_sta *sta)
507ee16dcf5SHarsh Kumar Bijlani {
508ee16dcf5SHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
509ee16dcf5SHarsh Kumar Bijlani 
510ee16dcf5SHarsh Kumar Bijlani 	spin_lock_bh(&dp_hw->peer_lock);
511ee16dcf5SHarsh Kumar Bijlani 
512ee16dcf5SHarsh Kumar Bijlani 	dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, addr, sta);
513ee16dcf5SHarsh Kumar Bijlani 	if (!dp_peer) {
514ee16dcf5SHarsh Kumar Bijlani 		spin_unlock_bh(&dp_hw->peer_lock);
515ee16dcf5SHarsh Kumar Bijlani 		return;
516ee16dcf5SHarsh Kumar Bijlani 	}
517ee16dcf5SHarsh Kumar Bijlani 
518ee16dcf5SHarsh Kumar Bijlani 	if (dp_peer->is_mlo)
519ee16dcf5SHarsh Kumar Bijlani 		rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
520ee16dcf5SHarsh Kumar Bijlani 
521ee16dcf5SHarsh Kumar Bijlani 	list_del(&dp_peer->list);
522ee16dcf5SHarsh Kumar Bijlani 
523ee16dcf5SHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
524ee16dcf5SHarsh Kumar Bijlani 
525ee16dcf5SHarsh Kumar Bijlani 	synchronize_rcu();
526ee16dcf5SHarsh Kumar Bijlani 	kfree(dp_peer);
527ee16dcf5SHarsh Kumar Bijlani }
5285525f12fSHarsh Kumar Bijlani 
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)5295525f12fSHarsh Kumar Bijlani int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
5305525f12fSHarsh Kumar Bijlani 			       u8 vdev_id, struct ieee80211_sta *sta, u8 *addr,
5315525f12fSHarsh Kumar Bijlani 			       u8 link_id, u32 hw_link_id)
5325525f12fSHarsh Kumar Bijlani {
5335525f12fSHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
5345525f12fSHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer, *temp_peer;
5355525f12fSHarsh Kumar Bijlani 	u16 peerid_index;
5365525f12fSHarsh Kumar Bijlani 	int ret = -EINVAL;
5375525f12fSHarsh Kumar Bijlani 	u8 *dp_peer_mac = !sta ? addr : sta->addr;
5385525f12fSHarsh Kumar Bijlani 
5395525f12fSHarsh Kumar Bijlani 	spin_lock_bh(&dp->dp_lock);
5405525f12fSHarsh Kumar Bijlani 
5415525f12fSHarsh Kumar Bijlani 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
5425525f12fSHarsh Kumar Bijlani 	if (!peer) {
5435525f12fSHarsh Kumar Bijlani 		ath12k_warn(dp, "failed to find dp_link_peer with mac %pM on vdev %u\n",
5445525f12fSHarsh Kumar Bijlani 			    addr, vdev_id);
5455525f12fSHarsh Kumar Bijlani 		ret = -ENOENT;
5465525f12fSHarsh Kumar Bijlani 		goto err_peer;
5475525f12fSHarsh Kumar Bijlani 	}
5485525f12fSHarsh Kumar Bijlani 
5495525f12fSHarsh Kumar Bijlani 	spin_lock_bh(&dp_hw->peer_lock);
5505525f12fSHarsh Kumar Bijlani 
5515525f12fSHarsh Kumar Bijlani 	dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, dp_peer_mac, sta);
5525525f12fSHarsh Kumar Bijlani 	if (!dp_peer) {
5535525f12fSHarsh Kumar Bijlani 		ath12k_warn(dp, "failed to find dp_peer with mac %pM\n", dp_peer_mac);
5545525f12fSHarsh Kumar Bijlani 		ret = -ENOENT;
5555525f12fSHarsh Kumar Bijlani 		goto err_dp_peer;
5565525f12fSHarsh Kumar Bijlani 	}
5575525f12fSHarsh Kumar Bijlani 
5585525f12fSHarsh Kumar Bijlani 	/*
5595525f12fSHarsh Kumar Bijlani 	 * Set peer_id in dp_peer for non-mlo client, peer_id for mlo client is
5605525f12fSHarsh Kumar Bijlani 	 * set during dp_peer create
5615525f12fSHarsh Kumar Bijlani 	 */
5625525f12fSHarsh Kumar Bijlani 	if (!dp_peer->is_mlo)
5635525f12fSHarsh Kumar Bijlani 		dp_peer->peer_id = peer->peer_id;
5645525f12fSHarsh Kumar Bijlani 
5655525f12fSHarsh Kumar Bijlani 	peer->dp_peer = dp_peer;
5665525f12fSHarsh Kumar Bijlani 	peer->hw_link_id = hw_link_id;
5675525f12fSHarsh Kumar Bijlani 
5685525f12fSHarsh Kumar Bijlani 	dp_peer->hw_links[peer->hw_link_id] = link_id;
5695525f12fSHarsh Kumar Bijlani 
5705525f12fSHarsh Kumar Bijlani 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
5715525f12fSHarsh Kumar Bijlani 
5725525f12fSHarsh Kumar Bijlani 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
5735525f12fSHarsh Kumar Bijlani 
5745525f12fSHarsh Kumar Bijlani 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
5755525f12fSHarsh Kumar Bijlani 
5765525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
5775525f12fSHarsh Kumar Bijlani 
5785525f12fSHarsh Kumar Bijlani 	/*
5795525f12fSHarsh Kumar Bijlani 	 * In case of Split PHY and roaming scenario, pdev idx
5805525f12fSHarsh Kumar Bijlani 	 * might differ but both the pdev will share same rhash
5815525f12fSHarsh Kumar Bijlani 	 * table. In that case update the rhash table if link_peer is
5825525f12fSHarsh Kumar Bijlani 	 * already present
5835525f12fSHarsh Kumar Bijlani 	 */
5845525f12fSHarsh Kumar Bijlani 	temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
5855525f12fSHarsh Kumar Bijlani 	if (temp_peer && temp_peer->hw_link_id != hw_link_id)
5865525f12fSHarsh Kumar Bijlani 		ath12k_dp_link_peer_rhash_delete(dp, temp_peer);
5875525f12fSHarsh Kumar Bijlani 
5885525f12fSHarsh Kumar Bijlani 	ret = ath12k_dp_link_peer_rhash_add(dp, peer);
5895525f12fSHarsh Kumar Bijlani 	if (ret) {
5905525f12fSHarsh Kumar Bijlani 		/*
5915525f12fSHarsh Kumar Bijlani 		 * If new entry addition failed, add back old entry
5925525f12fSHarsh Kumar Bijlani 		 * If old entry addition also fails, then nothing
5935525f12fSHarsh Kumar Bijlani 		 * can be done, simply proceed
5945525f12fSHarsh Kumar Bijlani 		 */
5955525f12fSHarsh Kumar Bijlani 		if (temp_peer)
5965525f12fSHarsh Kumar Bijlani 			ath12k_dp_link_peer_rhash_add(dp, temp_peer);
5975525f12fSHarsh Kumar Bijlani 	}
5985525f12fSHarsh Kumar Bijlani 
5995525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
6005525f12fSHarsh Kumar Bijlani 
6015525f12fSHarsh Kumar Bijlani 	return ret;
6025525f12fSHarsh Kumar Bijlani 
6035525f12fSHarsh Kumar Bijlani err_dp_peer:
6045525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
6055525f12fSHarsh Kumar Bijlani 
6065525f12fSHarsh Kumar Bijlani err_peer:
6075525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
6085525f12fSHarsh Kumar Bijlani 
6095525f12fSHarsh Kumar Bijlani 	return ret;
6105525f12fSHarsh Kumar Bijlani }
6115525f12fSHarsh Kumar Bijlani 
ath12k_dp_link_peer_unassign(struct ath12k_dp * dp,struct ath12k_dp_hw * dp_hw,u8 vdev_id,u8 * addr,u32 hw_link_id)6125525f12fSHarsh Kumar Bijlani void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
6135525f12fSHarsh Kumar Bijlani 				  u8 vdev_id, u8 *addr, u32 hw_link_id)
6145525f12fSHarsh Kumar Bijlani {
6155525f12fSHarsh Kumar Bijlani 	struct ath12k_dp_peer *dp_peer;
6165525f12fSHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *peer, *temp_peer;
6175525f12fSHarsh Kumar Bijlani 	u16 peerid_index;
6185525f12fSHarsh Kumar Bijlani 
6195525f12fSHarsh Kumar Bijlani 	spin_lock_bh(&dp->dp_lock);
6205525f12fSHarsh Kumar Bijlani 
6215525f12fSHarsh Kumar Bijlani 	peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
6225525f12fSHarsh Kumar Bijlani 	if (!peer || !peer->dp_peer) {
6235525f12fSHarsh Kumar Bijlani 		spin_unlock_bh(&dp->dp_lock);
6245525f12fSHarsh Kumar Bijlani 		return;
6255525f12fSHarsh Kumar Bijlani 	}
6265525f12fSHarsh Kumar Bijlani 
6275525f12fSHarsh Kumar Bijlani 	spin_lock_bh(&dp_hw->peer_lock);
6285525f12fSHarsh Kumar Bijlani 
6295525f12fSHarsh Kumar Bijlani 	dp_peer = peer->dp_peer;
6305525f12fSHarsh Kumar Bijlani 	dp_peer->hw_links[peer->hw_link_id] = 0;
6315525f12fSHarsh Kumar Bijlani 
6325525f12fSHarsh Kumar Bijlani 	peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
6335525f12fSHarsh Kumar Bijlani 
6345525f12fSHarsh Kumar Bijlani 	rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
6355525f12fSHarsh Kumar Bijlani 
6365525f12fSHarsh Kumar Bijlani 	rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
6375525f12fSHarsh Kumar Bijlani 
6385525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp_hw->peer_lock);
6395525f12fSHarsh Kumar Bijlani 
6405525f12fSHarsh Kumar Bijlani 	/* To handle roaming and split phy scenario */
6415525f12fSHarsh Kumar Bijlani 	temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
6425525f12fSHarsh Kumar Bijlani 	if (temp_peer && temp_peer->hw_link_id == hw_link_id)
6435525f12fSHarsh Kumar Bijlani 		ath12k_dp_link_peer_rhash_delete(dp, peer);
6445525f12fSHarsh Kumar Bijlani 
6455525f12fSHarsh Kumar Bijlani 	spin_unlock_bh(&dp->dp_lock);
6465525f12fSHarsh Kumar Bijlani 
6475525f12fSHarsh Kumar Bijlani 	synchronize_rcu();
6485525f12fSHarsh Kumar Bijlani }
64935fcf4faSHarsh Kumar Bijlani 
65035fcf4faSHarsh Kumar Bijlani 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)65135fcf4faSHarsh Kumar Bijlani ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr,
65235fcf4faSHarsh Kumar Bijlani 					    struct ath12k_dp_link_peer_rate_info *info)
65335fcf4faSHarsh Kumar Bijlani {
65435fcf4faSHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *link_peer;
65535fcf4faSHarsh Kumar Bijlani 
65635fcf4faSHarsh Kumar Bijlani 	guard(spinlock_bh)(&dp->dp_lock);
65735fcf4faSHarsh Kumar Bijlani 
65835fcf4faSHarsh Kumar Bijlani 	link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
65935fcf4faSHarsh Kumar Bijlani 	if (!link_peer)
66035fcf4faSHarsh Kumar Bijlani 		return;
66135fcf4faSHarsh Kumar Bijlani 
66235fcf4faSHarsh Kumar Bijlani 	info->rx_duration = link_peer->rx_duration;
66335fcf4faSHarsh Kumar Bijlani 	info->tx_duration = link_peer->tx_duration;
66435fcf4faSHarsh Kumar Bijlani 	info->txrate.legacy = link_peer->txrate.legacy;
66535fcf4faSHarsh Kumar Bijlani 	info->txrate.mcs = link_peer->txrate.mcs;
66635fcf4faSHarsh Kumar Bijlani 	info->txrate.nss = link_peer->txrate.nss;
66735fcf4faSHarsh Kumar Bijlani 	info->txrate.bw = link_peer->txrate.bw;
66835fcf4faSHarsh Kumar Bijlani 	info->txrate.he_gi = link_peer->txrate.he_gi;
66935fcf4faSHarsh Kumar Bijlani 	info->txrate.he_dcm = link_peer->txrate.he_dcm;
67035fcf4faSHarsh Kumar Bijlani 	info->txrate.he_ru_alloc = link_peer->txrate.he_ru_alloc;
67135fcf4faSHarsh Kumar Bijlani 	info->txrate.flags = link_peer->txrate.flags;
67235fcf4faSHarsh Kumar Bijlani 	info->rssi_comb = link_peer->rssi_comb;
67335fcf4faSHarsh Kumar Bijlani 	info->signal_avg = ewma_avg_rssi_read(&link_peer->avg_rssi);
67435fcf4faSHarsh Kumar Bijlani }
67535fcf4faSHarsh Kumar Bijlani 
ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp * dp,const u8 * addr)67635fcf4faSHarsh Kumar Bijlani void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
67735fcf4faSHarsh Kumar Bijlani {
67835fcf4faSHarsh Kumar Bijlani 	struct ath12k_rx_peer_stats *rx_stats;
67935fcf4faSHarsh Kumar Bijlani 	struct ath12k_dp_link_peer *link_peer;
68035fcf4faSHarsh Kumar Bijlani 
68135fcf4faSHarsh Kumar Bijlani 	guard(spinlock_bh)(&dp->dp_lock);
68235fcf4faSHarsh Kumar Bijlani 
68335fcf4faSHarsh Kumar Bijlani 	link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
68435fcf4faSHarsh Kumar Bijlani 	if (!link_peer || !link_peer->peer_stats.rx_stats)
68535fcf4faSHarsh Kumar Bijlani 		return;
68635fcf4faSHarsh Kumar Bijlani 
68735fcf4faSHarsh Kumar Bijlani 	rx_stats = link_peer->peer_stats.rx_stats;
68835fcf4faSHarsh Kumar Bijlani 	if (rx_stats)
68935fcf4faSHarsh Kumar Bijlani 		memset(rx_stats, 0, sizeof(*rx_stats));
69035fcf4faSHarsh Kumar Bijlani }
691