Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/athk/ath11k/peer.c
48378 views
1
// SPDX-License-Identifier: BSD-3-Clause-Clear
2
/*
3
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5
*/
6
7
#include "core.h"
8
#include "peer.h"
9
#include "debug.h"
10
11
static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab,
12
int peer_id)
13
{
14
struct ath11k_peer *peer;
15
16
lockdep_assert_held(&ab->base_lock);
17
18
list_for_each_entry(peer, &ab->peers, list) {
19
if (peer->peer_id != peer_id)
20
continue;
21
22
return peer;
23
}
24
25
return NULL;
26
}
27
28
struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
29
const u8 *addr)
30
{
31
struct ath11k_peer *peer;
32
33
lockdep_assert_held(&ab->base_lock);
34
35
list_for_each_entry(peer, &ab->peers, list) {
36
if (peer->vdev_id != vdev_id)
37
continue;
38
if (!ether_addr_equal(peer->addr, addr))
39
continue;
40
41
return peer;
42
}
43
44
return NULL;
45
}
46
47
struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
48
const u8 *addr)
49
{
50
struct ath11k_peer *peer;
51
52
lockdep_assert_held(&ab->base_lock);
53
54
if (!ab->rhead_peer_addr)
55
return NULL;
56
57
peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
58
ab->rhash_peer_addr_param);
59
60
return peer;
61
}
62
63
struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
64
int peer_id)
65
{
66
struct ath11k_peer *peer;
67
68
lockdep_assert_held(&ab->base_lock);
69
70
if (!ab->rhead_peer_id)
71
return NULL;
72
73
peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
74
ab->rhash_peer_id_param);
75
76
return peer;
77
}
78
79
struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
80
int vdev_id)
81
{
82
struct ath11k_peer *peer;
83
84
spin_lock_bh(&ab->base_lock);
85
86
list_for_each_entry(peer, &ab->peers, list) {
87
if (vdev_id == peer->vdev_id) {
88
spin_unlock_bh(&ab->base_lock);
89
return peer;
90
}
91
}
92
spin_unlock_bh(&ab->base_lock);
93
return NULL;
94
}
95
96
void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
97
{
98
struct ath11k_peer *peer;
99
100
spin_lock_bh(&ab->base_lock);
101
102
peer = ath11k_peer_find_list_by_id(ab, peer_id);
103
if (!peer) {
104
ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
105
peer_id);
106
goto exit;
107
}
108
109
ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer unmap vdev %d peer %pM id %d\n",
110
peer->vdev_id, peer->addr, peer_id);
111
112
list_del(&peer->list);
113
kfree(peer);
114
wake_up(&ab->peer_mapping_wq);
115
116
exit:
117
spin_unlock_bh(&ab->base_lock);
118
}
119
120
void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
121
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
122
{
123
struct ath11k_peer *peer;
124
125
spin_lock_bh(&ab->base_lock);
126
peer = ath11k_peer_find(ab, vdev_id, mac_addr);
127
if (!peer) {
128
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
129
if (!peer)
130
goto exit;
131
132
peer->vdev_id = vdev_id;
133
peer->peer_id = peer_id;
134
peer->ast_hash = ast_hash;
135
peer->hw_peer_id = hw_peer_id;
136
ether_addr_copy(peer->addr, mac_addr);
137
list_add(&peer->list, &ab->peers);
138
wake_up(&ab->peer_mapping_wq);
139
}
140
141
ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer map vdev %d peer %pM id %d\n",
142
vdev_id, mac_addr, peer_id);
143
144
exit:
145
spin_unlock_bh(&ab->base_lock);
146
}
147
148
static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
149
const u8 *addr, bool expect_mapped)
150
{
151
int ret;
152
153
ret = wait_event_timeout(ab->peer_mapping_wq, ({
154
bool mapped;
155
156
spin_lock_bh(&ab->base_lock);
157
mapped = !!ath11k_peer_find(ab, vdev_id, addr);
158
spin_unlock_bh(&ab->base_lock);
159
160
(mapped == expect_mapped ||
161
test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags));
162
}), 3 * HZ);
163
164
if (ret <= 0)
165
return -ETIMEDOUT;
166
167
return 0;
168
}
169
170
static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
171
struct rhashtable *rtbl,
172
struct rhash_head *rhead,
173
struct rhashtable_params *params,
174
void *key)
175
{
176
struct ath11k_peer *tmp;
177
178
lockdep_assert_held(&ab->tbl_mtx_lock);
179
180
tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
181
182
if (!tmp)
183
return 0;
184
else if (IS_ERR(tmp))
185
return PTR_ERR(tmp);
186
else
187
return -EEXIST;
188
}
189
190
static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
191
struct rhashtable *rtbl,
192
struct rhash_head *rhead,
193
struct rhashtable_params *params)
194
{
195
int ret;
196
197
lockdep_assert_held(&ab->tbl_mtx_lock);
198
199
ret = rhashtable_remove_fast(rtbl, rhead, *params);
200
if (ret && ret != -ENOENT)
201
return ret;
202
203
return 0;
204
}
205
206
static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
207
{
208
int ret;
209
210
lockdep_assert_held(&ab->base_lock);
211
lockdep_assert_held(&ab->tbl_mtx_lock);
212
213
if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
214
return -EPERM;
215
216
ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
217
&ab->rhash_peer_id_param, &peer->peer_id);
218
if (ret) {
219
ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
220
peer->addr, peer->peer_id, ret);
221
return ret;
222
}
223
224
ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
225
&ab->rhash_peer_addr_param, &peer->addr);
226
if (ret) {
227
ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
228
peer->addr, peer->peer_id, ret);
229
goto err_clean;
230
}
231
232
return 0;
233
234
err_clean:
235
ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
236
&ab->rhash_peer_id_param);
237
return ret;
238
}
239
240
void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
241
{
242
struct ath11k_peer *peer, *tmp;
243
struct ath11k_base *ab = ar->ab;
244
245
lockdep_assert_held(&ar->conf_mutex);
246
247
mutex_lock(&ab->tbl_mtx_lock);
248
spin_lock_bh(&ab->base_lock);
249
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
250
if (peer->vdev_id != vdev_id)
251
continue;
252
253
ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
254
peer->addr, vdev_id);
255
256
ath11k_peer_rhash_delete(ab, peer);
257
list_del(&peer->list);
258
kfree(peer);
259
ar->num_peers--;
260
}
261
262
spin_unlock_bh(&ab->base_lock);
263
mutex_unlock(&ab->tbl_mtx_lock);
264
}
265
266
static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
267
{
268
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
269
}
270
271
int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
272
const u8 *addr)
273
{
274
int ret;
275
unsigned long time_left;
276
277
ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
278
if (ret) {
279
ath11k_warn(ar->ab, "failed wait for peer deleted");
280
return ret;
281
}
282
283
time_left = wait_for_completion_timeout(&ar->peer_delete_done,
284
3 * HZ);
285
if (time_left == 0) {
286
ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
287
return -ETIMEDOUT;
288
}
289
290
return 0;
291
}
292
293
static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
294
{
295
int ret;
296
struct ath11k_peer *peer;
297
struct ath11k_base *ab = ar->ab;
298
299
lockdep_assert_held(&ar->conf_mutex);
300
301
mutex_lock(&ab->tbl_mtx_lock);
302
spin_lock_bh(&ab->base_lock);
303
304
peer = ath11k_peer_find_by_addr(ab, addr);
305
/* Check if the found peer is what we want to remove.
306
* While the sta is transitioning to another band we may
307
* have 2 peer with the same addr assigned to different
308
* vdev_id. Make sure we are deleting the correct peer.
309
*/
310
if (peer && peer->vdev_id == vdev_id)
311
ath11k_peer_rhash_delete(ab, peer);
312
313
/* Fallback to peer list search if the correct peer can't be found.
314
* Skip the deletion of the peer from the rhash since it has already
315
* been deleted in peer add.
316
*/
317
if (!peer)
318
peer = ath11k_peer_find(ab, vdev_id, addr);
319
320
if (!peer) {
321
spin_unlock_bh(&ab->base_lock);
322
mutex_unlock(&ab->tbl_mtx_lock);
323
324
ath11k_warn(ab,
325
"failed to find peer vdev_id %d addr %pM in delete\n",
326
vdev_id, addr);
327
return -EINVAL;
328
}
329
330
spin_unlock_bh(&ab->base_lock);
331
mutex_unlock(&ab->tbl_mtx_lock);
332
333
reinit_completion(&ar->peer_delete_done);
334
335
ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
336
if (ret) {
337
ath11k_warn(ab,
338
"failed to delete peer vdev_id %d addr %pM ret %d\n",
339
vdev_id, addr, ret);
340
return ret;
341
}
342
343
ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
344
if (ret)
345
return ret;
346
347
return 0;
348
}
349
350
int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
351
{
352
int ret;
353
354
lockdep_assert_held(&ar->conf_mutex);
355
356
ret = __ath11k_peer_delete(ar, vdev_id, addr);
357
if (ret)
358
return ret;
359
360
ar->num_peers--;
361
362
return 0;
363
}
364
365
static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr)
366
{
367
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
368
}
369
370
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
371
struct ieee80211_sta *sta, struct peer_create_params *param)
372
{
373
struct ath11k_peer *peer;
374
struct ath11k_sta *arsta;
375
int ret, fbret;
376
377
lockdep_assert_held(&ar->conf_mutex);
378
379
if (ar->num_peers > (ar->max_num_peers - 1)) {
380
ath11k_warn(ar->ab,
381
"failed to create peer due to insufficient peer entry resource in firmware\n");
382
return -ENOBUFS;
383
}
384
385
mutex_lock(&ar->ab->tbl_mtx_lock);
386
spin_lock_bh(&ar->ab->base_lock);
387
peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
388
if (peer) {
389
if (peer->vdev_id == param->vdev_id) {
390
spin_unlock_bh(&ar->ab->base_lock);
391
mutex_unlock(&ar->ab->tbl_mtx_lock);
392
return -EINVAL;
393
}
394
395
/* Assume sta is transitioning to another band.
396
* Remove here the peer from rhash.
397
*/
398
ath11k_peer_rhash_delete(ar->ab, peer);
399
}
400
spin_unlock_bh(&ar->ab->base_lock);
401
mutex_unlock(&ar->ab->tbl_mtx_lock);
402
403
ret = ath11k_wmi_send_peer_create_cmd(ar, param);
404
if (ret) {
405
ath11k_warn(ar->ab,
406
"failed to send peer create vdev_id %d ret %d\n",
407
param->vdev_id, ret);
408
return ret;
409
}
410
411
ret = ath11k_wait_for_peer_created(ar, param->vdev_id,
412
param->peer_addr);
413
if (ret)
414
return ret;
415
416
mutex_lock(&ar->ab->tbl_mtx_lock);
417
spin_lock_bh(&ar->ab->base_lock);
418
419
peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
420
if (!peer) {
421
spin_unlock_bh(&ar->ab->base_lock);
422
mutex_unlock(&ar->ab->tbl_mtx_lock);
423
ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
424
param->peer_addr, param->vdev_id);
425
426
ret = -ENOENT;
427
goto cleanup;
428
}
429
430
ret = ath11k_peer_rhash_add(ar->ab, peer);
431
if (ret) {
432
spin_unlock_bh(&ar->ab->base_lock);
433
mutex_unlock(&ar->ab->tbl_mtx_lock);
434
goto cleanup;
435
}
436
437
peer->pdev_idx = ar->pdev_idx;
438
peer->sta = sta;
439
440
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
441
arvif->ast_hash = peer->ast_hash;
442
arvif->ast_idx = peer->hw_peer_id;
443
}
444
445
peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
446
peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
447
448
if (sta) {
449
arsta = (struct ath11k_sta *)sta->drv_priv;
450
arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
451
FIELD_PREP(HTT_TCL_META_DATA_PEER_ID,
452
peer->peer_id);
453
454
/* set HTT extension valid bit to 0 by default */
455
arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
456
}
457
458
ar->num_peers++;
459
460
spin_unlock_bh(&ar->ab->base_lock);
461
mutex_unlock(&ar->ab->tbl_mtx_lock);
462
463
return 0;
464
465
cleanup:
466
fbret = __ath11k_peer_delete(ar, param->vdev_id, param->peer_addr);
467
if (fbret)
468
ath11k_warn(ar->ab, "failed peer %pM delete vdev_id %d fallback ret %d\n",
469
param->peer_addr, param->vdev_id, fbret);
470
471
return ret;
472
}
473
474
int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
475
{
476
int ret;
477
478
lockdep_assert_held(&ab->base_lock);
479
lockdep_assert_held(&ab->tbl_mtx_lock);
480
481
if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
482
return -EPERM;
483
484
ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
485
&ab->rhash_peer_addr_param);
486
if (ret) {
487
ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
488
peer->addr, peer->peer_id, ret);
489
return ret;
490
}
491
492
ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
493
&ab->rhash_peer_id_param);
494
if (ret) {
495
ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
496
peer->addr, peer->peer_id, ret);
497
return ret;
498
}
499
500
return 0;
501
}
502
503
static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
504
{
505
struct rhashtable_params *param;
506
struct rhashtable *rhash_id_tbl;
507
int ret;
508
size_t size;
509
510
lockdep_assert_held(&ab->tbl_mtx_lock);
511
512
if (ab->rhead_peer_id)
513
return 0;
514
515
size = sizeof(*ab->rhead_peer_id);
516
rhash_id_tbl = kzalloc(size, GFP_KERNEL);
517
if (!rhash_id_tbl) {
518
ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
519
size);
520
return -ENOMEM;
521
}
522
523
param = &ab->rhash_peer_id_param;
524
525
param->key_offset = offsetof(struct ath11k_peer, peer_id);
526
param->head_offset = offsetof(struct ath11k_peer, rhash_id);
527
param->key_len = sizeof_field(struct ath11k_peer, peer_id);
528
param->automatic_shrinking = true;
529
param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
530
531
ret = rhashtable_init(rhash_id_tbl, param);
532
if (ret) {
533
ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
534
goto err_free;
535
}
536
537
spin_lock_bh(&ab->base_lock);
538
539
if (!ab->rhead_peer_id) {
540
ab->rhead_peer_id = rhash_id_tbl;
541
} else {
542
spin_unlock_bh(&ab->base_lock);
543
goto cleanup_tbl;
544
}
545
546
spin_unlock_bh(&ab->base_lock);
547
548
return 0;
549
550
cleanup_tbl:
551
rhashtable_destroy(rhash_id_tbl);
552
err_free:
553
kfree(rhash_id_tbl);
554
555
return ret;
556
}
557
558
static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
559
{
560
struct rhashtable_params *param;
561
struct rhashtable *rhash_addr_tbl;
562
int ret;
563
size_t size;
564
565
lockdep_assert_held(&ab->tbl_mtx_lock);
566
567
if (ab->rhead_peer_addr)
568
return 0;
569
570
size = sizeof(*ab->rhead_peer_addr);
571
rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
572
if (!rhash_addr_tbl) {
573
ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
574
size);
575
return -ENOMEM;
576
}
577
578
param = &ab->rhash_peer_addr_param;
579
580
param->key_offset = offsetof(struct ath11k_peer, addr);
581
param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
582
param->key_len = sizeof_field(struct ath11k_peer, addr);
583
param->automatic_shrinking = true;
584
param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
585
586
ret = rhashtable_init(rhash_addr_tbl, param);
587
if (ret) {
588
ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
589
goto err_free;
590
}
591
592
spin_lock_bh(&ab->base_lock);
593
594
if (!ab->rhead_peer_addr) {
595
ab->rhead_peer_addr = rhash_addr_tbl;
596
} else {
597
spin_unlock_bh(&ab->base_lock);
598
goto cleanup_tbl;
599
}
600
601
spin_unlock_bh(&ab->base_lock);
602
603
return 0;
604
605
cleanup_tbl:
606
rhashtable_destroy(rhash_addr_tbl);
607
err_free:
608
kfree(rhash_addr_tbl);
609
610
return ret;
611
}
612
613
static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
614
{
615
lockdep_assert_held(&ab->tbl_mtx_lock);
616
617
if (!ab->rhead_peer_id)
618
return;
619
620
rhashtable_destroy(ab->rhead_peer_id);
621
kfree(ab->rhead_peer_id);
622
ab->rhead_peer_id = NULL;
623
}
624
625
static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
626
{
627
lockdep_assert_held(&ab->tbl_mtx_lock);
628
629
if (!ab->rhead_peer_addr)
630
return;
631
632
rhashtable_destroy(ab->rhead_peer_addr);
633
kfree(ab->rhead_peer_addr);
634
ab->rhead_peer_addr = NULL;
635
}
636
637
int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
638
{
639
int ret;
640
641
mutex_lock(&ab->tbl_mtx_lock);
642
643
ret = ath11k_peer_rhash_id_tbl_init(ab);
644
if (ret)
645
goto out;
646
647
ret = ath11k_peer_rhash_addr_tbl_init(ab);
648
if (ret)
649
goto cleanup_tbl;
650
651
mutex_unlock(&ab->tbl_mtx_lock);
652
653
return 0;
654
655
cleanup_tbl:
656
ath11k_peer_rhash_id_tbl_destroy(ab);
657
out:
658
mutex_unlock(&ab->tbl_mtx_lock);
659
return ret;
660
}
661
662
void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
663
{
664
mutex_lock(&ab->tbl_mtx_lock);
665
666
ath11k_peer_rhash_addr_tbl_destroy(ab);
667
ath11k_peer_rhash_id_tbl_destroy(ab);
668
669
mutex_unlock(&ab->tbl_mtx_lock);
670
}
671
672