1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
47b0c70d9SKarthikeyan Periyasamy  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5d5c65159SKalle Valo  */
6d5c65159SKalle Valo 
7d5c65159SKalle Valo #include "core.h"
8d5c65159SKalle Valo #include "peer.h"
9d5c65159SKalle Valo #include "debug.h"
10d5c65159SKalle Valo 
ath11k_peer_find_list_by_id(struct ath11k_base * ab,int peer_id)117b0c70d9SKarthikeyan Periyasamy static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab,
127b0c70d9SKarthikeyan Periyasamy 						       int peer_id)
137b0c70d9SKarthikeyan Periyasamy {
147b0c70d9SKarthikeyan Periyasamy 	struct ath11k_peer *peer;
157b0c70d9SKarthikeyan Periyasamy 
167b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->base_lock);
177b0c70d9SKarthikeyan Periyasamy 
187b0c70d9SKarthikeyan Periyasamy 	list_for_each_entry(peer, &ab->peers, list) {
197b0c70d9SKarthikeyan Periyasamy 		if (peer->peer_id != peer_id)
207b0c70d9SKarthikeyan Periyasamy 			continue;
217b0c70d9SKarthikeyan Periyasamy 
227b0c70d9SKarthikeyan Periyasamy 		return peer;
237b0c70d9SKarthikeyan Periyasamy 	}
247b0c70d9SKarthikeyan Periyasamy 
257b0c70d9SKarthikeyan Periyasamy 	return NULL;
267b0c70d9SKarthikeyan Periyasamy }
277b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_find(struct ath11k_base * ab,int vdev_id,const u8 * addr)28d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
29d5c65159SKalle Valo 				     const u8 *addr)
30d5c65159SKalle Valo {
31d5c65159SKalle Valo 	struct ath11k_peer *peer;
32d5c65159SKalle Valo 
33d5c65159SKalle Valo 	lockdep_assert_held(&ab->base_lock);
34d5c65159SKalle Valo 
35d5c65159SKalle Valo 	list_for_each_entry(peer, &ab->peers, list) {
36d5c65159SKalle Valo 		if (peer->vdev_id != vdev_id)
37d5c65159SKalle Valo 			continue;
381e744bf2SKarthikeyan Periyasamy 		if (!ether_addr_equal(peer->addr, addr))
391e744bf2SKarthikeyan Periyasamy 			continue;
401e744bf2SKarthikeyan Periyasamy 
411e744bf2SKarthikeyan Periyasamy 		return peer;
421e744bf2SKarthikeyan Periyasamy 	}
431e744bf2SKarthikeyan Periyasamy 
441e744bf2SKarthikeyan Periyasamy 	return NULL;
451e744bf2SKarthikeyan Periyasamy }
461e744bf2SKarthikeyan Periyasamy 
ath11k_peer_find_by_addr(struct ath11k_base * ab,const u8 * addr)47d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
48d5c65159SKalle Valo 					     const u8 *addr)
49d5c65159SKalle Valo {
50d5c65159SKalle Valo 	struct ath11k_peer *peer;
51d5c65159SKalle Valo 
52d5c65159SKalle Valo 	lockdep_assert_held(&ab->base_lock);
53d5c65159SKalle Valo 
547b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_addr)
557b0c70d9SKarthikeyan Periyasamy 		return NULL;
567b0c70d9SKarthikeyan Periyasamy 
577b0c70d9SKarthikeyan Periyasamy 	peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
587b0c70d9SKarthikeyan Periyasamy 				      ab->rhash_peer_addr_param);
59d5c65159SKalle Valo 
60d5c65159SKalle Valo 	return peer;
61d5c65159SKalle Valo }
62d5c65159SKalle Valo 
ath11k_peer_find_by_id(struct ath11k_base * ab,int peer_id)63d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
64d5c65159SKalle Valo 					   int peer_id)
65d5c65159SKalle Valo {
66d5c65159SKalle Valo 	struct ath11k_peer *peer;
67d5c65159SKalle Valo 
68d5c65159SKalle Valo 	lockdep_assert_held(&ab->base_lock);
69d5c65159SKalle Valo 
707b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_id)
71d5c65159SKalle Valo 		return NULL;
727b0c70d9SKarthikeyan Periyasamy 
737b0c70d9SKarthikeyan Periyasamy 	peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
747b0c70d9SKarthikeyan Periyasamy 				      ab->rhash_peer_id_param);
757b0c70d9SKarthikeyan Periyasamy 
767b0c70d9SKarthikeyan Periyasamy 	return peer;
77d5c65159SKalle Valo }
78d5c65159SKalle Valo 
ath11k_peer_find_by_vdev_id(struct ath11k_base * ab,int vdev_id)79aa44b2f3SCarl Huang struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
80aa44b2f3SCarl Huang 						int vdev_id)
81aa44b2f3SCarl Huang {
82aa44b2f3SCarl Huang 	struct ath11k_peer *peer;
83aa44b2f3SCarl Huang 
84aa44b2f3SCarl Huang 	spin_lock_bh(&ab->base_lock);
85aa44b2f3SCarl Huang 
86aa44b2f3SCarl Huang 	list_for_each_entry(peer, &ab->peers, list) {
87aa44b2f3SCarl Huang 		if (vdev_id == peer->vdev_id) {
88aa44b2f3SCarl Huang 			spin_unlock_bh(&ab->base_lock);
89aa44b2f3SCarl Huang 			return peer;
90aa44b2f3SCarl Huang 		}
91aa44b2f3SCarl Huang 	}
92aa44b2f3SCarl Huang 	spin_unlock_bh(&ab->base_lock);
93aa44b2f3SCarl Huang 	return NULL;
94aa44b2f3SCarl Huang }
95aa44b2f3SCarl Huang 
ath11k_peer_unmap_event(struct ath11k_base * ab,u16 peer_id)96d5c65159SKalle Valo void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
97d5c65159SKalle Valo {
98d5c65159SKalle Valo 	struct ath11k_peer *peer;
99d5c65159SKalle Valo 
100d5c65159SKalle Valo 	spin_lock_bh(&ab->base_lock);
101d5c65159SKalle Valo 
1027b0c70d9SKarthikeyan Periyasamy 	peer = ath11k_peer_find_list_by_id(ab, peer_id);
103d5c65159SKalle Valo 	if (!peer) {
104d5c65159SKalle Valo 		ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
105d5c65159SKalle Valo 			    peer_id);
106d5c65159SKalle Valo 		goto exit;
107d5c65159SKalle Valo 	}
108d5c65159SKalle Valo 
109*fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer unmap vdev %d peer %pM id %d\n",
110d5c65159SKalle Valo 		   peer->vdev_id, peer->addr, peer_id);
111d5c65159SKalle Valo 
112d5c65159SKalle Valo 	list_del(&peer->list);
113d5c65159SKalle Valo 	kfree(peer);
114d5c65159SKalle Valo 	wake_up(&ab->peer_mapping_wq);
115d5c65159SKalle Valo 
116d5c65159SKalle Valo exit:
117d5c65159SKalle Valo 	spin_unlock_bh(&ab->base_lock);
118d5c65159SKalle Valo }
119d5c65159SKalle Valo 
ath11k_peer_map_event(struct ath11k_base * ab,u8 vdev_id,u16 peer_id,u8 * mac_addr,u16 ast_hash,u16 hw_peer_id)120d5c65159SKalle Valo void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
1214b965be5SKarthikeyan Periyasamy 			   u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
122d5c65159SKalle Valo {
123d5c65159SKalle Valo 	struct ath11k_peer *peer;
124d5c65159SKalle Valo 
125d5c65159SKalle Valo 	spin_lock_bh(&ab->base_lock);
126d5c65159SKalle Valo 	peer = ath11k_peer_find(ab, vdev_id, mac_addr);
127d5c65159SKalle Valo 	if (!peer) {
128d5c65159SKalle Valo 		peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
129d5c65159SKalle Valo 		if (!peer)
130d5c65159SKalle Valo 			goto exit;
131d5c65159SKalle Valo 
132d5c65159SKalle Valo 		peer->vdev_id = vdev_id;
133d5c65159SKalle Valo 		peer->peer_id = peer_id;
134d5c65159SKalle Valo 		peer->ast_hash = ast_hash;
1354b965be5SKarthikeyan Periyasamy 		peer->hw_peer_id = hw_peer_id;
136d5c65159SKalle Valo 		ether_addr_copy(peer->addr, mac_addr);
137d5c65159SKalle Valo 		list_add(&peer->list, &ab->peers);
138d5c65159SKalle Valo 		wake_up(&ab->peer_mapping_wq);
139d5c65159SKalle Valo 	}
140d5c65159SKalle Valo 
141*fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer map vdev %d peer %pM id %d\n",
142d5c65159SKalle Valo 		   vdev_id, mac_addr, peer_id);
143d5c65159SKalle Valo 
144d5c65159SKalle Valo exit:
145d5c65159SKalle Valo 	spin_unlock_bh(&ab->base_lock);
146d5c65159SKalle Valo }
147d5c65159SKalle Valo 
ath11k_wait_for_peer_common(struct ath11k_base * ab,int vdev_id,const u8 * addr,bool expect_mapped)148d5c65159SKalle Valo static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
149d5c65159SKalle Valo 				       const u8 *addr, bool expect_mapped)
150d5c65159SKalle Valo {
151d5c65159SKalle Valo 	int ret;
152d5c65159SKalle Valo 
153d5c65159SKalle Valo 	ret = wait_event_timeout(ab->peer_mapping_wq, ({
154d5c65159SKalle Valo 				bool mapped;
155d5c65159SKalle Valo 
156d5c65159SKalle Valo 				spin_lock_bh(&ab->base_lock);
157d5c65159SKalle Valo 				mapped = !!ath11k_peer_find(ab, vdev_id, addr);
158d5c65159SKalle Valo 				spin_unlock_bh(&ab->base_lock);
159d5c65159SKalle Valo 
160d5c65159SKalle Valo 				(mapped == expect_mapped ||
161d5c65159SKalle Valo 				 test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags));
162d5c65159SKalle Valo 				}), 3 * HZ);
163d5c65159SKalle Valo 
164d5c65159SKalle Valo 	if (ret <= 0)
165d5c65159SKalle Valo 		return -ETIMEDOUT;
166d5c65159SKalle Valo 
167d5c65159SKalle Valo 	return 0;
168d5c65159SKalle Valo }
169d5c65159SKalle Valo 
ath11k_peer_rhash_insert(struct ath11k_base * ab,struct rhashtable * rtbl,struct rhash_head * rhead,struct rhashtable_params * params,void * key)1707b0c70d9SKarthikeyan Periyasamy static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
1717b0c70d9SKarthikeyan Periyasamy 					   struct rhashtable *rtbl,
1727b0c70d9SKarthikeyan Periyasamy 					   struct rhash_head *rhead,
1737b0c70d9SKarthikeyan Periyasamy 					   struct rhashtable_params *params,
1747b0c70d9SKarthikeyan Periyasamy 					   void *key)
1757b0c70d9SKarthikeyan Periyasamy {
1767b0c70d9SKarthikeyan Periyasamy 	struct ath11k_peer *tmp;
1777b0c70d9SKarthikeyan Periyasamy 
1787b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
1797b0c70d9SKarthikeyan Periyasamy 
1807b0c70d9SKarthikeyan Periyasamy 	tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
1817b0c70d9SKarthikeyan Periyasamy 
1827b0c70d9SKarthikeyan Periyasamy 	if (!tmp)
1837b0c70d9SKarthikeyan Periyasamy 		return 0;
1847b0c70d9SKarthikeyan Periyasamy 	else if (IS_ERR(tmp))
1857b0c70d9SKarthikeyan Periyasamy 		return PTR_ERR(tmp);
1867b0c70d9SKarthikeyan Periyasamy 	else
1877b0c70d9SKarthikeyan Periyasamy 		return -EEXIST;
1887b0c70d9SKarthikeyan Periyasamy }
1897b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_remove(struct ath11k_base * ab,struct rhashtable * rtbl,struct rhash_head * rhead,struct rhashtable_params * params)1907b0c70d9SKarthikeyan Periyasamy static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
1917b0c70d9SKarthikeyan Periyasamy 					   struct rhashtable *rtbl,
1927b0c70d9SKarthikeyan Periyasamy 					   struct rhash_head *rhead,
1937b0c70d9SKarthikeyan Periyasamy 					   struct rhashtable_params *params)
1947b0c70d9SKarthikeyan Periyasamy {
1957b0c70d9SKarthikeyan Periyasamy 	int ret;
1967b0c70d9SKarthikeyan Periyasamy 
1977b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
1987b0c70d9SKarthikeyan Periyasamy 
1997b0c70d9SKarthikeyan Periyasamy 	ret = rhashtable_remove_fast(rtbl, rhead, *params);
2007b0c70d9SKarthikeyan Periyasamy 	if (ret && ret != -ENOENT)
2017b0c70d9SKarthikeyan Periyasamy 		return ret;
2027b0c70d9SKarthikeyan Periyasamy 
2037b0c70d9SKarthikeyan Periyasamy 	return 0;
2047b0c70d9SKarthikeyan Periyasamy }
2057b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_add(struct ath11k_base * ab,struct ath11k_peer * peer)2067b0c70d9SKarthikeyan Periyasamy static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
2077b0c70d9SKarthikeyan Periyasamy {
2087b0c70d9SKarthikeyan Periyasamy 	int ret;
2097b0c70d9SKarthikeyan Periyasamy 
2107b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->base_lock);
2117b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
2127b0c70d9SKarthikeyan Periyasamy 
2137b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
2147b0c70d9SKarthikeyan Periyasamy 		return -EPERM;
2157b0c70d9SKarthikeyan Periyasamy 
2167b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
2177b0c70d9SKarthikeyan Periyasamy 				       &ab->rhash_peer_id_param, &peer->peer_id);
2187b0c70d9SKarthikeyan Periyasamy 	if (ret) {
2197b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
2207b0c70d9SKarthikeyan Periyasamy 			    peer->addr, peer->peer_id, ret);
2217b0c70d9SKarthikeyan Periyasamy 		return ret;
2227b0c70d9SKarthikeyan Periyasamy 	}
2237b0c70d9SKarthikeyan Periyasamy 
2247b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
2257b0c70d9SKarthikeyan Periyasamy 				       &ab->rhash_peer_addr_param, &peer->addr);
2267b0c70d9SKarthikeyan Periyasamy 	if (ret) {
2277b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
2287b0c70d9SKarthikeyan Periyasamy 			    peer->addr, peer->peer_id, ret);
2297b0c70d9SKarthikeyan Periyasamy 		goto err_clean;
2307b0c70d9SKarthikeyan Periyasamy 	}
2317b0c70d9SKarthikeyan Periyasamy 
2327b0c70d9SKarthikeyan Periyasamy 	return 0;
2337b0c70d9SKarthikeyan Periyasamy 
2347b0c70d9SKarthikeyan Periyasamy err_clean:
2357b0c70d9SKarthikeyan Periyasamy 	ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
2367b0c70d9SKarthikeyan Periyasamy 				 &ab->rhash_peer_id_param);
2377b0c70d9SKarthikeyan Periyasamy 	return ret;
2387b0c70d9SKarthikeyan Periyasamy }
2397b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_cleanup(struct ath11k * ar,u32 vdev_id)240d5c65159SKalle Valo void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
241d5c65159SKalle Valo {
242d5c65159SKalle Valo 	struct ath11k_peer *peer, *tmp;
243d5c65159SKalle Valo 	struct ath11k_base *ab = ar->ab;
244d5c65159SKalle Valo 
245d5c65159SKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
246d5c65159SKalle Valo 
2477b0c70d9SKarthikeyan Periyasamy 	mutex_lock(&ab->tbl_mtx_lock);
248d5c65159SKalle Valo 	spin_lock_bh(&ab->base_lock);
249d5c65159SKalle Valo 	list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
250d5c65159SKalle Valo 		if (peer->vdev_id != vdev_id)
251d5c65159SKalle Valo 			continue;
252d5c65159SKalle Valo 
253d5c65159SKalle Valo 		ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
254d5c65159SKalle Valo 			    peer->addr, vdev_id);
255d5c65159SKalle Valo 
2567b0c70d9SKarthikeyan Periyasamy 		ath11k_peer_rhash_delete(ab, peer);
257d5c65159SKalle Valo 		list_del(&peer->list);
258d5c65159SKalle Valo 		kfree(peer);
259d5c65159SKalle Valo 		ar->num_peers--;
260d5c65159SKalle Valo 	}
261d5c65159SKalle Valo 
262d5c65159SKalle Valo 	spin_unlock_bh(&ab->base_lock);
2637b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ab->tbl_mtx_lock);
264d5c65159SKalle Valo }
265d5c65159SKalle Valo 
ath11k_wait_for_peer_deleted(struct ath11k * ar,int vdev_id,const u8 * addr)266d5c65159SKalle Valo static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
267d5c65159SKalle Valo {
268d5c65159SKalle Valo 	return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
269d5c65159SKalle Valo }
270d5c65159SKalle Valo 
ath11k_wait_for_peer_delete_done(struct ath11k * ar,u32 vdev_id,const u8 * addr)271690ace20SRitesh Singh int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
272690ace20SRitesh Singh 				     const u8 *addr)
273690ace20SRitesh Singh {
274690ace20SRitesh Singh 	int ret;
275690ace20SRitesh Singh 	unsigned long time_left;
276690ace20SRitesh Singh 
277690ace20SRitesh Singh 	ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
278690ace20SRitesh Singh 	if (ret) {
279690ace20SRitesh Singh 		ath11k_warn(ar->ab, "failed wait for peer deleted");
280690ace20SRitesh Singh 		return ret;
281690ace20SRitesh Singh 	}
282690ace20SRitesh Singh 
283690ace20SRitesh Singh 	time_left = wait_for_completion_timeout(&ar->peer_delete_done,
284690ace20SRitesh Singh 						3 * HZ);
285690ace20SRitesh Singh 	if (time_left == 0) {
286690ace20SRitesh Singh 		ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
287690ace20SRitesh Singh 		return -ETIMEDOUT;
288690ace20SRitesh Singh 	}
289690ace20SRitesh Singh 
290690ace20SRitesh Singh 	return 0;
291690ace20SRitesh Singh }
292690ace20SRitesh Singh 
__ath11k_peer_delete(struct ath11k * ar,u32 vdev_id,const u8 * addr)293997dc60fSKarthikeyan Periyasamy static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
294d5c65159SKalle Valo {
295d5c65159SKalle Valo 	int ret;
2967b0c70d9SKarthikeyan Periyasamy 	struct ath11k_peer *peer;
2977b0c70d9SKarthikeyan Periyasamy 	struct ath11k_base *ab = ar->ab;
298d5c65159SKalle Valo 
299d5c65159SKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
300d5c65159SKalle Valo 
3017b0c70d9SKarthikeyan Periyasamy 	mutex_lock(&ab->tbl_mtx_lock);
3027b0c70d9SKarthikeyan Periyasamy 	spin_lock_bh(&ab->base_lock);
3037b0c70d9SKarthikeyan Periyasamy 
3047b0c70d9SKarthikeyan Periyasamy 	peer = ath11k_peer_find_by_addr(ab, addr);
305d673cb6fSChristian 'Ansuel' Marangi 	/* Check if the found peer is what we want to remove.
306d673cb6fSChristian 'Ansuel' Marangi 	 * While the sta is transitioning to another band we may
307d673cb6fSChristian 'Ansuel' Marangi 	 * have 2 peer with the same addr assigned to different
308d673cb6fSChristian 'Ansuel' Marangi 	 * vdev_id. Make sure we are deleting the correct peer.
309d673cb6fSChristian 'Ansuel' Marangi 	 */
310d673cb6fSChristian 'Ansuel' Marangi 	if (peer && peer->vdev_id == vdev_id)
311d673cb6fSChristian 'Ansuel' Marangi 		ath11k_peer_rhash_delete(ab, peer);
312d673cb6fSChristian 'Ansuel' Marangi 
313d673cb6fSChristian 'Ansuel' Marangi 	/* Fallback to peer list search if the correct peer can't be found.
314d673cb6fSChristian 'Ansuel' Marangi 	 * Skip the deletion of the peer from the rhash since it has already
315d673cb6fSChristian 'Ansuel' Marangi 	 * been deleted in peer add.
316d673cb6fSChristian 'Ansuel' Marangi 	 */
317d673cb6fSChristian 'Ansuel' Marangi 	if (!peer)
318d673cb6fSChristian 'Ansuel' Marangi 		peer = ath11k_peer_find(ab, vdev_id, addr);
319d673cb6fSChristian 'Ansuel' Marangi 
3207b0c70d9SKarthikeyan Periyasamy 	if (!peer) {
3217b0c70d9SKarthikeyan Periyasamy 		spin_unlock_bh(&ab->base_lock);
3227b0c70d9SKarthikeyan Periyasamy 		mutex_unlock(&ab->tbl_mtx_lock);
3237b0c70d9SKarthikeyan Periyasamy 
3247b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab,
3257b0c70d9SKarthikeyan Periyasamy 			    "failed to find peer vdev_id %d addr %pM in delete\n",
3267b0c70d9SKarthikeyan Periyasamy 			    vdev_id, addr);
3277b0c70d9SKarthikeyan Periyasamy 		return -EINVAL;
3287b0c70d9SKarthikeyan Periyasamy 	}
3297b0c70d9SKarthikeyan Periyasamy 
3307b0c70d9SKarthikeyan Periyasamy 	spin_unlock_bh(&ab->base_lock);
3317b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ab->tbl_mtx_lock);
3327b0c70d9SKarthikeyan Periyasamy 
333690ace20SRitesh Singh 	reinit_completion(&ar->peer_delete_done);
334690ace20SRitesh Singh 
335d5c65159SKalle Valo 	ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
336d5c65159SKalle Valo 	if (ret) {
3377b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab,
338d5c65159SKalle Valo 			    "failed to delete peer vdev_id %d addr %pM ret %d\n",
339d5c65159SKalle Valo 			    vdev_id, addr, ret);
340d5c65159SKalle Valo 		return ret;
341d5c65159SKalle Valo 	}
342d5c65159SKalle Valo 
343690ace20SRitesh Singh 	ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
344d5c65159SKalle Valo 	if (ret)
345d5c65159SKalle Valo 		return ret;
346d5c65159SKalle Valo 
347997dc60fSKarthikeyan Periyasamy 	return 0;
348997dc60fSKarthikeyan Periyasamy }
349997dc60fSKarthikeyan Periyasamy 
ath11k_peer_delete(struct ath11k * ar,u32 vdev_id,u8 * addr)350997dc60fSKarthikeyan Periyasamy int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
351997dc60fSKarthikeyan Periyasamy {
352997dc60fSKarthikeyan Periyasamy 	int ret;
353997dc60fSKarthikeyan Periyasamy 
354997dc60fSKarthikeyan Periyasamy 	lockdep_assert_held(&ar->conf_mutex);
355997dc60fSKarthikeyan Periyasamy 
356997dc60fSKarthikeyan Periyasamy 	ret = __ath11k_peer_delete(ar, vdev_id, addr);
357997dc60fSKarthikeyan Periyasamy 	if (ret)
358997dc60fSKarthikeyan Periyasamy 		return ret;
359997dc60fSKarthikeyan Periyasamy 
360d5c65159SKalle Valo 	ar->num_peers--;
361d5c65159SKalle Valo 
362d5c65159SKalle Valo 	return 0;
363d5c65159SKalle Valo }
364d5c65159SKalle Valo 
ath11k_wait_for_peer_created(struct ath11k * ar,int vdev_id,const u8 * addr)365d5c65159SKalle Valo static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr)
366d5c65159SKalle Valo {
367d5c65159SKalle Valo 	return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
368d5c65159SKalle Valo }
369d5c65159SKalle Valo 
ath11k_peer_create(struct ath11k * ar,struct ath11k_vif * arvif,struct ieee80211_sta * sta,struct peer_create_params * param)370d5c65159SKalle Valo int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
371d5c65159SKalle Valo 		       struct ieee80211_sta *sta, struct peer_create_params *param)
372d5c65159SKalle Valo {
373d5c65159SKalle Valo 	struct ath11k_peer *peer;
374e20cfa3bSKarthikeyan Periyasamy 	struct ath11k_sta *arsta;
375fbed57d8SKarthikeyan Periyasamy 	int ret, fbret;
376d5c65159SKalle Valo 
377d5c65159SKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
378d5c65159SKalle Valo 
379d5c65159SKalle Valo 	if (ar->num_peers > (ar->max_num_peers - 1)) {
380d5c65159SKalle Valo 		ath11k_warn(ar->ab,
381d5c65159SKalle Valo 			    "failed to create peer due to insufficient peer entry resource in firmware\n");
382d5c65159SKalle Valo 		return -ENOBUFS;
383d5c65159SKalle Valo 	}
384d5c65159SKalle Valo 
38560b7d62bSChristian Marangi 	mutex_lock(&ar->ab->tbl_mtx_lock);
3861e744bf2SKarthikeyan Periyasamy 	spin_lock_bh(&ar->ab->base_lock);
3877b0c70d9SKarthikeyan Periyasamy 	peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
3881e744bf2SKarthikeyan Periyasamy 	if (peer) {
389d673cb6fSChristian 'Ansuel' Marangi 		if (peer->vdev_id == param->vdev_id) {
3901e744bf2SKarthikeyan Periyasamy 			spin_unlock_bh(&ar->ab->base_lock);
39160b7d62bSChristian Marangi 			mutex_unlock(&ar->ab->tbl_mtx_lock);
3921e744bf2SKarthikeyan Periyasamy 			return -EINVAL;
3931e744bf2SKarthikeyan Periyasamy 		}
394d673cb6fSChristian 'Ansuel' Marangi 
395d673cb6fSChristian 'Ansuel' Marangi 		/* Assume sta is transitioning to another band.
396d673cb6fSChristian 'Ansuel' Marangi 		 * Remove here the peer from rhash.
397d673cb6fSChristian 'Ansuel' Marangi 		 */
398d673cb6fSChristian 'Ansuel' Marangi 		ath11k_peer_rhash_delete(ar->ab, peer);
399d673cb6fSChristian 'Ansuel' Marangi 	}
4001e744bf2SKarthikeyan Periyasamy 	spin_unlock_bh(&ar->ab->base_lock);
40160b7d62bSChristian Marangi 	mutex_unlock(&ar->ab->tbl_mtx_lock);
4021e744bf2SKarthikeyan Periyasamy 
403d5c65159SKalle Valo 	ret = ath11k_wmi_send_peer_create_cmd(ar, param);
404d5c65159SKalle Valo 	if (ret) {
405d5c65159SKalle Valo 		ath11k_warn(ar->ab,
406d5c65159SKalle Valo 			    "failed to send peer create vdev_id %d ret %d\n",
407d5c65159SKalle Valo 			    param->vdev_id, ret);
408d5c65159SKalle Valo 		return ret;
409d5c65159SKalle Valo 	}
410d5c65159SKalle Valo 
411d5c65159SKalle Valo 	ret = ath11k_wait_for_peer_created(ar, param->vdev_id,
412d5c65159SKalle Valo 					   param->peer_addr);
413d5c65159SKalle Valo 	if (ret)
414d5c65159SKalle Valo 		return ret;
415d5c65159SKalle Valo 
4167b0c70d9SKarthikeyan Periyasamy 	mutex_lock(&ar->ab->tbl_mtx_lock);
417d5c65159SKalle Valo 	spin_lock_bh(&ar->ab->base_lock);
418d5c65159SKalle Valo 
419d5c65159SKalle Valo 	peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
420d5c65159SKalle Valo 	if (!peer) {
421d5c65159SKalle Valo 		spin_unlock_bh(&ar->ab->base_lock);
4227b0c70d9SKarthikeyan Periyasamy 		mutex_unlock(&ar->ab->tbl_mtx_lock);
423d5c65159SKalle Valo 		ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
424d5c65159SKalle Valo 			    param->peer_addr, param->vdev_id);
425690ace20SRitesh Singh 
426fbed57d8SKarthikeyan Periyasamy 		ret = -ENOENT;
427fbed57d8SKarthikeyan Periyasamy 		goto cleanup;
428d5c65159SKalle Valo 	}
429d5c65159SKalle Valo 
4307b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_add(ar->ab, peer);
4317b0c70d9SKarthikeyan Periyasamy 	if (ret) {
4327b0c70d9SKarthikeyan Periyasamy 		spin_unlock_bh(&ar->ab->base_lock);
4337b0c70d9SKarthikeyan Periyasamy 		mutex_unlock(&ar->ab->tbl_mtx_lock);
4347b0c70d9SKarthikeyan Periyasamy 		goto cleanup;
4357b0c70d9SKarthikeyan Periyasamy 	}
4367b0c70d9SKarthikeyan Periyasamy 
4371e744bf2SKarthikeyan Periyasamy 	peer->pdev_idx = ar->pdev_idx;
438d5c65159SKalle Valo 	peer->sta = sta;
4394b965be5SKarthikeyan Periyasamy 
4404b965be5SKarthikeyan Periyasamy 	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
441d5c65159SKalle Valo 		arvif->ast_hash = peer->ast_hash;
4424b965be5SKarthikeyan Periyasamy 		arvif->ast_idx = peer->hw_peer_id;
4434b965be5SKarthikeyan Periyasamy 	}
444d5c65159SKalle Valo 
445acc79d98SSriram R 	peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
446acc79d98SSriram R 	peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
447acc79d98SSriram R 
448e20cfa3bSKarthikeyan Periyasamy 	if (sta) {
449e20cfa3bSKarthikeyan Periyasamy 		arsta = (struct ath11k_sta *)sta->drv_priv;
450e20cfa3bSKarthikeyan Periyasamy 		arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
451e20cfa3bSKarthikeyan Periyasamy 				       FIELD_PREP(HTT_TCL_META_DATA_PEER_ID,
452e20cfa3bSKarthikeyan Periyasamy 						  peer->peer_id);
453e20cfa3bSKarthikeyan Periyasamy 
454e20cfa3bSKarthikeyan Periyasamy 		/* set HTT extension valid bit to 0 by default */
455e20cfa3bSKarthikeyan Periyasamy 		arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
456e20cfa3bSKarthikeyan Periyasamy 	}
457e20cfa3bSKarthikeyan Periyasamy 
458d5c65159SKalle Valo 	ar->num_peers++;
459d5c65159SKalle Valo 
460d5c65159SKalle Valo 	spin_unlock_bh(&ar->ab->base_lock);
4617b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ar->ab->tbl_mtx_lock);
462d5c65159SKalle Valo 
463d5c65159SKalle Valo 	return 0;
464fbed57d8SKarthikeyan Periyasamy 
465fbed57d8SKarthikeyan Periyasamy cleanup:
466997dc60fSKarthikeyan Periyasamy 	fbret = __ath11k_peer_delete(ar, param->vdev_id, param->peer_addr);
467fbed57d8SKarthikeyan Periyasamy 	if (fbret)
468997dc60fSKarthikeyan Periyasamy 		ath11k_warn(ar->ab, "failed peer %pM delete vdev_id %d fallback ret %d\n",
469fbed57d8SKarthikeyan Periyasamy 			    param->peer_addr, param->vdev_id, fbret);
470fbed57d8SKarthikeyan Periyasamy 
471fbed57d8SKarthikeyan Periyasamy 	return ret;
472d5c65159SKalle Valo }
4737b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_delete(struct ath11k_base * ab,struct ath11k_peer * peer)4747b0c70d9SKarthikeyan Periyasamy int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
4757b0c70d9SKarthikeyan Periyasamy {
4767b0c70d9SKarthikeyan Periyasamy 	int ret;
4777b0c70d9SKarthikeyan Periyasamy 
4787b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->base_lock);
4797b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
4807b0c70d9SKarthikeyan Periyasamy 
4817b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
4827b0c70d9SKarthikeyan Periyasamy 		return -EPERM;
4837b0c70d9SKarthikeyan Periyasamy 
4847b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
4857b0c70d9SKarthikeyan Periyasamy 				       &ab->rhash_peer_addr_param);
4867b0c70d9SKarthikeyan Periyasamy 	if (ret) {
4877b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
4887b0c70d9SKarthikeyan Periyasamy 			    peer->addr, peer->peer_id, ret);
4897b0c70d9SKarthikeyan Periyasamy 		return ret;
4907b0c70d9SKarthikeyan Periyasamy 	}
4917b0c70d9SKarthikeyan Periyasamy 
4927b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
4937b0c70d9SKarthikeyan Periyasamy 				       &ab->rhash_peer_id_param);
4947b0c70d9SKarthikeyan Periyasamy 	if (ret) {
4957b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
4967b0c70d9SKarthikeyan Periyasamy 			    peer->addr, peer->peer_id, ret);
4977b0c70d9SKarthikeyan Periyasamy 		return ret;
4987b0c70d9SKarthikeyan Periyasamy 	}
4997b0c70d9SKarthikeyan Periyasamy 
5007b0c70d9SKarthikeyan Periyasamy 	return 0;
5017b0c70d9SKarthikeyan Periyasamy }
5027b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_id_tbl_init(struct ath11k_base * ab)5037b0c70d9SKarthikeyan Periyasamy static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
5047b0c70d9SKarthikeyan Periyasamy {
5057b0c70d9SKarthikeyan Periyasamy 	struct rhashtable_params *param;
5067b0c70d9SKarthikeyan Periyasamy 	struct rhashtable *rhash_id_tbl;
5077b0c70d9SKarthikeyan Periyasamy 	int ret;
5087b0c70d9SKarthikeyan Periyasamy 	size_t size;
5097b0c70d9SKarthikeyan Periyasamy 
5107b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
5117b0c70d9SKarthikeyan Periyasamy 
5127b0c70d9SKarthikeyan Periyasamy 	if (ab->rhead_peer_id)
5137b0c70d9SKarthikeyan Periyasamy 		return 0;
5147b0c70d9SKarthikeyan Periyasamy 
5157b0c70d9SKarthikeyan Periyasamy 	size = sizeof(*ab->rhead_peer_id);
5167b0c70d9SKarthikeyan Periyasamy 	rhash_id_tbl = kzalloc(size, GFP_KERNEL);
5177b0c70d9SKarthikeyan Periyasamy 	if (!rhash_id_tbl) {
5187b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
5197b0c70d9SKarthikeyan Periyasamy 			    size);
5207b0c70d9SKarthikeyan Periyasamy 		return -ENOMEM;
5217b0c70d9SKarthikeyan Periyasamy 	}
5227b0c70d9SKarthikeyan Periyasamy 
5237b0c70d9SKarthikeyan Periyasamy 	param = &ab->rhash_peer_id_param;
5247b0c70d9SKarthikeyan Periyasamy 
5257b0c70d9SKarthikeyan Periyasamy 	param->key_offset = offsetof(struct ath11k_peer, peer_id);
5267b0c70d9SKarthikeyan Periyasamy 	param->head_offset = offsetof(struct ath11k_peer, rhash_id);
5277b0c70d9SKarthikeyan Periyasamy 	param->key_len = sizeof_field(struct ath11k_peer, peer_id);
5287b0c70d9SKarthikeyan Periyasamy 	param->automatic_shrinking = true;
5297b0c70d9SKarthikeyan Periyasamy 	param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
5307b0c70d9SKarthikeyan Periyasamy 
5317b0c70d9SKarthikeyan Periyasamy 	ret = rhashtable_init(rhash_id_tbl, param);
5327b0c70d9SKarthikeyan Periyasamy 	if (ret) {
5337b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
5347b0c70d9SKarthikeyan Periyasamy 		goto err_free;
5357b0c70d9SKarthikeyan Periyasamy 	}
5367b0c70d9SKarthikeyan Periyasamy 
5377b0c70d9SKarthikeyan Periyasamy 	spin_lock_bh(&ab->base_lock);
5387b0c70d9SKarthikeyan Periyasamy 
5397b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_id) {
5407b0c70d9SKarthikeyan Periyasamy 		ab->rhead_peer_id = rhash_id_tbl;
5417b0c70d9SKarthikeyan Periyasamy 	} else {
5427b0c70d9SKarthikeyan Periyasamy 		spin_unlock_bh(&ab->base_lock);
5437b0c70d9SKarthikeyan Periyasamy 		goto cleanup_tbl;
5447b0c70d9SKarthikeyan Periyasamy 	}
5457b0c70d9SKarthikeyan Periyasamy 
5467b0c70d9SKarthikeyan Periyasamy 	spin_unlock_bh(&ab->base_lock);
5477b0c70d9SKarthikeyan Periyasamy 
5487b0c70d9SKarthikeyan Periyasamy 	return 0;
5497b0c70d9SKarthikeyan Periyasamy 
5507b0c70d9SKarthikeyan Periyasamy cleanup_tbl:
5517b0c70d9SKarthikeyan Periyasamy 	rhashtable_destroy(rhash_id_tbl);
5527b0c70d9SKarthikeyan Periyasamy err_free:
5537b0c70d9SKarthikeyan Periyasamy 	kfree(rhash_id_tbl);
5547b0c70d9SKarthikeyan Periyasamy 
5557b0c70d9SKarthikeyan Periyasamy 	return ret;
5567b0c70d9SKarthikeyan Periyasamy }
5577b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_addr_tbl_init(struct ath11k_base * ab)5587b0c70d9SKarthikeyan Periyasamy static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
5597b0c70d9SKarthikeyan Periyasamy {
5607b0c70d9SKarthikeyan Periyasamy 	struct rhashtable_params *param;
5617b0c70d9SKarthikeyan Periyasamy 	struct rhashtable *rhash_addr_tbl;
5627b0c70d9SKarthikeyan Periyasamy 	int ret;
5637b0c70d9SKarthikeyan Periyasamy 	size_t size;
5647b0c70d9SKarthikeyan Periyasamy 
5657b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
5667b0c70d9SKarthikeyan Periyasamy 
5677b0c70d9SKarthikeyan Periyasamy 	if (ab->rhead_peer_addr)
5687b0c70d9SKarthikeyan Periyasamy 		return 0;
5697b0c70d9SKarthikeyan Periyasamy 
5707b0c70d9SKarthikeyan Periyasamy 	size = sizeof(*ab->rhead_peer_addr);
5717b0c70d9SKarthikeyan Periyasamy 	rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
5727b0c70d9SKarthikeyan Periyasamy 	if (!rhash_addr_tbl) {
5737b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
5747b0c70d9SKarthikeyan Periyasamy 			    size);
5757b0c70d9SKarthikeyan Periyasamy 		return -ENOMEM;
5767b0c70d9SKarthikeyan Periyasamy 	}
5777b0c70d9SKarthikeyan Periyasamy 
5787b0c70d9SKarthikeyan Periyasamy 	param = &ab->rhash_peer_addr_param;
5797b0c70d9SKarthikeyan Periyasamy 
5807b0c70d9SKarthikeyan Periyasamy 	param->key_offset = offsetof(struct ath11k_peer, addr);
5817b0c70d9SKarthikeyan Periyasamy 	param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
5827b0c70d9SKarthikeyan Periyasamy 	param->key_len = sizeof_field(struct ath11k_peer, addr);
5837b0c70d9SKarthikeyan Periyasamy 	param->automatic_shrinking = true;
5847b0c70d9SKarthikeyan Periyasamy 	param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
5857b0c70d9SKarthikeyan Periyasamy 
5867b0c70d9SKarthikeyan Periyasamy 	ret = rhashtable_init(rhash_addr_tbl, param);
5877b0c70d9SKarthikeyan Periyasamy 	if (ret) {
5887b0c70d9SKarthikeyan Periyasamy 		ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
5897b0c70d9SKarthikeyan Periyasamy 		goto err_free;
5907b0c70d9SKarthikeyan Periyasamy 	}
5917b0c70d9SKarthikeyan Periyasamy 
5927b0c70d9SKarthikeyan Periyasamy 	spin_lock_bh(&ab->base_lock);
5937b0c70d9SKarthikeyan Periyasamy 
5947b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_addr) {
5957b0c70d9SKarthikeyan Periyasamy 		ab->rhead_peer_addr = rhash_addr_tbl;
5967b0c70d9SKarthikeyan Periyasamy 	} else {
5977b0c70d9SKarthikeyan Periyasamy 		spin_unlock_bh(&ab->base_lock);
5987b0c70d9SKarthikeyan Periyasamy 		goto cleanup_tbl;
5997b0c70d9SKarthikeyan Periyasamy 	}
6007b0c70d9SKarthikeyan Periyasamy 
6017b0c70d9SKarthikeyan Periyasamy 	spin_unlock_bh(&ab->base_lock);
6027b0c70d9SKarthikeyan Periyasamy 
6037b0c70d9SKarthikeyan Periyasamy 	return 0;
6047b0c70d9SKarthikeyan Periyasamy 
6057b0c70d9SKarthikeyan Periyasamy cleanup_tbl:
6067b0c70d9SKarthikeyan Periyasamy 	rhashtable_destroy(rhash_addr_tbl);
6077b0c70d9SKarthikeyan Periyasamy err_free:
6087b0c70d9SKarthikeyan Periyasamy 	kfree(rhash_addr_tbl);
6097b0c70d9SKarthikeyan Periyasamy 
6107b0c70d9SKarthikeyan Periyasamy 	return ret;
6117b0c70d9SKarthikeyan Periyasamy }
6127b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base * ab)6137b0c70d9SKarthikeyan Periyasamy static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
6147b0c70d9SKarthikeyan Periyasamy {
6157b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
6167b0c70d9SKarthikeyan Periyasamy 
6177b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_id)
6187b0c70d9SKarthikeyan Periyasamy 		return;
6197b0c70d9SKarthikeyan Periyasamy 
6207b0c70d9SKarthikeyan Periyasamy 	rhashtable_destroy(ab->rhead_peer_id);
6217b0c70d9SKarthikeyan Periyasamy 	kfree(ab->rhead_peer_id);
6227b0c70d9SKarthikeyan Periyasamy 	ab->rhead_peer_id = NULL;
6237b0c70d9SKarthikeyan Periyasamy }
6247b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base * ab)6257b0c70d9SKarthikeyan Periyasamy static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
6267b0c70d9SKarthikeyan Periyasamy {
6277b0c70d9SKarthikeyan Periyasamy 	lockdep_assert_held(&ab->tbl_mtx_lock);
6287b0c70d9SKarthikeyan Periyasamy 
6297b0c70d9SKarthikeyan Periyasamy 	if (!ab->rhead_peer_addr)
6307b0c70d9SKarthikeyan Periyasamy 		return;
6317b0c70d9SKarthikeyan Periyasamy 
6327b0c70d9SKarthikeyan Periyasamy 	rhashtable_destroy(ab->rhead_peer_addr);
6337b0c70d9SKarthikeyan Periyasamy 	kfree(ab->rhead_peer_addr);
6347b0c70d9SKarthikeyan Periyasamy 	ab->rhead_peer_addr = NULL;
6357b0c70d9SKarthikeyan Periyasamy }
6367b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_tbl_init(struct ath11k_base * ab)6377b0c70d9SKarthikeyan Periyasamy int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
6387b0c70d9SKarthikeyan Periyasamy {
6397b0c70d9SKarthikeyan Periyasamy 	int ret;
6407b0c70d9SKarthikeyan Periyasamy 
6417b0c70d9SKarthikeyan Periyasamy 	mutex_lock(&ab->tbl_mtx_lock);
6427b0c70d9SKarthikeyan Periyasamy 
6437b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_id_tbl_init(ab);
6447b0c70d9SKarthikeyan Periyasamy 	if (ret)
6457b0c70d9SKarthikeyan Periyasamy 		goto out;
6467b0c70d9SKarthikeyan Periyasamy 
6477b0c70d9SKarthikeyan Periyasamy 	ret = ath11k_peer_rhash_addr_tbl_init(ab);
6487b0c70d9SKarthikeyan Periyasamy 	if (ret)
6497b0c70d9SKarthikeyan Periyasamy 		goto cleanup_tbl;
6507b0c70d9SKarthikeyan Periyasamy 
6517b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ab->tbl_mtx_lock);
6527b0c70d9SKarthikeyan Periyasamy 
6537b0c70d9SKarthikeyan Periyasamy 	return 0;
6547b0c70d9SKarthikeyan Periyasamy 
6557b0c70d9SKarthikeyan Periyasamy cleanup_tbl:
6567b0c70d9SKarthikeyan Periyasamy 	ath11k_peer_rhash_id_tbl_destroy(ab);
6577b0c70d9SKarthikeyan Periyasamy out:
6587b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ab->tbl_mtx_lock);
6597b0c70d9SKarthikeyan Periyasamy 	return ret;
6607b0c70d9SKarthikeyan Periyasamy }
6617b0c70d9SKarthikeyan Periyasamy 
ath11k_peer_rhash_tbl_destroy(struct ath11k_base * ab)6627b0c70d9SKarthikeyan Periyasamy void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
6637b0c70d9SKarthikeyan Periyasamy {
6647b0c70d9SKarthikeyan Periyasamy 	mutex_lock(&ab->tbl_mtx_lock);
6657b0c70d9SKarthikeyan Periyasamy 
6667b0c70d9SKarthikeyan Periyasamy 	ath11k_peer_rhash_addr_tbl_destroy(ab);
6677b0c70d9SKarthikeyan Periyasamy 	ath11k_peer_rhash_id_tbl_destroy(ab);
6687b0c70d9SKarthikeyan Periyasamy 
6697b0c70d9SKarthikeyan Periyasamy 	mutex_unlock(&ab->tbl_mtx_lock);
6707b0c70d9SKarthikeyan Periyasamy }
671