xref: /freebsd/sys/contrib/dev/athk/ath11k/peer.c (revision 28348cae)
1dd4f32aeSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2dd4f32aeSBjoern A. Zeeb /*
3dd4f32aeSBjoern A. Zeeb  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
428348caeSBjoern A. Zeeb  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5dd4f32aeSBjoern A. Zeeb  */
6dd4f32aeSBjoern A. Zeeb 
7dd4f32aeSBjoern A. Zeeb #include "core.h"
8dd4f32aeSBjoern A. Zeeb #include "peer.h"
9dd4f32aeSBjoern A. Zeeb #include "debug.h"
10dd4f32aeSBjoern A. Zeeb 
ath11k_peer_find_list_by_id(struct ath11k_base * ab,int peer_id)1128348caeSBjoern A. Zeeb static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab,
1228348caeSBjoern A. Zeeb 						       int peer_id)
1328348caeSBjoern A. Zeeb {
1428348caeSBjoern A. Zeeb 	struct ath11k_peer *peer;
1528348caeSBjoern A. Zeeb 
1628348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
1728348caeSBjoern A. Zeeb 
1828348caeSBjoern A. Zeeb 	list_for_each_entry(peer, &ab->peers, list) {
1928348caeSBjoern A. Zeeb 		if (peer->peer_id != peer_id)
2028348caeSBjoern A. Zeeb 			continue;
2128348caeSBjoern A. Zeeb 
2228348caeSBjoern A. Zeeb 		return peer;
2328348caeSBjoern A. Zeeb 	}
2428348caeSBjoern A. Zeeb 
2528348caeSBjoern A. Zeeb 	return NULL;
2628348caeSBjoern A. Zeeb }
2728348caeSBjoern A. Zeeb 
ath11k_peer_find(struct ath11k_base * ab,int vdev_id,const u8 * addr)28dd4f32aeSBjoern A. Zeeb struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
29dd4f32aeSBjoern A. Zeeb 				     const u8 *addr)
30dd4f32aeSBjoern A. Zeeb {
31dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
32dd4f32aeSBjoern A. Zeeb 
33dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
34dd4f32aeSBjoern A. Zeeb 
35dd4f32aeSBjoern A. Zeeb 	list_for_each_entry(peer, &ab->peers, list) {
36dd4f32aeSBjoern A. Zeeb 		if (peer->vdev_id != vdev_id)
37dd4f32aeSBjoern A. Zeeb 			continue;
38dd4f32aeSBjoern A. Zeeb 		if (!ether_addr_equal(peer->addr, addr))
39dd4f32aeSBjoern A. Zeeb 			continue;
40dd4f32aeSBjoern A. Zeeb 
41dd4f32aeSBjoern A. Zeeb 		return peer;
42dd4f32aeSBjoern A. Zeeb 	}
43dd4f32aeSBjoern A. Zeeb 
44dd4f32aeSBjoern A. Zeeb 	return NULL;
45dd4f32aeSBjoern A. Zeeb }
46dd4f32aeSBjoern A. Zeeb 
ath11k_peer_find_by_addr(struct ath11k_base * ab,const u8 * addr)47dd4f32aeSBjoern A. Zeeb struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
48dd4f32aeSBjoern A. Zeeb 					     const u8 *addr)
49dd4f32aeSBjoern A. Zeeb {
50dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
51dd4f32aeSBjoern A. Zeeb 
52dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
53dd4f32aeSBjoern A. Zeeb 
5428348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_addr)
5528348caeSBjoern A. Zeeb 		return NULL;
5628348caeSBjoern A. Zeeb 
5728348caeSBjoern A. Zeeb 	peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
5828348caeSBjoern A. Zeeb 				      ab->rhash_peer_addr_param);
59dd4f32aeSBjoern A. Zeeb 
60dd4f32aeSBjoern A. Zeeb 	return peer;
61dd4f32aeSBjoern A. Zeeb }
62dd4f32aeSBjoern A. Zeeb 
ath11k_peer_find_by_id(struct ath11k_base * ab,int peer_id)63dd4f32aeSBjoern A. Zeeb struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
64dd4f32aeSBjoern A. Zeeb 					   int peer_id)
65dd4f32aeSBjoern A. Zeeb {
66dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
67dd4f32aeSBjoern A. Zeeb 
68dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
69dd4f32aeSBjoern A. Zeeb 
7028348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_id)
71dd4f32aeSBjoern A. Zeeb 		return NULL;
7228348caeSBjoern A. Zeeb 
7328348caeSBjoern A. Zeeb 	peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
7428348caeSBjoern A. Zeeb 				      ab->rhash_peer_id_param);
7528348caeSBjoern A. Zeeb 
7628348caeSBjoern A. Zeeb 	return peer;
77dd4f32aeSBjoern A. Zeeb }
78dd4f32aeSBjoern A. Zeeb 
ath11k_peer_find_by_vdev_id(struct ath11k_base * ab,int vdev_id)79dd4f32aeSBjoern A. Zeeb struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
80dd4f32aeSBjoern A. Zeeb 						int vdev_id)
81dd4f32aeSBjoern A. Zeeb {
82dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
83dd4f32aeSBjoern A. Zeeb 
84dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
85dd4f32aeSBjoern A. Zeeb 
86dd4f32aeSBjoern A. Zeeb 	list_for_each_entry(peer, &ab->peers, list) {
87dd4f32aeSBjoern A. Zeeb 		if (vdev_id == peer->vdev_id) {
88dd4f32aeSBjoern A. Zeeb 			spin_unlock_bh(&ab->base_lock);
89dd4f32aeSBjoern A. Zeeb 			return peer;
90dd4f32aeSBjoern A. Zeeb 		}
91dd4f32aeSBjoern A. Zeeb 	}
92dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
93dd4f32aeSBjoern A. Zeeb 	return NULL;
94dd4f32aeSBjoern A. Zeeb }
95dd4f32aeSBjoern A. Zeeb 
ath11k_peer_unmap_event(struct ath11k_base * ab,u16 peer_id)96dd4f32aeSBjoern A. Zeeb void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
97dd4f32aeSBjoern A. Zeeb {
98dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
99dd4f32aeSBjoern A. Zeeb 
100dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
101dd4f32aeSBjoern A. Zeeb 
10228348caeSBjoern A. Zeeb 	peer = ath11k_peer_find_list_by_id(ab, peer_id);
103dd4f32aeSBjoern A. Zeeb 	if (!peer) {
104dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
105dd4f32aeSBjoern A. Zeeb 			    peer_id);
106dd4f32aeSBjoern A. Zeeb 		goto exit;
107dd4f32aeSBjoern A. Zeeb 	}
108dd4f32aeSBjoern A. Zeeb 
10928348caeSBjoern A. Zeeb 	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer unmap vdev %d peer %pM id %d\n",
110dd4f32aeSBjoern A. Zeeb 		   peer->vdev_id, peer->addr, peer_id);
111dd4f32aeSBjoern A. Zeeb 
112dd4f32aeSBjoern A. Zeeb 	list_del(&peer->list);
113dd4f32aeSBjoern A. Zeeb 	kfree(peer);
114dd4f32aeSBjoern A. Zeeb 	wake_up(&ab->peer_mapping_wq);
115dd4f32aeSBjoern A. Zeeb 
116dd4f32aeSBjoern A. Zeeb exit:
117dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
118dd4f32aeSBjoern A. Zeeb }
119dd4f32aeSBjoern A. Zeeb 
ath11k_peer_map_event(struct ath11k_base * ab,u8 vdev_id,u16 peer_id,u8 * mac_addr,u16 ast_hash,u16 hw_peer_id)120dd4f32aeSBjoern A. Zeeb void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
121dd4f32aeSBjoern A. Zeeb 			   u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
122dd4f32aeSBjoern A. Zeeb {
123dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
124dd4f32aeSBjoern A. Zeeb 
125dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
126dd4f32aeSBjoern A. Zeeb 	peer = ath11k_peer_find(ab, vdev_id, mac_addr);
127dd4f32aeSBjoern A. Zeeb 	if (!peer) {
128dd4f32aeSBjoern A. Zeeb 		peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
129dd4f32aeSBjoern A. Zeeb 		if (!peer)
130dd4f32aeSBjoern A. Zeeb 			goto exit;
131dd4f32aeSBjoern A. Zeeb 
132dd4f32aeSBjoern A. Zeeb 		peer->vdev_id = vdev_id;
133dd4f32aeSBjoern A. Zeeb 		peer->peer_id = peer_id;
134dd4f32aeSBjoern A. Zeeb 		peer->ast_hash = ast_hash;
135dd4f32aeSBjoern A. Zeeb 		peer->hw_peer_id = hw_peer_id;
136dd4f32aeSBjoern A. Zeeb 		ether_addr_copy(peer->addr, mac_addr);
137dd4f32aeSBjoern A. Zeeb 		list_add(&peer->list, &ab->peers);
138dd4f32aeSBjoern A. Zeeb 		wake_up(&ab->peer_mapping_wq);
139dd4f32aeSBjoern A. Zeeb 	}
140dd4f32aeSBjoern A. Zeeb 
14128348caeSBjoern A. Zeeb 	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer map vdev %d peer %pM id %d\n",
142dd4f32aeSBjoern A. Zeeb 		   vdev_id, mac_addr, peer_id);
143dd4f32aeSBjoern A. Zeeb 
144dd4f32aeSBjoern A. Zeeb exit:
145dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
146dd4f32aeSBjoern A. Zeeb }
147dd4f32aeSBjoern A. Zeeb 
ath11k_wait_for_peer_common(struct ath11k_base * ab,int vdev_id,const u8 * addr,bool expect_mapped)148dd4f32aeSBjoern A. Zeeb static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
149dd4f32aeSBjoern A. Zeeb 				       const u8 *addr, bool expect_mapped)
150dd4f32aeSBjoern A. Zeeb {
151dd4f32aeSBjoern A. Zeeb 	int ret;
152dd4f32aeSBjoern A. Zeeb 
153dd4f32aeSBjoern A. Zeeb 	ret = wait_event_timeout(ab->peer_mapping_wq, ({
154dd4f32aeSBjoern A. Zeeb 				bool mapped;
155dd4f32aeSBjoern A. Zeeb 
156dd4f32aeSBjoern A. Zeeb 				spin_lock_bh(&ab->base_lock);
157dd4f32aeSBjoern A. Zeeb 				mapped = !!ath11k_peer_find(ab, vdev_id, addr);
158dd4f32aeSBjoern A. Zeeb 				spin_unlock_bh(&ab->base_lock);
159dd4f32aeSBjoern A. Zeeb 
160dd4f32aeSBjoern A. Zeeb 				(mapped == expect_mapped ||
161dd4f32aeSBjoern A. Zeeb 				 test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags));
162dd4f32aeSBjoern A. Zeeb 				}), 3 * HZ);
163dd4f32aeSBjoern A. Zeeb 
164dd4f32aeSBjoern A. Zeeb 	if (ret <= 0)
165dd4f32aeSBjoern A. Zeeb 		return -ETIMEDOUT;
166dd4f32aeSBjoern A. Zeeb 
167dd4f32aeSBjoern A. Zeeb 	return 0;
168dd4f32aeSBjoern A. Zeeb }
169dd4f32aeSBjoern A. Zeeb 
ath11k_peer_rhash_insert(struct ath11k_base * ab,struct rhashtable * rtbl,struct rhash_head * rhead,struct rhashtable_params * params,void * key)17028348caeSBjoern A. Zeeb static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
17128348caeSBjoern A. Zeeb 					   struct rhashtable *rtbl,
17228348caeSBjoern A. Zeeb 					   struct rhash_head *rhead,
17328348caeSBjoern A. Zeeb 					   struct rhashtable_params *params,
17428348caeSBjoern A. Zeeb 					   void *key)
17528348caeSBjoern A. Zeeb {
17628348caeSBjoern A. Zeeb 	struct ath11k_peer *tmp;
17728348caeSBjoern A. Zeeb 
17828348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
17928348caeSBjoern A. Zeeb 
18028348caeSBjoern A. Zeeb 	tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
18128348caeSBjoern A. Zeeb 
18228348caeSBjoern A. Zeeb 	if (!tmp)
18328348caeSBjoern A. Zeeb 		return 0;
18428348caeSBjoern A. Zeeb 	else if (IS_ERR(tmp))
18528348caeSBjoern A. Zeeb 		return PTR_ERR(tmp);
18628348caeSBjoern A. Zeeb 	else
18728348caeSBjoern A. Zeeb 		return -EEXIST;
18828348caeSBjoern A. Zeeb }
18928348caeSBjoern A. Zeeb 
ath11k_peer_rhash_remove(struct ath11k_base * ab,struct rhashtable * rtbl,struct rhash_head * rhead,struct rhashtable_params * params)19028348caeSBjoern A. Zeeb static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
19128348caeSBjoern A. Zeeb 					   struct rhashtable *rtbl,
19228348caeSBjoern A. Zeeb 					   struct rhash_head *rhead,
19328348caeSBjoern A. Zeeb 					   struct rhashtable_params *params)
19428348caeSBjoern A. Zeeb {
19528348caeSBjoern A. Zeeb 	int ret;
19628348caeSBjoern A. Zeeb 
19728348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
19828348caeSBjoern A. Zeeb 
19928348caeSBjoern A. Zeeb 	ret = rhashtable_remove_fast(rtbl, rhead, *params);
20028348caeSBjoern A. Zeeb 	if (ret && ret != -ENOENT)
20128348caeSBjoern A. Zeeb 		return ret;
20228348caeSBjoern A. Zeeb 
20328348caeSBjoern A. Zeeb 	return 0;
20428348caeSBjoern A. Zeeb }
20528348caeSBjoern A. Zeeb 
ath11k_peer_rhash_add(struct ath11k_base * ab,struct ath11k_peer * peer)20628348caeSBjoern A. Zeeb static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
20728348caeSBjoern A. Zeeb {
20828348caeSBjoern A. Zeeb 	int ret;
20928348caeSBjoern A. Zeeb 
21028348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
21128348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
21228348caeSBjoern A. Zeeb 
21328348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
21428348caeSBjoern A. Zeeb 		return -EPERM;
21528348caeSBjoern A. Zeeb 
21628348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
21728348caeSBjoern A. Zeeb 				       &ab->rhash_peer_id_param, &peer->peer_id);
21828348caeSBjoern A. Zeeb 	if (ret) {
21928348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
22028348caeSBjoern A. Zeeb 			    peer->addr, peer->peer_id, ret);
22128348caeSBjoern A. Zeeb 		return ret;
22228348caeSBjoern A. Zeeb 	}
22328348caeSBjoern A. Zeeb 
22428348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
22528348caeSBjoern A. Zeeb 				       &ab->rhash_peer_addr_param, &peer->addr);
22628348caeSBjoern A. Zeeb 	if (ret) {
22728348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
22828348caeSBjoern A. Zeeb 			    peer->addr, peer->peer_id, ret);
22928348caeSBjoern A. Zeeb 		goto err_clean;
23028348caeSBjoern A. Zeeb 	}
23128348caeSBjoern A. Zeeb 
23228348caeSBjoern A. Zeeb 	return 0;
23328348caeSBjoern A. Zeeb 
23428348caeSBjoern A. Zeeb err_clean:
23528348caeSBjoern A. Zeeb 	ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
23628348caeSBjoern A. Zeeb 				 &ab->rhash_peer_id_param);
23728348caeSBjoern A. Zeeb 	return ret;
23828348caeSBjoern A. Zeeb }
23928348caeSBjoern A. Zeeb 
ath11k_peer_cleanup(struct ath11k * ar,u32 vdev_id)240dd4f32aeSBjoern A. Zeeb void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
241dd4f32aeSBjoern A. Zeeb {
242dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer, *tmp;
243dd4f32aeSBjoern A. Zeeb 	struct ath11k_base *ab = ar->ab;
244dd4f32aeSBjoern A. Zeeb 
245dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ar->conf_mutex);
246dd4f32aeSBjoern A. Zeeb 
24728348caeSBjoern A. Zeeb 	mutex_lock(&ab->tbl_mtx_lock);
248dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
249dd4f32aeSBjoern A. Zeeb 	list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
250dd4f32aeSBjoern A. Zeeb 		if (peer->vdev_id != vdev_id)
251dd4f32aeSBjoern A. Zeeb 			continue;
252dd4f32aeSBjoern A. Zeeb 
253dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
254dd4f32aeSBjoern A. Zeeb 			    peer->addr, vdev_id);
255dd4f32aeSBjoern A. Zeeb 
25628348caeSBjoern A. Zeeb 		ath11k_peer_rhash_delete(ab, peer);
257dd4f32aeSBjoern A. Zeeb 		list_del(&peer->list);
258dd4f32aeSBjoern A. Zeeb 		kfree(peer);
259dd4f32aeSBjoern A. Zeeb 		ar->num_peers--;
260dd4f32aeSBjoern A. Zeeb 	}
261dd4f32aeSBjoern A. Zeeb 
262dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
26328348caeSBjoern A. Zeeb 	mutex_unlock(&ab->tbl_mtx_lock);
264dd4f32aeSBjoern A. Zeeb }
265dd4f32aeSBjoern A. Zeeb 
ath11k_wait_for_peer_deleted(struct ath11k * ar,int vdev_id,const u8 * addr)266dd4f32aeSBjoern A. Zeeb static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
267dd4f32aeSBjoern A. Zeeb {
268dd4f32aeSBjoern A. Zeeb 	return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
269dd4f32aeSBjoern A. Zeeb }
270dd4f32aeSBjoern A. Zeeb 
ath11k_wait_for_peer_delete_done(struct ath11k * ar,u32 vdev_id,const u8 * addr)271dd4f32aeSBjoern A. Zeeb int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
272dd4f32aeSBjoern A. Zeeb 				     const u8 *addr)
273dd4f32aeSBjoern A. Zeeb {
274dd4f32aeSBjoern A. Zeeb 	int ret;
275dd4f32aeSBjoern A. Zeeb 	unsigned long time_left;
276dd4f32aeSBjoern A. Zeeb 
277dd4f32aeSBjoern A. Zeeb 	ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
278dd4f32aeSBjoern A. Zeeb 	if (ret) {
279dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ar->ab, "failed wait for peer deleted");
280dd4f32aeSBjoern A. Zeeb 		return ret;
281dd4f32aeSBjoern A. Zeeb 	}
282dd4f32aeSBjoern A. Zeeb 
283dd4f32aeSBjoern A. Zeeb 	time_left = wait_for_completion_timeout(&ar->peer_delete_done,
284dd4f32aeSBjoern A. Zeeb 						3 * HZ);
285dd4f32aeSBjoern A. Zeeb 	if (time_left == 0) {
286dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
287dd4f32aeSBjoern A. Zeeb 		return -ETIMEDOUT;
288dd4f32aeSBjoern A. Zeeb 	}
289dd4f32aeSBjoern A. Zeeb 
290dd4f32aeSBjoern A. Zeeb 	return 0;
291dd4f32aeSBjoern A. Zeeb }
292dd4f32aeSBjoern A. Zeeb 
__ath11k_peer_delete(struct ath11k * ar,u32 vdev_id,const u8 * addr)29328348caeSBjoern A. Zeeb static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
294dd4f32aeSBjoern A. Zeeb {
295dd4f32aeSBjoern A. Zeeb 	int ret;
29628348caeSBjoern A. Zeeb 	struct ath11k_peer *peer;
29728348caeSBjoern A. Zeeb 	struct ath11k_base *ab = ar->ab;
298dd4f32aeSBjoern A. Zeeb 
299dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ar->conf_mutex);
300dd4f32aeSBjoern A. Zeeb 
30128348caeSBjoern A. Zeeb 	mutex_lock(&ab->tbl_mtx_lock);
30228348caeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
30328348caeSBjoern A. Zeeb 
30428348caeSBjoern A. Zeeb 	peer = ath11k_peer_find_by_addr(ab, addr);
30528348caeSBjoern A. Zeeb 	/* Check if the found peer is what we want to remove.
30628348caeSBjoern A. Zeeb 	 * While the sta is transitioning to another band we may
30728348caeSBjoern A. Zeeb 	 * have 2 peer with the same addr assigned to different
30828348caeSBjoern A. Zeeb 	 * vdev_id. Make sure we are deleting the correct peer.
30928348caeSBjoern A. Zeeb 	 */
31028348caeSBjoern A. Zeeb 	if (peer && peer->vdev_id == vdev_id)
31128348caeSBjoern A. Zeeb 		ath11k_peer_rhash_delete(ab, peer);
31228348caeSBjoern A. Zeeb 
31328348caeSBjoern A. Zeeb 	/* Fallback to peer list search if the correct peer can't be found.
31428348caeSBjoern A. Zeeb 	 * Skip the deletion of the peer from the rhash since it has already
31528348caeSBjoern A. Zeeb 	 * been deleted in peer add.
31628348caeSBjoern A. Zeeb 	 */
31728348caeSBjoern A. Zeeb 	if (!peer)
31828348caeSBjoern A. Zeeb 		peer = ath11k_peer_find(ab, vdev_id, addr);
31928348caeSBjoern A. Zeeb 
32028348caeSBjoern A. Zeeb 	if (!peer) {
32128348caeSBjoern A. Zeeb 		spin_unlock_bh(&ab->base_lock);
32228348caeSBjoern A. Zeeb 		mutex_unlock(&ab->tbl_mtx_lock);
32328348caeSBjoern A. Zeeb 
32428348caeSBjoern A. Zeeb 		ath11k_warn(ab,
32528348caeSBjoern A. Zeeb 			    "failed to find peer vdev_id %d addr %pM in delete\n",
32628348caeSBjoern A. Zeeb 			    vdev_id, addr);
32728348caeSBjoern A. Zeeb 		return -EINVAL;
32828348caeSBjoern A. Zeeb 	}
32928348caeSBjoern A. Zeeb 
33028348caeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
33128348caeSBjoern A. Zeeb 	mutex_unlock(&ab->tbl_mtx_lock);
33228348caeSBjoern A. Zeeb 
333dd4f32aeSBjoern A. Zeeb 	reinit_completion(&ar->peer_delete_done);
334dd4f32aeSBjoern A. Zeeb 
335dd4f32aeSBjoern A. Zeeb 	ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
336dd4f32aeSBjoern A. Zeeb 	if (ret) {
33728348caeSBjoern A. Zeeb 		ath11k_warn(ab,
338dd4f32aeSBjoern A. Zeeb 			    "failed to delete peer vdev_id %d addr %pM ret %d\n",
339dd4f32aeSBjoern A. Zeeb 			    vdev_id, addr, ret);
340dd4f32aeSBjoern A. Zeeb 		return ret;
341dd4f32aeSBjoern A. Zeeb 	}
342dd4f32aeSBjoern A. Zeeb 
343dd4f32aeSBjoern A. Zeeb 	ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
344dd4f32aeSBjoern A. Zeeb 	if (ret)
345dd4f32aeSBjoern A. Zeeb 		return ret;
346dd4f32aeSBjoern A. Zeeb 
34728348caeSBjoern A. Zeeb 	return 0;
34828348caeSBjoern A. Zeeb }
34928348caeSBjoern A. Zeeb 
ath11k_peer_delete(struct ath11k * ar,u32 vdev_id,u8 * addr)35028348caeSBjoern A. Zeeb int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
35128348caeSBjoern A. Zeeb {
35228348caeSBjoern A. Zeeb 	int ret;
35328348caeSBjoern A. Zeeb 
35428348caeSBjoern A. Zeeb 	lockdep_assert_held(&ar->conf_mutex);
35528348caeSBjoern A. Zeeb 
35628348caeSBjoern A. Zeeb 	ret = __ath11k_peer_delete(ar, vdev_id, addr);
35728348caeSBjoern A. Zeeb 	if (ret)
35828348caeSBjoern A. Zeeb 		return ret;
35928348caeSBjoern A. Zeeb 
360dd4f32aeSBjoern A. Zeeb 	ar->num_peers--;
361dd4f32aeSBjoern A. Zeeb 
362dd4f32aeSBjoern A. Zeeb 	return 0;
363dd4f32aeSBjoern A. Zeeb }
364dd4f32aeSBjoern A. Zeeb 
ath11k_wait_for_peer_created(struct ath11k * ar,int vdev_id,const u8 * addr)365dd4f32aeSBjoern A. Zeeb static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr)
366dd4f32aeSBjoern A. Zeeb {
367dd4f32aeSBjoern A. Zeeb 	return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
368dd4f32aeSBjoern A. Zeeb }
369dd4f32aeSBjoern A. Zeeb 
ath11k_peer_create(struct ath11k * ar,struct ath11k_vif * arvif,struct ieee80211_sta * sta,struct peer_create_params * param)370dd4f32aeSBjoern A. Zeeb int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
371dd4f32aeSBjoern A. Zeeb 		       struct ieee80211_sta *sta, struct peer_create_params *param)
372dd4f32aeSBjoern A. Zeeb {
373dd4f32aeSBjoern A. Zeeb 	struct ath11k_peer *peer;
374dd4f32aeSBjoern A. Zeeb 	struct ath11k_sta *arsta;
375dd4f32aeSBjoern A. Zeeb 	int ret, fbret;
376dd4f32aeSBjoern A. Zeeb 
377dd4f32aeSBjoern A. Zeeb 	lockdep_assert_held(&ar->conf_mutex);
378dd4f32aeSBjoern A. Zeeb 
379dd4f32aeSBjoern A. Zeeb 	if (ar->num_peers > (ar->max_num_peers - 1)) {
380dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ar->ab,
381dd4f32aeSBjoern A. Zeeb 			    "failed to create peer due to insufficient peer entry resource in firmware\n");
382dd4f32aeSBjoern A. Zeeb 		return -ENOBUFS;
383dd4f32aeSBjoern A. Zeeb 	}
384dd4f32aeSBjoern A. Zeeb 
38528348caeSBjoern A. Zeeb 	mutex_lock(&ar->ab->tbl_mtx_lock);
386dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ar->ab->base_lock);
38728348caeSBjoern A. Zeeb 	peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
388dd4f32aeSBjoern A. Zeeb 	if (peer) {
38928348caeSBjoern A. Zeeb 		if (peer->vdev_id == param->vdev_id) {
390dd4f32aeSBjoern A. Zeeb 			spin_unlock_bh(&ar->ab->base_lock);
39128348caeSBjoern A. Zeeb 			mutex_unlock(&ar->ab->tbl_mtx_lock);
392dd4f32aeSBjoern A. Zeeb 			return -EINVAL;
393dd4f32aeSBjoern A. Zeeb 		}
39428348caeSBjoern A. Zeeb 
39528348caeSBjoern A. Zeeb 		/* Assume sta is transitioning to another band.
39628348caeSBjoern A. Zeeb 		 * Remove here the peer from rhash.
39728348caeSBjoern A. Zeeb 		 */
39828348caeSBjoern A. Zeeb 		ath11k_peer_rhash_delete(ar->ab, peer);
39928348caeSBjoern A. Zeeb 	}
400dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ar->ab->base_lock);
40128348caeSBjoern A. Zeeb 	mutex_unlock(&ar->ab->tbl_mtx_lock);
402dd4f32aeSBjoern A. Zeeb 
403dd4f32aeSBjoern A. Zeeb 	ret = ath11k_wmi_send_peer_create_cmd(ar, param);
404dd4f32aeSBjoern A. Zeeb 	if (ret) {
405dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ar->ab,
406dd4f32aeSBjoern A. Zeeb 			    "failed to send peer create vdev_id %d ret %d\n",
407dd4f32aeSBjoern A. Zeeb 			    param->vdev_id, ret);
408dd4f32aeSBjoern A. Zeeb 		return ret;
409dd4f32aeSBjoern A. Zeeb 	}
410dd4f32aeSBjoern A. Zeeb 
411dd4f32aeSBjoern A. Zeeb 	ret = ath11k_wait_for_peer_created(ar, param->vdev_id,
412dd4f32aeSBjoern A. Zeeb 					   param->peer_addr);
413dd4f32aeSBjoern A. Zeeb 	if (ret)
414dd4f32aeSBjoern A. Zeeb 		return ret;
415dd4f32aeSBjoern A. Zeeb 
41628348caeSBjoern A. Zeeb 	mutex_lock(&ar->ab->tbl_mtx_lock);
417dd4f32aeSBjoern A. Zeeb 	spin_lock_bh(&ar->ab->base_lock);
418dd4f32aeSBjoern A. Zeeb 
419dd4f32aeSBjoern A. Zeeb 	peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
420dd4f32aeSBjoern A. Zeeb 	if (!peer) {
421dd4f32aeSBjoern A. Zeeb 		spin_unlock_bh(&ar->ab->base_lock);
42228348caeSBjoern A. Zeeb 		mutex_unlock(&ar->ab->tbl_mtx_lock);
423dd4f32aeSBjoern A. Zeeb 		ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
424dd4f32aeSBjoern A. Zeeb 			    param->peer_addr, param->vdev_id);
425dd4f32aeSBjoern A. Zeeb 
426dd4f32aeSBjoern A. Zeeb 		ret = -ENOENT;
427dd4f32aeSBjoern A. Zeeb 		goto cleanup;
428dd4f32aeSBjoern A. Zeeb 	}
429dd4f32aeSBjoern A. Zeeb 
43028348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_add(ar->ab, peer);
43128348caeSBjoern A. Zeeb 	if (ret) {
43228348caeSBjoern A. Zeeb 		spin_unlock_bh(&ar->ab->base_lock);
43328348caeSBjoern A. Zeeb 		mutex_unlock(&ar->ab->tbl_mtx_lock);
43428348caeSBjoern A. Zeeb 		goto cleanup;
43528348caeSBjoern A. Zeeb 	}
43628348caeSBjoern A. Zeeb 
437dd4f32aeSBjoern A. Zeeb 	peer->pdev_idx = ar->pdev_idx;
438dd4f32aeSBjoern A. Zeeb 	peer->sta = sta;
439dd4f32aeSBjoern A. Zeeb 
440dd4f32aeSBjoern A. Zeeb 	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
441dd4f32aeSBjoern A. Zeeb 		arvif->ast_hash = peer->ast_hash;
442dd4f32aeSBjoern A. Zeeb 		arvif->ast_idx = peer->hw_peer_id;
443dd4f32aeSBjoern A. Zeeb 	}
444dd4f32aeSBjoern A. Zeeb 
445dd4f32aeSBjoern A. Zeeb 	peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
446dd4f32aeSBjoern A. Zeeb 	peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
447dd4f32aeSBjoern A. Zeeb 
448dd4f32aeSBjoern A. Zeeb 	if (sta) {
449dd4f32aeSBjoern A. Zeeb 		arsta = (struct ath11k_sta *)sta->drv_priv;
450dd4f32aeSBjoern A. Zeeb 		arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
451dd4f32aeSBjoern A. Zeeb 				       FIELD_PREP(HTT_TCL_META_DATA_PEER_ID,
452dd4f32aeSBjoern A. Zeeb 						  peer->peer_id);
453dd4f32aeSBjoern A. Zeeb 
454dd4f32aeSBjoern A. Zeeb 		/* set HTT extension valid bit to 0 by default */
455dd4f32aeSBjoern A. Zeeb 		arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
456dd4f32aeSBjoern A. Zeeb 	}
457dd4f32aeSBjoern A. Zeeb 
458dd4f32aeSBjoern A. Zeeb 	ar->num_peers++;
459dd4f32aeSBjoern A. Zeeb 
460dd4f32aeSBjoern A. Zeeb 	spin_unlock_bh(&ar->ab->base_lock);
46128348caeSBjoern A. Zeeb 	mutex_unlock(&ar->ab->tbl_mtx_lock);
462dd4f32aeSBjoern A. Zeeb 
463dd4f32aeSBjoern A. Zeeb 	return 0;
464dd4f32aeSBjoern A. Zeeb 
465dd4f32aeSBjoern A. Zeeb cleanup:
46628348caeSBjoern A. Zeeb 	fbret = __ath11k_peer_delete(ar, param->vdev_id, param->peer_addr);
467dd4f32aeSBjoern A. Zeeb 	if (fbret)
46828348caeSBjoern A. Zeeb 		ath11k_warn(ar->ab, "failed peer %pM delete vdev_id %d fallback ret %d\n",
469dd4f32aeSBjoern A. Zeeb 			    param->peer_addr, param->vdev_id, fbret);
470dd4f32aeSBjoern A. Zeeb 
471dd4f32aeSBjoern A. Zeeb 	return ret;
472dd4f32aeSBjoern A. Zeeb }
47328348caeSBjoern A. Zeeb 
ath11k_peer_rhash_delete(struct ath11k_base * ab,struct ath11k_peer * peer)47428348caeSBjoern A. Zeeb int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
47528348caeSBjoern A. Zeeb {
47628348caeSBjoern A. Zeeb 	int ret;
47728348caeSBjoern A. Zeeb 
47828348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->base_lock);
47928348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
48028348caeSBjoern A. Zeeb 
48128348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
48228348caeSBjoern A. Zeeb 		return -EPERM;
48328348caeSBjoern A. Zeeb 
48428348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
48528348caeSBjoern A. Zeeb 				       &ab->rhash_peer_addr_param);
48628348caeSBjoern A. Zeeb 	if (ret) {
48728348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
48828348caeSBjoern A. Zeeb 			    peer->addr, peer->peer_id, ret);
48928348caeSBjoern A. Zeeb 		return ret;
49028348caeSBjoern A. Zeeb 	}
49128348caeSBjoern A. Zeeb 
49228348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
49328348caeSBjoern A. Zeeb 				       &ab->rhash_peer_id_param);
49428348caeSBjoern A. Zeeb 	if (ret) {
49528348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
49628348caeSBjoern A. Zeeb 			    peer->addr, peer->peer_id, ret);
49728348caeSBjoern A. Zeeb 		return ret;
49828348caeSBjoern A. Zeeb 	}
49928348caeSBjoern A. Zeeb 
50028348caeSBjoern A. Zeeb 	return 0;
50128348caeSBjoern A. Zeeb }
50228348caeSBjoern A. Zeeb 
ath11k_peer_rhash_id_tbl_init(struct ath11k_base * ab)50328348caeSBjoern A. Zeeb static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
50428348caeSBjoern A. Zeeb {
50528348caeSBjoern A. Zeeb 	struct rhashtable_params *param;
50628348caeSBjoern A. Zeeb 	struct rhashtable *rhash_id_tbl;
50728348caeSBjoern A. Zeeb 	int ret;
50828348caeSBjoern A. Zeeb 	size_t size;
50928348caeSBjoern A. Zeeb 
51028348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
51128348caeSBjoern A. Zeeb 
51228348caeSBjoern A. Zeeb 	if (ab->rhead_peer_id)
51328348caeSBjoern A. Zeeb 		return 0;
51428348caeSBjoern A. Zeeb 
51528348caeSBjoern A. Zeeb 	size = sizeof(*ab->rhead_peer_id);
51628348caeSBjoern A. Zeeb 	rhash_id_tbl = kzalloc(size, GFP_KERNEL);
51728348caeSBjoern A. Zeeb 	if (!rhash_id_tbl) {
51828348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
51928348caeSBjoern A. Zeeb 			    size);
52028348caeSBjoern A. Zeeb 		return -ENOMEM;
52128348caeSBjoern A. Zeeb 	}
52228348caeSBjoern A. Zeeb 
52328348caeSBjoern A. Zeeb 	param = &ab->rhash_peer_id_param;
52428348caeSBjoern A. Zeeb 
52528348caeSBjoern A. Zeeb 	param->key_offset = offsetof(struct ath11k_peer, peer_id);
52628348caeSBjoern A. Zeeb 	param->head_offset = offsetof(struct ath11k_peer, rhash_id);
52728348caeSBjoern A. Zeeb 	param->key_len = sizeof_field(struct ath11k_peer, peer_id);
52828348caeSBjoern A. Zeeb 	param->automatic_shrinking = true;
52928348caeSBjoern A. Zeeb 	param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
53028348caeSBjoern A. Zeeb 
53128348caeSBjoern A. Zeeb 	ret = rhashtable_init(rhash_id_tbl, param);
53228348caeSBjoern A. Zeeb 	if (ret) {
53328348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
53428348caeSBjoern A. Zeeb 		goto err_free;
53528348caeSBjoern A. Zeeb 	}
53628348caeSBjoern A. Zeeb 
53728348caeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
53828348caeSBjoern A. Zeeb 
53928348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_id) {
54028348caeSBjoern A. Zeeb 		ab->rhead_peer_id = rhash_id_tbl;
54128348caeSBjoern A. Zeeb 	} else {
54228348caeSBjoern A. Zeeb 		spin_unlock_bh(&ab->base_lock);
54328348caeSBjoern A. Zeeb 		goto cleanup_tbl;
54428348caeSBjoern A. Zeeb 	}
54528348caeSBjoern A. Zeeb 
54628348caeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
54728348caeSBjoern A. Zeeb 
54828348caeSBjoern A. Zeeb 	return 0;
54928348caeSBjoern A. Zeeb 
55028348caeSBjoern A. Zeeb cleanup_tbl:
55128348caeSBjoern A. Zeeb 	rhashtable_destroy(rhash_id_tbl);
55228348caeSBjoern A. Zeeb err_free:
55328348caeSBjoern A. Zeeb 	kfree(rhash_id_tbl);
55428348caeSBjoern A. Zeeb 
55528348caeSBjoern A. Zeeb 	return ret;
55628348caeSBjoern A. Zeeb }
55728348caeSBjoern A. Zeeb 
ath11k_peer_rhash_addr_tbl_init(struct ath11k_base * ab)55828348caeSBjoern A. Zeeb static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
55928348caeSBjoern A. Zeeb {
56028348caeSBjoern A. Zeeb 	struct rhashtable_params *param;
56128348caeSBjoern A. Zeeb 	struct rhashtable *rhash_addr_tbl;
56228348caeSBjoern A. Zeeb 	int ret;
56328348caeSBjoern A. Zeeb 	size_t size;
56428348caeSBjoern A. Zeeb 
56528348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
56628348caeSBjoern A. Zeeb 
56728348caeSBjoern A. Zeeb 	if (ab->rhead_peer_addr)
56828348caeSBjoern A. Zeeb 		return 0;
56928348caeSBjoern A. Zeeb 
57028348caeSBjoern A. Zeeb 	size = sizeof(*ab->rhead_peer_addr);
57128348caeSBjoern A. Zeeb 	rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
57228348caeSBjoern A. Zeeb 	if (!rhash_addr_tbl) {
57328348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
57428348caeSBjoern A. Zeeb 			    size);
57528348caeSBjoern A. Zeeb 		return -ENOMEM;
57628348caeSBjoern A. Zeeb 	}
57728348caeSBjoern A. Zeeb 
57828348caeSBjoern A. Zeeb 	param = &ab->rhash_peer_addr_param;
57928348caeSBjoern A. Zeeb 
58028348caeSBjoern A. Zeeb 	param->key_offset = offsetof(struct ath11k_peer, addr);
58128348caeSBjoern A. Zeeb 	param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
58228348caeSBjoern A. Zeeb 	param->key_len = sizeof_field(struct ath11k_peer, addr);
58328348caeSBjoern A. Zeeb 	param->automatic_shrinking = true;
58428348caeSBjoern A. Zeeb 	param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
58528348caeSBjoern A. Zeeb 
58628348caeSBjoern A. Zeeb 	ret = rhashtable_init(rhash_addr_tbl, param);
58728348caeSBjoern A. Zeeb 	if (ret) {
58828348caeSBjoern A. Zeeb 		ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
58928348caeSBjoern A. Zeeb 		goto err_free;
59028348caeSBjoern A. Zeeb 	}
59128348caeSBjoern A. Zeeb 
59228348caeSBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
59328348caeSBjoern A. Zeeb 
59428348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_addr) {
59528348caeSBjoern A. Zeeb 		ab->rhead_peer_addr = rhash_addr_tbl;
59628348caeSBjoern A. Zeeb 	} else {
59728348caeSBjoern A. Zeeb 		spin_unlock_bh(&ab->base_lock);
59828348caeSBjoern A. Zeeb 		goto cleanup_tbl;
59928348caeSBjoern A. Zeeb 	}
60028348caeSBjoern A. Zeeb 
60128348caeSBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
60228348caeSBjoern A. Zeeb 
60328348caeSBjoern A. Zeeb 	return 0;
60428348caeSBjoern A. Zeeb 
60528348caeSBjoern A. Zeeb cleanup_tbl:
60628348caeSBjoern A. Zeeb 	rhashtable_destroy(rhash_addr_tbl);
60728348caeSBjoern A. Zeeb err_free:
60828348caeSBjoern A. Zeeb 	kfree(rhash_addr_tbl);
60928348caeSBjoern A. Zeeb 
61028348caeSBjoern A. Zeeb 	return ret;
61128348caeSBjoern A. Zeeb }
61228348caeSBjoern A. Zeeb 
ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base * ab)61328348caeSBjoern A. Zeeb static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
61428348caeSBjoern A. Zeeb {
61528348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
61628348caeSBjoern A. Zeeb 
61728348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_id)
61828348caeSBjoern A. Zeeb 		return;
61928348caeSBjoern A. Zeeb 
62028348caeSBjoern A. Zeeb 	rhashtable_destroy(ab->rhead_peer_id);
62128348caeSBjoern A. Zeeb 	kfree(ab->rhead_peer_id);
62228348caeSBjoern A. Zeeb 	ab->rhead_peer_id = NULL;
62328348caeSBjoern A. Zeeb }
62428348caeSBjoern A. Zeeb 
ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base * ab)62528348caeSBjoern A. Zeeb static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
62628348caeSBjoern A. Zeeb {
62728348caeSBjoern A. Zeeb 	lockdep_assert_held(&ab->tbl_mtx_lock);
62828348caeSBjoern A. Zeeb 
62928348caeSBjoern A. Zeeb 	if (!ab->rhead_peer_addr)
63028348caeSBjoern A. Zeeb 		return;
63128348caeSBjoern A. Zeeb 
63228348caeSBjoern A. Zeeb 	rhashtable_destroy(ab->rhead_peer_addr);
63328348caeSBjoern A. Zeeb 	kfree(ab->rhead_peer_addr);
63428348caeSBjoern A. Zeeb 	ab->rhead_peer_addr = NULL;
63528348caeSBjoern A. Zeeb }
63628348caeSBjoern A. Zeeb 
ath11k_peer_rhash_tbl_init(struct ath11k_base * ab)63728348caeSBjoern A. Zeeb int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
63828348caeSBjoern A. Zeeb {
63928348caeSBjoern A. Zeeb 	int ret;
64028348caeSBjoern A. Zeeb 
64128348caeSBjoern A. Zeeb 	mutex_lock(&ab->tbl_mtx_lock);
64228348caeSBjoern A. Zeeb 
64328348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_id_tbl_init(ab);
64428348caeSBjoern A. Zeeb 	if (ret)
64528348caeSBjoern A. Zeeb 		goto out;
64628348caeSBjoern A. Zeeb 
64728348caeSBjoern A. Zeeb 	ret = ath11k_peer_rhash_addr_tbl_init(ab);
64828348caeSBjoern A. Zeeb 	if (ret)
64928348caeSBjoern A. Zeeb 		goto cleanup_tbl;
65028348caeSBjoern A. Zeeb 
65128348caeSBjoern A. Zeeb 	mutex_unlock(&ab->tbl_mtx_lock);
65228348caeSBjoern A. Zeeb 
65328348caeSBjoern A. Zeeb 	return 0;
65428348caeSBjoern A. Zeeb 
65528348caeSBjoern A. Zeeb cleanup_tbl:
65628348caeSBjoern A. Zeeb 	ath11k_peer_rhash_id_tbl_destroy(ab);
65728348caeSBjoern A. Zeeb out:
65828348caeSBjoern A. Zeeb 	mutex_unlock(&ab->tbl_mtx_lock);
65928348caeSBjoern A. Zeeb 	return ret;
66028348caeSBjoern A. Zeeb }
66128348caeSBjoern A. Zeeb 
ath11k_peer_rhash_tbl_destroy(struct ath11k_base * ab)66228348caeSBjoern A. Zeeb void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
66328348caeSBjoern A. Zeeb {
66428348caeSBjoern A. Zeeb 	mutex_lock(&ab->tbl_mtx_lock);
66528348caeSBjoern A. Zeeb 
66628348caeSBjoern A. Zeeb 	ath11k_peer_rhash_addr_tbl_destroy(ab);
66728348caeSBjoern A. Zeeb 	ath11k_peer_rhash_id_tbl_destroy(ab);
66828348caeSBjoern A. Zeeb 
66928348caeSBjoern A. Zeeb 	mutex_unlock(&ab->tbl_mtx_lock);
67028348caeSBjoern A. Zeeb }
671