Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/rtw89/chan.c
105210 views
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
/* Copyright(c) 2020-2022 Realtek Corporation
3
*/
4
5
#include "chan.h"
6
#include "coex.h"
7
#include "debug.h"
8
#include "fw.h"
9
#include "mac.h"
10
#include "phy.h"
11
#include "ps.h"
12
#include "sar.h"
13
#include "util.h"
14
15
static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
16
enum rtw89_chanctx_idx idx1,
17
enum rtw89_chanctx_idx idx2);
18
19
static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
20
u8 center_chan)
21
{
22
switch (band) {
23
default:
24
case RTW89_BAND_2G:
25
switch (center_chan) {
26
default:
27
case 1 ... 14:
28
return RTW89_CH_2G;
29
}
30
case RTW89_BAND_5G:
31
switch (center_chan) {
32
default:
33
case 36 ... 64:
34
return RTW89_CH_5G_BAND_1;
35
case 100 ... 144:
36
return RTW89_CH_5G_BAND_3;
37
case 149 ... 177:
38
return RTW89_CH_5G_BAND_4;
39
}
40
case RTW89_BAND_6G:
41
switch (center_chan) {
42
default:
43
case 1 ... 29:
44
return RTW89_CH_6G_BAND_IDX0;
45
case 33 ... 61:
46
return RTW89_CH_6G_BAND_IDX1;
47
case 65 ... 93:
48
return RTW89_CH_6G_BAND_IDX2;
49
case 97 ... 125:
50
return RTW89_CH_6G_BAND_IDX3;
51
case 129 ... 157:
52
return RTW89_CH_6G_BAND_IDX4;
53
case 161 ... 189:
54
return RTW89_CH_6G_BAND_IDX5;
55
case 193 ... 221:
56
return RTW89_CH_6G_BAND_IDX6;
57
case 225 ... 253:
58
return RTW89_CH_6G_BAND_IDX7;
59
}
60
}
61
}
62
63
static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
64
u32 center_freq,
65
u32 primary_freq)
66
{
67
u8 primary_chan_idx;
68
u32 offset;
69
70
switch (bw) {
71
default:
72
case RTW89_CHANNEL_WIDTH_20:
73
primary_chan_idx = RTW89_SC_DONT_CARE;
74
break;
75
case RTW89_CHANNEL_WIDTH_40:
76
if (primary_freq > center_freq)
77
primary_chan_idx = RTW89_SC_20_UPPER;
78
else
79
primary_chan_idx = RTW89_SC_20_LOWER;
80
break;
81
case RTW89_CHANNEL_WIDTH_80:
82
case RTW89_CHANNEL_WIDTH_160:
83
if (primary_freq > center_freq) {
84
offset = (primary_freq - center_freq - 10) / 20;
85
primary_chan_idx = RTW89_SC_20_UPPER + offset * 2;
86
} else {
87
offset = (center_freq - primary_freq - 10) / 20;
88
primary_chan_idx = RTW89_SC_20_LOWER + offset * 2;
89
}
90
break;
91
}
92
93
return primary_chan_idx;
94
}
95
96
static u8 rtw89_get_primary_sb_idx(u8 central_ch, u8 pri_ch,
97
enum rtw89_bandwidth bw)
98
{
99
static const u8 prisb_cal_ofst[RTW89_CHANNEL_WIDTH_ORDINARY_NUM] = {
100
0, 2, 6, 14, 30
101
};
102
103
if (bw >= RTW89_CHANNEL_WIDTH_ORDINARY_NUM)
104
return 0;
105
106
return (prisb_cal_ofst[bw] + pri_ch - central_ch) / 4;
107
}
108
109
void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
110
enum rtw89_band band, enum rtw89_bandwidth bandwidth)
111
{
112
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
113
u32 center_freq, primary_freq;
114
115
memset(chan, 0, sizeof(*chan));
116
chan->channel = center_chan;
117
chan->primary_channel = primary_chan;
118
chan->band_type = band;
119
chan->band_width = bandwidth;
120
121
center_freq = ieee80211_channel_to_frequency(center_chan, nl_band);
122
primary_freq = ieee80211_channel_to_frequency(primary_chan, nl_band);
123
124
chan->freq = center_freq;
125
chan->subband_type = rtw89_get_subband_type(band, center_chan);
126
chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq,
127
primary_freq);
128
chan->pri_sb_idx = rtw89_get_primary_sb_idx(center_chan, primary_chan,
129
bandwidth);
130
}
131
132
static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev,
133
struct rtw89_vif_link *rtwvif_link,
134
const struct cfg80211_chan_def *chandef)
135
{
136
struct ieee80211_bss_conf *bss_conf;
137
138
if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION &&
139
rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
140
return;
141
142
rcu_read_lock();
143
144
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
145
if (!bss_conf->eht_support) {
146
rcu_read_unlock();
147
return;
148
}
149
150
rcu_read_unlock();
151
152
rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured);
153
}
154
155
static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev,
156
enum rtw89_chanctx_idx idx,
157
const struct cfg80211_chan_def *chandef)
158
{
159
struct rtw89_vif_link *rtwvif_link;
160
struct rtw89_vif *rtwvif;
161
unsigned int link_id;
162
163
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
164
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
165
if (!rtwvif_link->chanctx_assigned ||
166
rtwvif_link->chanctx_idx != idx)
167
continue;
168
169
_rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef);
170
}
171
}
172
}
173
174
bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
175
enum rtw89_chanctx_idx idx,
176
const struct rtw89_chan *new)
177
{
178
struct rtw89_hal *hal = &rtwdev->hal;
179
struct rtw89_chan *chan = &hal->chanctx[idx].chan;
180
struct rtw89_chan_rcd *rcd = &hal->chanctx[idx].rcd;
181
bool band_changed;
182
183
rcd->prev_primary_channel = chan->primary_channel;
184
rcd->prev_band_type = chan->band_type;
185
band_changed = new->band_type != chan->band_type;
186
rcd->band_changed = band_changed;
187
188
*chan = *new;
189
return band_changed;
190
}
191
192
int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,
193
int (*iterator)(const struct rtw89_chan *chan,
194
void *data),
195
void *data)
196
{
197
struct rtw89_hal *hal = &rtwdev->hal;
198
const struct rtw89_chan *chan;
199
int ret;
200
u8 idx;
201
202
lockdep_assert_wiphy(rtwdev->hw->wiphy);
203
204
for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) {
205
chan = rtw89_chan_get(rtwdev, idx);
206
ret = iterator(chan, data);
207
if (ret)
208
return ret;
209
}
210
211
return 0;
212
}
213
214
static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
215
enum rtw89_chanctx_idx idx,
216
const struct cfg80211_chan_def *chandef)
217
{
218
struct rtw89_hal *hal = &rtwdev->hal;
219
220
hal->chanctx[idx].chandef = *chandef;
221
}
222
223
void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
224
enum rtw89_chanctx_idx idx,
225
const struct cfg80211_chan_def *chandef)
226
{
227
struct rtw89_hal *hal = &rtwdev->hal;
228
229
if (!chandef) {
230
clear_bit(idx, hal->entity_map);
231
return;
232
}
233
234
__rtw89_config_entity_chandef(rtwdev, idx, chandef);
235
set_bit(idx, hal->entity_map);
236
}
237
238
void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
239
struct rtw89_vif_link *rtwvif_link,
240
const struct cfg80211_chan_def *chandef)
241
{
242
enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx;
243
struct rtw89_hal *hal = &rtwdev->hal;
244
enum rtw89_chanctx_idx cur;
245
246
if (chandef) {
247
cur = atomic_cmpxchg(&hal->roc_chanctx_idx,
248
RTW89_CHANCTX_IDLE, idx);
249
if (cur != RTW89_CHANCTX_IDLE) {
250
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
251
"ROC still processing on entity %d\n", idx);
252
return;
253
}
254
255
hal->roc_chandef = *chandef;
256
hal->roc_link_index = rtw89_vif_link_inst_get_index(rtwvif_link);
257
} else {
258
cur = atomic_cmpxchg(&hal->roc_chanctx_idx, idx,
259
RTW89_CHANCTX_IDLE);
260
if (cur == idx)
261
return;
262
263
if (cur == RTW89_CHANCTX_IDLE)
264
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
265
"ROC already finished on entity %d\n", idx);
266
else
267
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
268
"ROC is processing on entity %d\n", cur);
269
}
270
}
271
272
static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
273
{
274
struct cfg80211_chan_def chandef = {0};
275
276
rtw89_get_default_chandef(&chandef);
277
__rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef);
278
}
279
280
void rtw89_entity_init(struct rtw89_dev *rtwdev)
281
{
282
struct rtw89_hal *hal = &rtwdev->hal;
283
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
284
int i, j;
285
286
hal->entity_pause = false;
287
bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX);
288
bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
289
atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE);
290
291
INIT_LIST_HEAD(&mgnt->active_list);
292
293
for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) {
294
for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++)
295
mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE;
296
}
297
298
rtw89_config_default_chandef(rtwdev);
299
}
300
301
static bool rtw89_vif_is_active_role(struct rtw89_vif *rtwvif)
302
{
303
struct rtw89_vif_link *rtwvif_link;
304
unsigned int link_id;
305
306
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
307
if (rtwvif_link->chanctx_assigned)
308
return true;
309
310
return false;
311
}
312
313
static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
314
struct rtw89_entity_weight *w)
315
{
316
struct rtw89_hal *hal = &rtwdev->hal;
317
const struct rtw89_chanctx_cfg *cfg;
318
struct rtw89_vif *rtwvif;
319
int idx;
320
321
w->registered_chanctxs = bitmap_weight(hal->entity_map, NUM_OF_RTW89_CHANCTX);
322
323
for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) {
324
cfg = hal->chanctx[idx].cfg;
325
if (!cfg) {
326
/* doesn't run with chanctx ops; one channel at most */
327
w->active_chanctxs = 1;
328
break;
329
}
330
331
if (cfg->ref_count > 0)
332
w->active_chanctxs++;
333
}
334
335
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
336
if (rtw89_vif_is_active_role(rtwvif))
337
w->active_roles++;
338
}
339
}
340
341
static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
342
struct rtw89_vif_link *rtwvif_link)
343
{
344
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
345
struct rtw89_vif_link *cur;
346
347
if (unlikely(!rtwvif_link->chanctx_assigned))
348
return;
349
350
cur = rtw89_vif_get_link_inst(rtwvif, 0);
351
if (!cur || !cur->chanctx_assigned)
352
return;
353
354
if (cur == rtwvif_link)
355
return;
356
357
rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx);
358
}
359
360
const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
361
const char *caller_message,
362
u8 link_index, bool nullchk)
363
{
364
struct rtw89_hal *hal = &rtwdev->hal;
365
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
366
enum rtw89_chanctx_idx chanctx_idx;
367
enum rtw89_chanctx_idx roc_idx;
368
enum rtw89_entity_mode mode;
369
u8 role_index;
370
371
lockdep_assert_wiphy(rtwdev->hw->wiphy);
372
373
if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) {
374
WARN(1, "link index %u is invalid (max link inst num: %d)\n",
375
link_index, __RTW89_MLD_MAX_LINK_NUM);
376
goto dflt;
377
}
378
379
mode = rtw89_get_entity_mode(rtwdev);
380
switch (mode) {
381
case RTW89_ENTITY_MODE_SCC_OR_SMLD:
382
case RTW89_ENTITY_MODE_MCC:
383
role_index = 0;
384
break;
385
case RTW89_ENTITY_MODE_MCC_PREPARE:
386
role_index = 1;
387
break;
388
default:
389
WARN(1, "Invalid ent mode: %d\n", mode);
390
goto dflt;
391
}
392
393
chanctx_idx = mgnt->chanctx_tbl[role_index][link_index];
394
if (chanctx_idx == RTW89_CHANCTX_IDLE)
395
goto dflt;
396
397
roc_idx = atomic_read(&hal->roc_chanctx_idx);
398
if (roc_idx != RTW89_CHANCTX_IDLE) {
399
/* ROC is ongoing (given ROC runs on @hal->roc_link_index).
400
* If @link_index is the same, get the ongoing ROC chanctx.
401
*/
402
if (link_index == hal->roc_link_index)
403
chanctx_idx = roc_idx;
404
}
405
406
return rtw89_chan_get(rtwdev, chanctx_idx);
407
408
dflt:
409
if (unlikely(nullchk))
410
return NULL;
411
412
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
413
"%s (%s): prefetch NULL on link index %u\n",
414
__func__, caller_message ?: "", link_index);
415
416
return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
417
}
418
EXPORT_SYMBOL(__rtw89_mgnt_chan_get);
419
420
static enum rtw89_mlo_dbcc_mode
421
rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
422
{
423
if (rtwdev->chip->chip_gen != RTW89_CHIP_BE)
424
return MLO_DBCC_NOT_SUPPORT;
425
426
switch (active_hws) {
427
case BIT(0):
428
return MLO_2_PLUS_0_1RF;
429
case BIT(1):
430
return MLO_0_PLUS_2_1RF;
431
case BIT(0) | BIT(1):
432
default:
433
return MLO_1_PLUS_1_1RF;
434
}
435
}
436
437
static
438
void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
439
{
440
enum rtw89_mlo_dbcc_mode mode;
441
442
mode = rtw89_entity_sel_mlo_dbcc_mode(rtwdev, active_hws);
443
rtwdev->mlo_dbcc_mode = mode;
444
445
rtw89_debug(rtwdev, RTW89_DBG_STATE, "recalc mlo dbcc mode to %d\n", mode);
446
}
447
448
static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
449
{
450
struct rtw89_hal *hal = &rtwdev->hal;
451
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
452
struct rtw89_vif_link *link;
453
struct rtw89_vif *role;
454
u8 active_hws = 0;
455
u8 pos = 0;
456
int i, j;
457
458
lockdep_assert_wiphy(rtwdev->hw->wiphy);
459
460
for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++)
461
mgnt->active_roles[i] = NULL;
462
463
for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) {
464
for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++)
465
mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE;
466
}
467
468
/* To be consistent with legacy behavior, expect the first active role
469
* which uses RTW89_CHANCTX_0 to put at position 0, and make its first
470
* link instance take RTW89_CHANCTX_0. (normalizing)
471
*/
472
list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
473
for (i = 0; i < role->links_inst_valid_num; i++) {
474
link = rtw89_vif_get_link_inst(role, i);
475
if (!link || !link->chanctx_assigned)
476
continue;
477
478
if (link->chanctx_idx == RTW89_CHANCTX_0) {
479
rtw89_normalize_link_chanctx(rtwdev, link);
480
481
list_del(&role->mgnt_entry);
482
list_add(&role->mgnt_entry, &mgnt->active_list);
483
goto fill;
484
}
485
}
486
}
487
488
fill:
489
list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
490
if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) {
491
rtw89_warn(rtwdev,
492
"%s: active roles are over max iface num\n",
493
__func__);
494
break;
495
}
496
497
for (i = 0; i < role->links_inst_valid_num; i++) {
498
link = rtw89_vif_get_link_inst(role, i);
499
if (!link || !link->chanctx_assigned)
500
continue;
501
502
mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
503
active_hws |= BIT(i);
504
}
505
506
mgnt->active_roles[pos++] = role;
507
}
508
509
rtw89_entity_recalc_mlo_dbcc_mode(rtwdev, active_hws);
510
}
511
512
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
513
{
514
DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {};
515
struct rtw89_hal *hal = &rtwdev->hal;
516
const struct cfg80211_chan_def *chandef;
517
struct rtw89_entity_weight w = {};
518
enum rtw89_entity_mode mode;
519
struct rtw89_chan chan;
520
u8 idx;
521
522
lockdep_assert_wiphy(rtwdev->hw->wiphy);
523
524
bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_CHANCTX);
525
526
rtw89_entity_calculate_weight(rtwdev, &w);
527
switch (w.active_chanctxs) {
528
default:
529
rtw89_warn(rtwdev, "unknown ent chanctxs weight: %d\n",
530
w.active_chanctxs);
531
bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX);
532
fallthrough;
533
case 0:
534
if (!w.registered_chanctxs)
535
rtw89_config_default_chandef(rtwdev);
536
set_bit(RTW89_CHANCTX_0, recalc_map);
537
fallthrough;
538
case 1:
539
mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
540
break;
541
case 2 ... NUM_OF_RTW89_CHANCTX:
542
if (w.active_roles == 1) {
543
mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
544
break;
545
}
546
547
if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) {
548
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
549
"unhandled ent: %d chanctxs %d roles\n",
550
w.active_chanctxs, w.active_roles);
551
return RTW89_ENTITY_MODE_UNHANDLED;
552
}
553
554
mode = rtw89_get_entity_mode(rtwdev);
555
if (mode == RTW89_ENTITY_MODE_MCC)
556
break;
557
558
mode = RTW89_ENTITY_MODE_MCC_PREPARE;
559
break;
560
}
561
562
for_each_set_bit(idx, recalc_map, NUM_OF_RTW89_CHANCTX) {
563
chandef = rtw89_chandef_get(rtwdev, idx);
564
rtw89_get_channel_params(chandef, &chan);
565
if (chan.channel == 0) {
566
WARN(1, "Invalid channel on chanctx %d\n", idx);
567
return RTW89_ENTITY_MODE_INVALID;
568
}
569
570
rtw89_assign_entity_chan(rtwdev, idx, &chan);
571
}
572
573
rtw89_entity_recalc_mgnt_roles(rtwdev);
574
575
if (hal->entity_pause)
576
return rtw89_get_entity_mode(rtwdev);
577
578
rtw89_set_entity_mode(rtwdev, mode);
579
return mode;
580
}
581
582
static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
583
enum rtw89_chanctx_state state)
584
{
585
const struct rtw89_chip_info *chip = rtwdev->chip;
586
const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
587
int i;
588
589
if (!listener)
590
return;
591
592
for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
593
if (!listener->callbacks[i])
594
continue;
595
596
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
597
"chanctx notify listener: cb %d, state %d\n",
598
i, state);
599
600
listener->callbacks[i](rtwdev, state);
601
}
602
}
603
604
static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev)
605
{
606
enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
607
608
return chip_gen == RTW89_CHIP_BE;
609
}
610
611
/* This function centrally manages how MCC roles are sorted and iterated.
612
* And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES.
613
* So, if data needs to pass an array for ordered_idx, the array can declare
614
* with NUM_OF_RTW89_MCC_ROLES. Besides, the entire iteration will stop
615
* immediately as long as iterator returns a non-zero value.
616
*/
617
static
618
int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev,
619
int (*iterator)(struct rtw89_dev *rtwdev,
620
struct rtw89_mcc_role *mcc_role,
621
unsigned int ordered_idx,
622
void *data),
623
void *data)
624
{
625
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
626
struct rtw89_mcc_role * const roles[] = {
627
&mcc->role_ref,
628
&mcc->role_aux,
629
};
630
unsigned int idx;
631
int ret;
632
633
BUILD_BUG_ON(ARRAY_SIZE(roles) != NUM_OF_RTW89_MCC_ROLES);
634
635
for (idx = 0; idx < NUM_OF_RTW89_MCC_ROLES; idx++) {
636
ret = iterator(rtwdev, roles[idx], idx, data);
637
if (ret)
638
return ret;
639
}
640
641
return 0;
642
}
643
644
static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
645
struct rtw89_mcc_role *role, u64 tsf)
646
{
647
struct rtw89_vif_link *rtwvif_link = role->rtwvif_link;
648
u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval);
649
u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);
650
u32 remainder;
651
652
if (role->is_go) {
653
sync_tsf = 0;
654
} else if (tsf < sync_tsf) {
655
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
656
"MCC get tbtt ofst: tsf might not update yet\n");
657
sync_tsf = 0;
658
}
659
660
div_u64_rem(tsf - sync_tsf, bcn_intvl_us, &remainder);
661
662
return remainder;
663
}
664
665
static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
666
{
667
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
668
struct rtw89_mcc_role *ref = &mcc->role_ref;
669
struct rtw89_mcc_role *aux = &mcc->role_aux;
670
struct rtw89_mac_mcc_tsf_rpt rpt = {};
671
struct rtw89_fw_mcc_tsf_req req = {};
672
int ret;
673
674
req.group = mcc->group;
675
req.macid_x = ref->rtwvif_link->mac_id;
676
req.macid_y = aux->rtwvif_link->mac_id;
677
ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt);
678
if (ret) {
679
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
680
"MCC h2c failed to request tsf: %d\n", ret);
681
return ret;
682
}
683
684
*tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
685
*tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
686
687
return 0;
688
}
689
690
static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
691
{
692
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
693
struct rtw89_mcc_role *ref = &mcc->role_ref;
694
struct rtw89_mcc_role *aux = &mcc->role_aux;
695
struct rtw89_fw_mrc_req_tsf_arg arg = {};
696
struct rtw89_mac_mrc_tsf_rpt rpt = {};
697
int ret;
698
699
BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
700
701
arg.num = 2;
702
arg.infos[0].band = ref->rtwvif_link->mac_idx;
703
arg.infos[0].port = ref->rtwvif_link->port;
704
arg.infos[1].band = aux->rtwvif_link->mac_idx;
705
arg.infos[1].port = aux->rtwvif_link->port;
706
707
ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt);
708
if (ret) {
709
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
710
"MRC h2c failed to request tsf: %d\n", ret);
711
return ret;
712
}
713
714
*tsf_ref = rpt.tsfs[0];
715
*tsf_aux = rpt.tsfs[1];
716
717
return 0;
718
}
719
720
static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
721
{
722
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
723
struct rtw89_mcc_role *ref = &mcc->role_ref;
724
struct rtw89_mcc_role *aux = &mcc->role_aux;
725
u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
726
u32 tbtt_ofst_ref, tbtt_ofst_aux;
727
u64 tsf_ref, tsf_aux;
728
int ret;
729
730
if (rtw89_concurrent_via_mrc(rtwdev))
731
ret = __mrc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
732
else
733
ret = __mcc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
734
735
if (ret)
736
return RTW89_MCC_DFLT_BCN_OFST_TIME;
737
738
tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf_ref);
739
tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, aux, tsf_aux);
740
741
while (tbtt_ofst_ref < tbtt_ofst_aux)
742
tbtt_ofst_ref += bcn_intvl_ref_us;
743
744
return (tbtt_ofst_ref - tbtt_ofst_aux) / 1024;
745
}
746
747
static
748
void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role,
749
unsigned int bit)
750
{
751
unsigned int idx = bit / 8;
752
unsigned int pos = bit % 8;
753
754
if (idx >= ARRAY_SIZE(mcc_role->macid_bitmap))
755
return;
756
757
mcc_role->macid_bitmap[idx] |= BIT(pos);
758
}
759
760
static
761
u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role)
762
{
763
unsigned int macid;
764
unsigned int i, j;
765
u32 bitmap = 0;
766
767
for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) {
768
for (j = 0; j < 8; j++) {
769
macid = i * 8 + j;
770
if (macid >= 32)
771
goto out;
772
773
if (mcc_role->macid_bitmap[i] & BIT(j))
774
bitmap |= BIT(macid);
775
}
776
}
777
778
out:
779
return bitmap;
780
}
781
782
static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
783
{
784
struct rtw89_mcc_role *mcc_role = data;
785
struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif;
786
struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
787
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
788
u8 macid;
789
790
if (rtwvif != target)
791
return;
792
793
macid = rtw89_sta_get_main_macid(rtwsta);
794
rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, macid);
795
}
796
797
static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
798
struct rtw89_mcc_role *mcc_role)
799
{
800
struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
801
802
rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif_link->mac_id);
803
ieee80211_iterate_stations_atomic(rtwdev->hw,
804
rtw89_mcc_role_macid_sta_iter,
805
mcc_role);
806
}
807
808
static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev,
809
struct rtw89_mcc_role *mcc_role)
810
{
811
struct rtw89_mcc_policy *policy = &mcc_role->policy;
812
813
policy->c2h_rpt = RTW89_FW_MCC_C2H_RPT_ALL;
814
policy->tx_null_early = RTW89_MCC_DFLT_TX_NULL_EARLY;
815
policy->in_curr_ch = false;
816
policy->dis_sw_retry = true;
817
policy->sw_retry_count = false;
818
819
if (mcc_role->is_go)
820
policy->dis_tx_null = true;
821
else
822
policy->dis_tx_null = false;
823
}
824
825
static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
826
struct rtw89_mcc_role *mcc_role)
827
{
828
struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
829
struct ieee80211_p2p_noa_desc *noa_desc;
830
struct ieee80211_bss_conf *bss_conf;
831
u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval);
832
u32 max_toa_us, max_tob_us, max_dur_us;
833
u32 start_time, interval, duration;
834
u64 tsf, tsf_lmt;
835
int ret;
836
int i;
837
838
if (!mcc_role->is_gc)
839
return;
840
841
rtw89_p2p_noa_once_recalc(rtwvif_link);
842
843
rcu_read_lock();
844
845
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
846
847
/* find the first periodic NoA */
848
for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
849
noa_desc = &bss_conf->p2p_noa_attr.desc[i];
850
if (noa_desc->count == 255)
851
goto fill;
852
}
853
854
rcu_read_unlock();
855
return;
856
857
fill:
858
start_time = le32_to_cpu(noa_desc->start_time);
859
interval = le32_to_cpu(noa_desc->interval);
860
duration = le32_to_cpu(noa_desc->duration);
861
862
rcu_read_unlock();
863
864
if (interval != bcn_intvl_us) {
865
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
866
"MCC role limit: mismatch interval: %d vs. %d\n",
867
interval, bcn_intvl_us);
868
return;
869
}
870
871
ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
872
if (ret) {
873
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
874
return;
875
}
876
877
tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time;
878
if (tsf_lmt < tsf)
879
tsf_lmt += roundup_u64(tsf - tsf_lmt, interval);
880
881
max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, mcc_role, tsf_lmt);
882
max_dur_us = interval - duration;
883
max_tob_us = max_dur_us - max_toa_us;
884
885
if (!max_toa_us || !max_tob_us) {
886
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
887
"MCC role limit: hit boundary\n");
888
return;
889
}
890
891
if (max_dur_us < max_toa_us) {
892
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
893
"MCC role limit: insufficient duration\n");
894
return;
895
}
896
897
mcc_role->limit.max_toa = max_toa_us / 1024;
898
mcc_role->limit.max_tob = max_tob_us / 1024;
899
mcc_role->limit.max_dur = mcc_role->limit.max_toa + mcc_role->limit.max_tob;
900
mcc_role->limit.enable = true;
901
902
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
903
"MCC role limit: max_toa %d, max_tob %d, max_dur %d\n",
904
mcc_role->limit.max_toa, mcc_role->limit.max_tob,
905
mcc_role->limit.max_dur);
906
}
907
908
static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
909
struct rtw89_vif_link *rtwvif_link,
910
struct rtw89_mcc_role *role)
911
{
912
struct ieee80211_bss_conf *bss_conf;
913
const struct rtw89_chan *chan;
914
915
memset(role, 0, sizeof(*role));
916
role->rtwvif_link = rtwvif_link;
917
918
rcu_read_lock();
919
920
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
921
role->beacon_interval = bss_conf->beacon_int;
922
923
rcu_read_unlock();
924
925
if (!role->beacon_interval) {
926
rtw89_warn(rtwdev,
927
"cannot handle MCC role without beacon interval\n");
928
return -EINVAL;
929
}
930
931
role->duration = role->beacon_interval / 2;
932
933
chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
934
role->is_2ghz = chan->band_type == RTW89_BAND_2G;
935
role->is_go = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
936
role->is_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
937
938
rtw89_mcc_fill_role_macid_bitmap(rtwdev, role);
939
rtw89_mcc_fill_role_policy(rtwdev, role);
940
rtw89_mcc_fill_role_limit(rtwdev, role);
941
942
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
943
"MCC role: bcn_intvl %d, is_2ghz %d, is_go %d, is_gc %d\n",
944
role->beacon_interval, role->is_2ghz, role->is_go, role->is_gc);
945
return 0;
946
}
947
948
static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev)
949
{
950
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
951
struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
952
953
memset(bt_role, 0, sizeof(*bt_role));
954
bt_role->duration = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
955
956
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC bt role: dur %d\n",
957
bt_role->duration);
958
}
959
960
struct rtw89_mcc_fill_role_selector {
961
struct rtw89_vif_link *bind_vif[NUM_OF_RTW89_CHANCTX];
962
};
963
964
static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES);
965
static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES);
966
967
static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
968
struct rtw89_mcc_role *mcc_role,
969
unsigned int ordered_idx,
970
void *data)
971
{
972
struct rtw89_mcc_fill_role_selector *sel = data;
973
struct rtw89_vif_link *role_vif = sel->bind_vif[ordered_idx];
974
int ret;
975
976
if (!role_vif) {
977
rtw89_warn(rtwdev, "cannot handle MCC without role[%d]\n",
978
ordered_idx);
979
return -EINVAL;
980
}
981
982
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
983
"MCC fill role[%d] with vif <macid %d>\n",
984
ordered_idx, role_vif->mac_id);
985
986
ret = rtw89_mcc_fill_role(rtwdev, role_vif, mcc_role);
987
if (ret)
988
return ret;
989
990
return 0;
991
}
992
993
static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
994
{
995
struct rtw89_hal *hal = &rtwdev->hal;
996
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
997
struct rtw89_mcc_fill_role_selector sel = {};
998
struct rtw89_vif_link *rtwvif_link;
999
struct rtw89_vif *rtwvif;
1000
int ret;
1001
int i;
1002
1003
for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) {
1004
rtwvif = mgnt->active_roles[i];
1005
if (!rtwvif)
1006
break;
1007
1008
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
1009
if (unlikely(!rtwvif_link)) {
1010
rtw89_err(rtwdev, "mcc fill roles: find no link on HW-0\n");
1011
continue;
1012
}
1013
1014
sel.bind_vif[i] = rtwvif_link;
1015
rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, NULL);
1016
}
1017
1018
ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel);
1019
if (ret)
1020
return ret;
1021
1022
rtw89_mcc_fill_bt_role(rtwdev);
1023
return 0;
1024
}
1025
1026
static bool rtw89_mcc_can_courtesy(const struct rtw89_mcc_role *provider,
1027
const struct rtw89_mcc_role *receiver)
1028
{
1029
if (provider->is_go || receiver->is_gc)
1030
return false;
1031
1032
return true;
1033
}
1034
1035
static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
1036
const struct rtw89_mcc_pattern *new)
1037
{
1038
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1039
struct rtw89_mcc_role *ref = &mcc->role_ref;
1040
struct rtw89_mcc_role *aux = &mcc->role_aux;
1041
struct rtw89_mcc_config *config = &mcc->config;
1042
struct rtw89_mcc_pattern *pattern = &config->pattern;
1043
struct rtw89_mcc_courtesy_cfg *crtz;
1044
1045
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1046
"MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",
1047
new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux);
1048
1049
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC pattern plan: %d\n", new->plan);
1050
1051
*pattern = *new;
1052
memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
1053
1054
if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc)
1055
aux->ignore_bcn = true;
1056
else
1057
aux->ignore_bcn = false;
1058
1059
if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) {
1060
crtz = &pattern->courtesy.ref;
1061
ref->crtz = crtz;
1062
1063
crtz->macid_tgt = aux->rtwvif_link->mac_id;
1064
crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
1065
1066
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1067
"MCC courtesy ref: tgt %d, slot %d\n",
1068
crtz->macid_tgt, crtz->slot_num);
1069
} else {
1070
ref->crtz = NULL;
1071
}
1072
1073
if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc)
1074
ref->ignore_bcn = true;
1075
else
1076
ref->ignore_bcn = false;
1077
1078
if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) {
1079
crtz = &pattern->courtesy.aux;
1080
aux->crtz = crtz;
1081
1082
crtz->macid_tgt = ref->rtwvif_link->mac_id;
1083
crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
1084
1085
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1086
"MCC courtesy aux: tgt %d, slot %d\n",
1087
crtz->macid_tgt, crtz->slot_num);
1088
} else {
1089
aux->crtz = NULL;
1090
}
1091
}
1092
1093
/* The follow-up roughly shows the relationship between the parameters
1094
* for pattern calculation.
1095
*
1096
* |< duration ref >| (if mid bt) |< duration aux >|
1097
* |< tob ref >|< toa ref >| ... |< tob aux >|< toa aux >|
1098
* V V
1099
* tbtt ref tbtt aux
1100
* |< beacon offset >|
1101
*
1102
* In loose pattern calculation, we only ensure at least tob_ref and
1103
* toa_ref have positive results. If tob_aux or toa_aux is negative
1104
* unfortunately, FW will be notified to handle it with courtesy
1105
* mechanism.
1106
*/
1107
static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
1108
struct rtw89_mcc_pattern *ptrn,
1109
bool hdl_bt)
1110
{
1111
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1112
struct rtw89_mcc_role *ref = &mcc->role_ref;
1113
struct rtw89_mcc_role *aux = &mcc->role_aux;
1114
struct rtw89_mcc_config *config = &mcc->config;
1115
u16 mcc_intvl = config->mcc_interval;
1116
u16 bcn_ofst = config->beacon_offset;
1117
u16 bt_dur_in_mid = 0;
1118
u16 max_bcn_ofst;
1119
s16 upper, lower;
1120
u16 res;
1121
1122
*ptrn = (typeof(*ptrn)){
1123
.plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
1124
};
1125
1126
if (!hdl_bt)
1127
goto calc;
1128
1129
max_bcn_ofst = ref->duration + aux->duration;
1130
if (ref->limit.enable)
1131
max_bcn_ofst = min_t(u16, max_bcn_ofst,
1132
ref->limit.max_toa + aux->duration);
1133
else if (aux->limit.enable)
1134
max_bcn_ofst = min_t(u16, max_bcn_ofst,
1135
ref->duration + aux->limit.max_tob);
1136
1137
if (bcn_ofst > max_bcn_ofst && bcn_ofst >= mcc->bt_role.duration) {
1138
bt_dur_in_mid = mcc->bt_role.duration;
1139
ptrn->plan = RTW89_MCC_PLAN_MID_BT;
1140
}
1141
1142
calc:
1143
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1144
"MCC calc ptrn_ls: plan %d, bcn_ofst %d\n",
1145
ptrn->plan, bcn_ofst);
1146
1147
res = bcn_ofst - bt_dur_in_mid;
1148
upper = min_t(s16, ref->duration, res);
1149
lower = max_t(s16, 0, ref->duration - (mcc_intvl - bcn_ofst));
1150
1151
if (ref->limit.enable) {
1152
upper = min_t(s16, upper, ref->limit.max_toa);
1153
lower = max_t(s16, lower, ref->duration - ref->limit.max_tob);
1154
} else if (aux->limit.enable) {
1155
upper = min_t(s16, upper,
1156
res - (aux->duration - aux->limit.max_toa));
1157
lower = max_t(s16, lower, res - aux->limit.max_tob);
1158
}
1159
1160
if (lower < upper)
1161
ptrn->toa_ref = (upper + lower) / 2;
1162
else
1163
ptrn->toa_ref = lower;
1164
1165
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
1166
ptrn->tob_aux = res - ptrn->toa_ref;
1167
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
1168
}
1169
1170
/* In strict pattern calculation, we consider timing that might need
1171
* for HW stuffs, i.e. min_tob and min_toa.
1172
*/
1173
static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,
1174
struct rtw89_mcc_pattern *ptrn)
1175
{
1176
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1177
struct rtw89_mcc_role *ref = &mcc->role_ref;
1178
struct rtw89_mcc_role *aux = &mcc->role_aux;
1179
struct rtw89_mcc_config *config = &mcc->config;
1180
u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME;
1181
u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME;
1182
u16 bcn_ofst = config->beacon_offset;
1183
s16 upper_toa_ref, lower_toa_ref;
1184
s16 upper_tob_aux, lower_tob_aux;
1185
u16 bt_dur_in_mid;
1186
s16 res;
1187
1188
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1189
"MCC calc ptrn_st: plan %d, bcn_ofst %d\n",
1190
ptrn->plan, bcn_ofst);
1191
1192
if (ptrn->plan == RTW89_MCC_PLAN_MID_BT)
1193
bt_dur_in_mid = mcc->bt_role.duration;
1194
else
1195
bt_dur_in_mid = 0;
1196
1197
if (ref->duration < min_tob + min_toa) {
1198
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1199
"MCC calc ptrn_st: not meet ref dur cond\n");
1200
return -EINVAL;
1201
}
1202
1203
if (aux->duration < min_tob + min_toa) {
1204
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1205
"MCC calc ptrn_st: not meet aux dur cond\n");
1206
return -EINVAL;
1207
}
1208
1209
res = bcn_ofst - min_toa - min_tob - bt_dur_in_mid;
1210
if (res < 0) {
1211
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1212
"MCC calc ptrn_st: not meet bcn_ofst cond\n");
1213
return -EINVAL;
1214
}
1215
1216
upper_toa_ref = min_t(s16, min_toa + res, ref->duration - min_tob);
1217
lower_toa_ref = min_toa;
1218
upper_tob_aux = min_t(s16, min_tob + res, aux->duration - min_toa);
1219
lower_tob_aux = min_tob;
1220
1221
if (ref->limit.enable) {
1222
if (min_tob > ref->limit.max_tob || min_toa > ref->limit.max_toa) {
1223
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1224
"MCC calc ptrn_st: conflict ref limit\n");
1225
return -EINVAL;
1226
}
1227
1228
upper_toa_ref = min_t(s16, upper_toa_ref, ref->limit.max_toa);
1229
lower_toa_ref = max_t(s16, lower_toa_ref,
1230
ref->duration - ref->limit.max_tob);
1231
} else if (aux->limit.enable) {
1232
if (min_tob > aux->limit.max_tob || min_toa > aux->limit.max_toa) {
1233
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1234
"MCC calc ptrn_st: conflict aux limit\n");
1235
return -EINVAL;
1236
}
1237
1238
upper_tob_aux = min_t(s16, upper_tob_aux, aux->limit.max_tob);
1239
lower_tob_aux = max_t(s16, lower_tob_aux,
1240
aux->duration - aux->limit.max_toa);
1241
}
1242
1243
upper_toa_ref = min_t(s16, upper_toa_ref,
1244
bcn_ofst - bt_dur_in_mid - lower_tob_aux);
1245
lower_toa_ref = max_t(s16, lower_toa_ref,
1246
bcn_ofst - bt_dur_in_mid - upper_tob_aux);
1247
if (lower_toa_ref > upper_toa_ref) {
1248
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1249
"MCC calc ptrn_st: conflict boundary\n");
1250
return -EINVAL;
1251
}
1252
1253
ptrn->toa_ref = (upper_toa_ref + lower_toa_ref) / 2;
1254
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
1255
ptrn->tob_aux = bcn_ofst - ptrn->toa_ref - bt_dur_in_mid;
1256
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
1257
return 0;
1258
}
1259
1260
static void __rtw89_mcc_fill_ptrn_anchor_ref(struct rtw89_dev *rtwdev,
1261
struct rtw89_mcc_pattern *ptrn,
1262
bool small_bcn_ofst)
1263
{
1264
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1265
struct rtw89_mcc_role *ref = &mcc->role_ref;
1266
struct rtw89_mcc_role *aux = &mcc->role_aux;
1267
struct rtw89_mcc_config *config = &mcc->config;
1268
u16 bcn_ofst = config->beacon_offset;
1269
u16 ref_tob;
1270
u16 ref_toa;
1271
1272
if (ref->limit.enable) {
1273
ref_tob = ref->limit.max_tob;
1274
ref_toa = ref->limit.max_toa;
1275
} else {
1276
ref_tob = ref->duration / 2;
1277
ref_toa = ref->duration / 2;
1278
}
1279
1280
if (small_bcn_ofst) {
1281
ptrn->toa_ref = ref_toa;
1282
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
1283
} else {
1284
ptrn->tob_ref = ref_tob;
1285
ptrn->toa_ref = ref->duration - ptrn->tob_ref;
1286
}
1287
1288
ptrn->tob_aux = bcn_ofst - ptrn->toa_ref;
1289
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
1290
}
1291
1292
static void __rtw89_mcc_fill_ptrn_anchor_aux(struct rtw89_dev *rtwdev,
1293
struct rtw89_mcc_pattern *ptrn,
1294
bool small_bcn_ofst)
1295
{
1296
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1297
struct rtw89_mcc_role *ref = &mcc->role_ref;
1298
struct rtw89_mcc_role *aux = &mcc->role_aux;
1299
struct rtw89_mcc_config *config = &mcc->config;
1300
u16 bcn_ofst = config->beacon_offset;
1301
u16 aux_tob;
1302
u16 aux_toa;
1303
1304
if (aux->limit.enable) {
1305
aux_tob = aux->limit.max_tob;
1306
aux_toa = aux->limit.max_toa;
1307
} else {
1308
aux_tob = aux->duration / 2;
1309
aux_toa = aux->duration / 2;
1310
}
1311
1312
if (small_bcn_ofst) {
1313
ptrn->tob_aux = aux_tob;
1314
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
1315
} else {
1316
ptrn->toa_aux = aux_toa;
1317
ptrn->tob_aux = aux->duration - ptrn->toa_aux;
1318
}
1319
1320
ptrn->toa_ref = bcn_ofst - ptrn->tob_aux;
1321
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
1322
}
1323
1324
static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev,
1325
struct rtw89_mcc_pattern *ptrn,
1326
bool hdl_bt)
1327
{
1328
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1329
struct rtw89_mcc_role *ref = &mcc->role_ref;
1330
struct rtw89_mcc_role *aux = &mcc->role_aux;
1331
struct rtw89_mcc_config *config = &mcc->config;
1332
u16 mcc_intvl = config->mcc_interval;
1333
u16 bcn_ofst = config->beacon_offset;
1334
bool small_bcn_ofst;
1335
1336
if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME)
1337
small_bcn_ofst = true;
1338
else if (bcn_ofst < aux->duration - aux->limit.max_toa)
1339
small_bcn_ofst = true;
1340
else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME)
1341
small_bcn_ofst = false;
1342
else
1343
return -EPERM;
1344
1345
*ptrn = (typeof(*ptrn)){
1346
.plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
1347
};
1348
1349
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1350
"MCC calc ptrn_ac: plan %d, bcn_ofst %d\n",
1351
ptrn->plan, bcn_ofst);
1352
1353
if (ref->is_go || ref->is_gc)
1354
__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst);
1355
else if (aux->is_go || aux->is_gc)
1356
__rtw89_mcc_fill_ptrn_anchor_aux(rtwdev, ptrn, small_bcn_ofst);
1357
else
1358
__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst);
1359
1360
return 0;
1361
}
1362
1363
static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
1364
{
1365
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1366
struct rtw89_mcc_role *ref = &mcc->role_ref;
1367
struct rtw89_mcc_role *aux = &mcc->role_aux;
1368
bool sel_plan[NUM_OF_RTW89_MCC_PLAN] = {};
1369
struct rtw89_mcc_pattern ptrn;
1370
int ret;
1371
int i;
1372
1373
if (ref->limit.enable && aux->limit.enable) {
1374
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1375
"MCC calc ptrn: not support dual limited roles\n");
1376
return -EINVAL;
1377
}
1378
1379
if (ref->limit.enable &&
1380
ref->duration > ref->limit.max_tob + ref->limit.max_toa) {
1381
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1382
"MCC calc ptrn: not fit ref limit\n");
1383
return -EINVAL;
1384
}
1385
1386
if (aux->limit.enable &&
1387
aux->duration > aux->limit.max_tob + aux->limit.max_toa) {
1388
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1389
"MCC calc ptrn: not fit aux limit\n");
1390
return -EINVAL;
1391
}
1392
1393
if (hdl_bt) {
1394
sel_plan[RTW89_MCC_PLAN_TAIL_BT] = true;
1395
sel_plan[RTW89_MCC_PLAN_MID_BT] = true;
1396
} else {
1397
sel_plan[RTW89_MCC_PLAN_NO_BT] = true;
1398
}
1399
1400
for (i = 0; i < NUM_OF_RTW89_MCC_PLAN; i++) {
1401
if (!sel_plan[i])
1402
continue;
1403
1404
ptrn = (typeof(ptrn)){
1405
.plan = i,
1406
};
1407
1408
ret = __rtw89_mcc_calc_pattern_strict(rtwdev, &ptrn);
1409
if (ret)
1410
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1411
"MCC calc ptrn_st with plan %d: fail\n", i);
1412
else
1413
goto done;
1414
}
1415
1416
ret = __rtw89_mcc_calc_pattern_anchor(rtwdev, &ptrn, hdl_bt);
1417
if (!ret)
1418
goto done;
1419
1420
__rtw89_mcc_calc_pattern_loose(rtwdev, &ptrn, hdl_bt);
1421
1422
done:
1423
rtw89_mcc_assign_pattern(rtwdev, &ptrn);
1424
return 0;
1425
}
1426
1427
static void rtw89_mcc_set_default_pattern(struct rtw89_dev *rtwdev)
1428
{
1429
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1430
struct rtw89_mcc_role *ref = &mcc->role_ref;
1431
struct rtw89_mcc_role *aux = &mcc->role_aux;
1432
struct rtw89_mcc_pattern tmp = {};
1433
1434
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1435
"MCC use default pattern unexpectedly\n");
1436
1437
tmp.plan = RTW89_MCC_PLAN_NO_BT;
1438
tmp.tob_ref = ref->duration / 2;
1439
tmp.toa_ref = ref->duration - tmp.tob_ref;
1440
tmp.tob_aux = aux->duration / 2;
1441
tmp.toa_aux = aux->duration - tmp.tob_aux;
1442
1443
rtw89_mcc_assign_pattern(rtwdev, &tmp);
1444
}
1445
1446
static void rtw89_mcc_set_duration_go_sta(struct rtw89_dev *rtwdev,
1447
struct rtw89_mcc_role *role_go,
1448
struct rtw89_mcc_role *role_sta)
1449
{
1450
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1451
struct rtw89_mcc_config *config = &mcc->config;
1452
u16 mcc_intvl = config->mcc_interval;
1453
u16 dur_go, dur_sta;
1454
1455
dur_go = clamp_t(u16, role_go->duration, RTW89_MCC_MIN_GO_DURATION,
1456
mcc_intvl - RTW89_MCC_MIN_STA_DURATION);
1457
if (role_go->limit.enable)
1458
dur_go = min(dur_go, role_go->limit.max_dur);
1459
dur_sta = mcc_intvl - dur_go;
1460
1461
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1462
"MCC set dur: (go, sta) {%d, %d} -> {%d, %d}\n",
1463
role_go->duration, role_sta->duration, dur_go, dur_sta);
1464
1465
role_go->duration = dur_go;
1466
role_sta->duration = dur_sta;
1467
}
1468
1469
static void rtw89_mcc_set_duration_gc_sta(struct rtw89_dev *rtwdev)
1470
{
1471
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1472
struct rtw89_mcc_role *ref = &mcc->role_ref;
1473
struct rtw89_mcc_role *aux = &mcc->role_aux;
1474
struct rtw89_mcc_config *config = &mcc->config;
1475
u16 mcc_intvl = config->mcc_interval;
1476
u16 dur_ref, dur_aux;
1477
1478
if (ref->duration < RTW89_MCC_MIN_STA_DURATION) {
1479
dur_ref = RTW89_MCC_MIN_STA_DURATION;
1480
dur_aux = mcc_intvl - dur_ref;
1481
} else if (aux->duration < RTW89_MCC_MIN_STA_DURATION) {
1482
dur_aux = RTW89_MCC_MIN_STA_DURATION;
1483
dur_ref = mcc_intvl - dur_aux;
1484
} else {
1485
dur_ref = ref->duration;
1486
dur_aux = mcc_intvl - dur_ref;
1487
}
1488
1489
if (ref->limit.enable) {
1490
dur_ref = min(dur_ref, ref->limit.max_dur);
1491
dur_aux = mcc_intvl - dur_ref;
1492
} else if (aux->limit.enable) {
1493
dur_aux = min(dur_aux, aux->limit.max_dur);
1494
dur_ref = mcc_intvl - dur_aux;
1495
}
1496
1497
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1498
"MCC set dur: (ref, aux) {%d ~ %d} -> {%d ~ %d}\n",
1499
ref->duration, aux->duration, dur_ref, dur_aux);
1500
1501
ref->duration = dur_ref;
1502
aux->duration = dur_aux;
1503
}
1504
1505
struct rtw89_mcc_mod_dur_data {
1506
u16 available;
1507
struct {
1508
u16 dur;
1509
u16 room;
1510
} parm[NUM_OF_RTW89_MCC_ROLES];
1511
};
1512
1513
static int rtw89_mcc_mod_dur_get_iterator(struct rtw89_dev *rtwdev,
1514
struct rtw89_mcc_role *mcc_role,
1515
unsigned int ordered_idx,
1516
void *data)
1517
{
1518
struct rtw89_mcc_mod_dur_data *p = data;
1519
u16 min;
1520
1521
p->parm[ordered_idx].dur = mcc_role->duration;
1522
1523
if (mcc_role->is_go)
1524
min = RTW89_MCC_MIN_GO_DURATION;
1525
else
1526
min = RTW89_MCC_MIN_STA_DURATION;
1527
1528
p->parm[ordered_idx].room = max_t(s32, p->parm[ordered_idx].dur - min, 0);
1529
1530
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1531
"MCC mod dur: chk role[%u]: dur %u, min %u, room %u\n",
1532
ordered_idx, p->parm[ordered_idx].dur, min,
1533
p->parm[ordered_idx].room);
1534
1535
p->available += p->parm[ordered_idx].room;
1536
return 0;
1537
}
1538
1539
static int rtw89_mcc_mod_dur_put_iterator(struct rtw89_dev *rtwdev,
1540
struct rtw89_mcc_role *mcc_role,
1541
unsigned int ordered_idx,
1542
void *data)
1543
{
1544
struct rtw89_mcc_mod_dur_data *p = data;
1545
1546
mcc_role->duration = p->parm[ordered_idx].dur;
1547
1548
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1549
"MCC mod dur: set role[%u]: dur %u\n",
1550
ordered_idx, p->parm[ordered_idx].dur);
1551
return 0;
1552
}
1553
1554
static void rtw89_mcc_mod_duration_dual_2ghz_with_bt(struct rtw89_dev *rtwdev)
1555
{
1556
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1557
struct rtw89_mcc_config *config = &mcc->config;
1558
struct rtw89_mcc_mod_dur_data data = {};
1559
u16 mcc_intvl = config->mcc_interval;
1560
u16 bt_dur = mcc->bt_role.duration;
1561
u16 wifi_dur;
1562
1563
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1564
"MCC mod dur (dual 2ghz): mcc_intvl %u, raw bt_dur %u\n",
1565
mcc_intvl, bt_dur);
1566
1567
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_get_iterator, &data);
1568
1569
bt_dur = clamp_t(u16, bt_dur, 1, data.available / 3);
1570
wifi_dur = mcc_intvl - bt_dur;
1571
1572
if (data.parm[0].room <= data.parm[1].room) {
1573
data.parm[0].dur -= min_t(u16, bt_dur / 2, data.parm[0].room);
1574
data.parm[1].dur = wifi_dur - data.parm[0].dur;
1575
} else {
1576
data.parm[1].dur -= min_t(u16, bt_dur / 2, data.parm[1].room);
1577
data.parm[0].dur = wifi_dur - data.parm[1].dur;
1578
}
1579
1580
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_put_iterator, &data);
1581
1582
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC mod dur: set bt: dur %u\n", bt_dur);
1583
mcc->bt_role.duration = bt_dur;
1584
}
1585
1586
static
1587
void rtw89_mcc_mod_duration_diff_band_with_bt(struct rtw89_dev *rtwdev,
1588
struct rtw89_mcc_role *role_2ghz,
1589
struct rtw89_mcc_role *role_non_2ghz)
1590
{
1591
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1592
struct rtw89_mcc_config *config = &mcc->config;
1593
u16 dur_2ghz, dur_non_2ghz;
1594
u16 bt_dur, mcc_intvl;
1595
1596
dur_2ghz = role_2ghz->duration;
1597
dur_non_2ghz = role_non_2ghz->duration;
1598
mcc_intvl = config->mcc_interval;
1599
bt_dur = mcc->bt_role.duration;
1600
1601
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1602
"MCC mod dur (diff band): mcc_intvl %u, bt_dur %u\n",
1603
mcc_intvl, bt_dur);
1604
1605
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1606
"MCC mod dur: check dur_2ghz %u, dur_non_2ghz %u\n",
1607
dur_2ghz, dur_non_2ghz);
1608
1609
if (dur_non_2ghz >= bt_dur) {
1610
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1611
"MCC mod dur: dur_non_2ghz is enough for bt\n");
1612
return;
1613
}
1614
1615
dur_non_2ghz = bt_dur;
1616
dur_2ghz = mcc_intvl - dur_non_2ghz;
1617
1618
if (role_non_2ghz->limit.enable) {
1619
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1620
"MCC mod dur: dur_non_2ghz is limited with max %u\n",
1621
role_non_2ghz->limit.max_dur);
1622
1623
dur_non_2ghz = min(dur_non_2ghz, role_non_2ghz->limit.max_dur);
1624
dur_2ghz = mcc_intvl - dur_non_2ghz;
1625
}
1626
1627
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1628
"MCC mod dur: set dur_2ghz %u, dur_non_2ghz %u\n",
1629
dur_2ghz, dur_non_2ghz);
1630
1631
role_2ghz->duration = dur_2ghz;
1632
role_non_2ghz->duration = dur_non_2ghz;
1633
}
1634
1635
static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)
1636
{
1637
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1638
struct rtw89_mcc_role *ref = &mcc->role_ref;
1639
struct rtw89_mcc_role *aux = &mcc->role_aux;
1640
struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1641
1642
if (!bt_role->duration)
1643
return false;
1644
1645
if (ref->is_2ghz && aux->is_2ghz) {
1646
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1647
"MCC dual roles are on 2GHz; consider BT duration\n");
1648
1649
rtw89_mcc_mod_duration_dual_2ghz_with_bt(rtwdev);
1650
return true;
1651
}
1652
1653
if (!ref->is_2ghz && !aux->is_2ghz) {
1654
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1655
"MCC dual roles are not on 2GHz; ignore BT duration\n");
1656
return false;
1657
}
1658
1659
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1660
"MCC one role is on 2GHz; modify another for BT duration\n");
1661
1662
if (ref->is_2ghz)
1663
rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, ref, aux);
1664
else
1665
rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, aux, ref);
1666
1667
return false;
1668
}
1669
1670
void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work)
1671
{
1672
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
1673
mcc_prepare_done_work.work);
1674
1675
lockdep_assert_wiphy(wiphy);
1676
1677
ieee80211_wake_queues(rtwdev->hw);
1678
}
1679
1680
static void rtw89_mcc_prepare(struct rtw89_dev *rtwdev, bool start)
1681
{
1682
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1683
struct rtw89_mcc_config *config = &mcc->config;
1684
1685
if (start) {
1686
ieee80211_stop_queues(rtwdev->hw);
1687
1688
wiphy_delayed_work_queue(rtwdev->hw->wiphy,
1689
&rtwdev->mcc_prepare_done_work,
1690
usecs_to_jiffies(config->prepare_delay));
1691
} else {
1692
wiphy_delayed_work_queue(rtwdev->hw->wiphy,
1693
&rtwdev->mcc_prepare_done_work, 0);
1694
wiphy_delayed_work_flush(rtwdev->hw->wiphy,
1695
&rtwdev->mcc_prepare_done_work);
1696
}
1697
}
1698
1699
static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
1700
{
1701
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1702
struct rtw89_mcc_role *ref = &mcc->role_ref;
1703
struct rtw89_mcc_role *aux = &mcc->role_aux;
1704
struct rtw89_mcc_config *config = &mcc->config;
1705
u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
1706
s32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
1707
u64 tsf, start_tsf;
1708
u32 cur_tbtt_ofst;
1709
u64 min_time;
1710
u64 tsf_aux;
1711
int ret;
1712
1713
if (rtw89_concurrent_via_mrc(rtwdev))
1714
ret = __mrc_fw_req_tsf(rtwdev, &tsf, &tsf_aux);
1715
else
1716
ret = __mcc_fw_req_tsf(rtwdev, &tsf, &tsf_aux);
1717
1718
if (ret)
1719
return ret;
1720
1721
min_time = tsf;
1722
if (ref->is_go || aux->is_go)
1723
min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);
1724
else
1725
min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);
1726
1727
cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf);
1728
start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us;
1729
if (start_tsf < min_time)
1730
start_tsf += roundup_u64(min_time - start_tsf, bcn_intvl_ref_us);
1731
1732
config->start_tsf = start_tsf;
1733
config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf;
1734
config->prepare_delay = start_tsf - tsf;
1735
1736
return 0;
1737
}
1738
1739
static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
1740
{
1741
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1742
struct rtw89_mcc_role *ref = &mcc->role_ref;
1743
struct rtw89_mcc_role *aux = &mcc->role_aux;
1744
struct rtw89_mcc_config *config = &mcc->config;
1745
bool hdl_bt;
1746
int ret;
1747
1748
memset(config, 0, sizeof(*config));
1749
1750
switch (mcc->mode) {
1751
case RTW89_MCC_MODE_GO_STA:
1752
config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
1753
if (ref->is_go) {
1754
config->mcc_interval = ref->beacon_interval;
1755
rtw89_mcc_set_duration_go_sta(rtwdev, ref, aux);
1756
} else {
1757
config->mcc_interval = aux->beacon_interval;
1758
rtw89_mcc_set_duration_go_sta(rtwdev, aux, ref);
1759
}
1760
break;
1761
case RTW89_MCC_MODE_GC_STA:
1762
config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
1763
config->mcc_interval = ref->beacon_interval;
1764
rtw89_mcc_set_duration_gc_sta(rtwdev);
1765
break;
1766
default:
1767
rtw89_warn(rtwdev, "MCC unknown mode: %d\n", mcc->mode);
1768
return -EFAULT;
1769
}
1770
1771
hdl_bt = rtw89_mcc_duration_decision_on_bt(rtwdev);
1772
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC handle bt: %d\n", hdl_bt);
1773
1774
ret = rtw89_mcc_calc_pattern(rtwdev, hdl_bt);
1775
if (!ret)
1776
goto bottom;
1777
1778
rtw89_mcc_set_default_pattern(rtwdev);
1779
1780
bottom:
1781
return rtw89_mcc_fill_start_tsf(rtwdev);
1782
}
1783
1784
static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
1785
{
1786
const struct rtw89_mcc_courtesy_cfg *crtz = role->crtz;
1787
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1788
struct rtw89_mcc_policy *policy = &role->policy;
1789
struct rtw89_fw_mcc_add_req req = {};
1790
const struct rtw89_chan *chan;
1791
int ret;
1792
1793
chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
1794
req.central_ch_seg0 = chan->channel;
1795
req.primary_ch = chan->primary_channel;
1796
req.bandwidth = chan->band_width;
1797
req.ch_band_type = chan->band_type;
1798
1799
req.macid = role->rtwvif_link->mac_id;
1800
req.group = mcc->group;
1801
req.c2h_rpt = policy->c2h_rpt;
1802
req.tx_null_early = policy->tx_null_early;
1803
req.dis_tx_null = policy->dis_tx_null;
1804
req.in_curr_ch = policy->in_curr_ch;
1805
req.sw_retry_count = policy->sw_retry_count;
1806
req.dis_sw_retry = policy->dis_sw_retry;
1807
req.duration = role->duration;
1808
req.btc_in_2g = false;
1809
1810
if (crtz) {
1811
req.courtesy_target = crtz->macid_tgt;
1812
req.courtesy_num = crtz->slot_num;
1813
req.courtesy_en = true;
1814
}
1815
1816
ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
1817
if (ret) {
1818
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1819
"MCC h2c failed to add wifi role: %d\n", ret);
1820
return ret;
1821
}
1822
1823
ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
1824
role->rtwvif_link->mac_id,
1825
role->macid_bitmap);
1826
if (ret) {
1827
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1828
"MCC h2c failed to set macid bitmap: %d\n", ret);
1829
return ret;
1830
}
1831
1832
return 0;
1833
}
1834
1835
static
1836
void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
1837
struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
1838
{
1839
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1840
struct rtw89_mcc_role *ref = &mcc->role_ref;
1841
struct rtw89_mcc_policy *policy = &role->policy;
1842
struct rtw89_fw_mrc_add_slot_arg *slot_arg;
1843
const struct rtw89_chan *chan;
1844
1845
slot_arg = &arg->slots[slot_idx];
1846
role->slot_idx = slot_idx;
1847
1848
slot_arg->duration = role->duration;
1849
slot_arg->role_num = 1;
1850
1851
chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
1852
1853
slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
1854
slot_arg->roles[0].is_master = role == ref;
1855
slot_arg->roles[0].band = chan->band_type;
1856
slot_arg->roles[0].bw = chan->band_width;
1857
slot_arg->roles[0].central_ch = chan->channel;
1858
slot_arg->roles[0].primary_ch = chan->primary_channel;
1859
slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
1860
slot_arg->roles[0].null_early = policy->tx_null_early;
1861
slot_arg->roles[0].macid = role->rtwvif_link->mac_id;
1862
slot_arg->roles[0].macid_main_bitmap =
1863
rtw89_mcc_role_fw_macid_bitmap_to_u32(role);
1864
}
1865
1866
static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
1867
{
1868
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1869
struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1870
struct rtw89_fw_mcc_add_req req = {};
1871
int ret;
1872
1873
req.group = mcc->group;
1874
req.duration = bt_role->duration;
1875
req.btc_in_2g = true;
1876
1877
ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
1878
if (ret) {
1879
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1880
"MCC h2c failed to add bt role: %d\n", ret);
1881
return ret;
1882
}
1883
1884
return 0;
1885
}
1886
1887
static
1888
void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev,
1889
struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
1890
{
1891
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1892
struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1893
struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx];
1894
1895
slot_arg->duration = bt_role->duration;
1896
slot_arg->role_num = 1;
1897
1898
slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT;
1899
}
1900
1901
static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
1902
{
1903
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1904
struct rtw89_mcc_role *ref = &mcc->role_ref;
1905
struct rtw89_mcc_role *aux = &mcc->role_aux;
1906
struct rtw89_mcc_config *config = &mcc->config;
1907
struct rtw89_mcc_pattern *pattern = &config->pattern;
1908
struct rtw89_mcc_sync *sync = &config->sync;
1909
struct rtw89_fw_mcc_start_req req = {};
1910
int ret;
1911
1912
if (replace) {
1913
req.old_group = mcc->group;
1914
req.old_group_action = RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE;
1915
mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
1916
}
1917
1918
req.group = mcc->group;
1919
1920
switch (pattern->plan) {
1921
case RTW89_MCC_PLAN_TAIL_BT:
1922
ret = __mcc_fw_add_role(rtwdev, ref);
1923
if (ret)
1924
return ret;
1925
ret = __mcc_fw_add_role(rtwdev, aux);
1926
if (ret)
1927
return ret;
1928
ret = __mcc_fw_add_bt_role(rtwdev);
1929
if (ret)
1930
return ret;
1931
1932
req.btc_in_group = true;
1933
break;
1934
case RTW89_MCC_PLAN_MID_BT:
1935
ret = __mcc_fw_add_role(rtwdev, ref);
1936
if (ret)
1937
return ret;
1938
ret = __mcc_fw_add_bt_role(rtwdev);
1939
if (ret)
1940
return ret;
1941
ret = __mcc_fw_add_role(rtwdev, aux);
1942
if (ret)
1943
return ret;
1944
1945
req.btc_in_group = true;
1946
break;
1947
case RTW89_MCC_PLAN_NO_BT:
1948
ret = __mcc_fw_add_role(rtwdev, ref);
1949
if (ret)
1950
return ret;
1951
ret = __mcc_fw_add_role(rtwdev, aux);
1952
if (ret)
1953
return ret;
1954
1955
req.btc_in_group = false;
1956
break;
1957
default:
1958
rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
1959
return -EFAULT;
1960
}
1961
1962
if (sync->enable) {
1963
ret = rtw89_fw_h2c_mcc_sync(rtwdev, req.group, sync->macid_src,
1964
sync->macid_tgt, sync->offset);
1965
if (ret) {
1966
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1967
"MCC h2c failed to trigger sync: %d\n", ret);
1968
return ret;
1969
}
1970
}
1971
1972
req.macid = ref->rtwvif_link->mac_id;
1973
req.tsf_high = config->start_tsf >> 32;
1974
req.tsf_low = config->start_tsf;
1975
1976
ret = rtw89_fw_h2c_start_mcc(rtwdev, &req);
1977
if (ret) {
1978
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
1979
"MCC h2c failed to trigger start: %d\n", ret);
1980
return ret;
1981
}
1982
1983
return 0;
1984
}
1985
1986
static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
1987
struct rtw89_fw_mrc_add_arg *arg)
1988
{
1989
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1990
struct rtw89_mcc_role *ref = &mcc->role_ref;
1991
struct rtw89_mcc_role *aux = &mcc->role_aux;
1992
struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
1993
1994
if (ref->crtz) {
1995
slot_arg_src = &arg->slots[ref->slot_idx];
1996
1997
slot_arg_src->courtesy_target = aux->slot_idx;
1998
slot_arg_src->courtesy_period = ref->crtz->slot_num;
1999
slot_arg_src->courtesy_en = true;
2000
}
2001
2002
if (aux->crtz) {
2003
slot_arg_src = &arg->slots[aux->slot_idx];
2004
2005
slot_arg_src->courtesy_target = ref->slot_idx;
2006
slot_arg_src->courtesy_period = aux->crtz->slot_num;
2007
slot_arg_src->courtesy_en = true;
2008
}
2009
}
2010
2011
static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
2012
{
2013
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2014
struct rtw89_mcc_role *ref = &mcc->role_ref;
2015
struct rtw89_mcc_role *aux = &mcc->role_aux;
2016
struct rtw89_mcc_config *config = &mcc->config;
2017
struct rtw89_mcc_pattern *pattern = &config->pattern;
2018
struct rtw89_mcc_sync *sync = &config->sync;
2019
struct rtw89_fw_mrc_start_arg start_arg = {};
2020
struct rtw89_fw_mrc_add_arg add_arg = {};
2021
int ret;
2022
2023
BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM <
2024
NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */);
2025
2026
if (replace) {
2027
start_arg.old_sch_idx = mcc->group;
2028
start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD;
2029
mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
2030
}
2031
2032
add_arg.sch_idx = mcc->group;
2033
add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY;
2034
2035
switch (pattern->plan) {
2036
case RTW89_MCC_PLAN_TAIL_BT:
2037
__mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
2038
__mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
2039
__mrc_fw_add_bt_role(rtwdev, &add_arg, 2);
2040
2041
add_arg.slot_num = 3;
2042
add_arg.btc_in_sch = true;
2043
break;
2044
case RTW89_MCC_PLAN_MID_BT:
2045
__mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
2046
__mrc_fw_add_bt_role(rtwdev, &add_arg, 1);
2047
__mrc_fw_add_role(rtwdev, aux, &add_arg, 2);
2048
2049
add_arg.slot_num = 3;
2050
add_arg.btc_in_sch = true;
2051
break;
2052
case RTW89_MCC_PLAN_NO_BT:
2053
__mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
2054
__mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
2055
2056
add_arg.slot_num = 2;
2057
add_arg.btc_in_sch = false;
2058
break;
2059
default:
2060
rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
2061
return -EFAULT;
2062
}
2063
2064
__mrc_fw_add_courtesy(rtwdev, &add_arg);
2065
2066
ret = rtw89_fw_h2c_mrc_add(rtwdev, &add_arg);
2067
if (ret) {
2068
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2069
"MRC h2c failed to trigger add: %d\n", ret);
2070
return ret;
2071
}
2072
2073
if (sync->enable) {
2074
struct rtw89_fw_mrc_sync_arg sync_arg = {
2075
.offset = sync->offset,
2076
.src = {
2077
.band = sync->band_src,
2078
.port = sync->port_src,
2079
},
2080
.dest = {
2081
.band = sync->band_tgt,
2082
.port = sync->port_tgt,
2083
},
2084
};
2085
2086
ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
2087
if (ret) {
2088
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2089
"MRC h2c failed to trigger sync: %d\n", ret);
2090
return ret;
2091
}
2092
}
2093
2094
start_arg.sch_idx = mcc->group;
2095
start_arg.start_tsf = config->start_tsf;
2096
2097
ret = rtw89_fw_h2c_mrc_start(rtwdev, &start_arg);
2098
if (ret) {
2099
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2100
"MRC h2c failed to trigger start: %d\n", ret);
2101
return ret;
2102
}
2103
2104
return 0;
2105
}
2106
2107
static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
2108
{
2109
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2110
struct rtw89_mcc_config *config = &mcc->config;
2111
struct rtw89_mcc_sync *sync = &config->sync;
2112
struct rtw89_mcc_role *ref = &mcc->role_ref;
2113
struct rtw89_mcc_role *aux = &mcc->role_aux;
2114
struct rtw89_fw_mcc_duration req = {
2115
.group = mcc->group,
2116
.btc_in_group = false,
2117
.start_macid = ref->rtwvif_link->mac_id,
2118
.macid_x = ref->rtwvif_link->mac_id,
2119
.macid_y = aux->rtwvif_link->mac_id,
2120
.duration_x = ref->duration,
2121
.duration_y = aux->duration,
2122
.start_tsf_high = config->start_tsf >> 32,
2123
.start_tsf_low = config->start_tsf,
2124
};
2125
int ret;
2126
2127
ret = rtw89_fw_h2c_mcc_set_duration(rtwdev, &req);
2128
if (ret) {
2129
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2130
"MCC h2c failed to set duration: %d\n", ret);
2131
return ret;
2132
}
2133
2134
if (!sync->enable || !sync_changed)
2135
return 0;
2136
2137
ret = rtw89_fw_h2c_mcc_sync(rtwdev, mcc->group, sync->macid_src,
2138
sync->macid_tgt, sync->offset);
2139
if (ret) {
2140
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2141
"MCC h2c failed to trigger sync: %d\n", ret);
2142
return ret;
2143
}
2144
2145
return 0;
2146
}
2147
2148
static int __mrc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
2149
{
2150
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2151
struct rtw89_mcc_config *config = &mcc->config;
2152
struct rtw89_mcc_sync *sync = &config->sync;
2153
struct rtw89_mcc_role *ref = &mcc->role_ref;
2154
struct rtw89_mcc_role *aux = &mcc->role_aux;
2155
struct rtw89_fw_mrc_upd_duration_arg dur_arg = {
2156
.sch_idx = mcc->group,
2157
.start_tsf = config->start_tsf,
2158
.slot_num = 2,
2159
.slots[0] = {
2160
.slot_idx = ref->slot_idx,
2161
.duration = ref->duration,
2162
},
2163
.slots[1] = {
2164
.slot_idx = aux->slot_idx,
2165
.duration = aux->duration,
2166
},
2167
};
2168
struct rtw89_fw_mrc_sync_arg sync_arg = {
2169
.offset = sync->offset,
2170
.src = {
2171
.band = sync->band_src,
2172
.port = sync->port_src,
2173
},
2174
.dest = {
2175
.band = sync->band_tgt,
2176
.port = sync->port_tgt,
2177
},
2178
2179
};
2180
int ret;
2181
2182
ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, &dur_arg);
2183
if (ret) {
2184
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2185
"MRC h2c failed to update duration: %d\n", ret);
2186
return ret;
2187
}
2188
2189
if (!sync->enable || !sync_changed)
2190
return 0;
2191
2192
ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
2193
if (ret) {
2194
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2195
"MRC h2c failed to trigger sync: %d\n", ret);
2196
return ret;
2197
}
2198
2199
return 0;
2200
}
2201
2202
static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
2203
{
2204
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2205
struct rtw89_mcc_role *ref = &mcc->role_ref;
2206
struct rtw89_mcc_role *aux = &mcc->role_aux;
2207
struct rtw89_mcc_config *config = &mcc->config;
2208
struct ieee80211_p2p_noa_desc noa_desc = {};
2209
u32 interval = config->mcc_interval;
2210
struct rtw89_vif_link *rtwvif_go;
2211
u64 start_time;
2212
u32 duration;
2213
2214
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
2215
return;
2216
2217
if (ref->is_go) {
2218
start_time = config->start_tsf;
2219
rtwvif_go = ref->rtwvif_link;
2220
start_time += ieee80211_tu_to_usec(ref->duration);
2221
duration = config->mcc_interval - ref->duration;
2222
} else if (aux->is_go) {
2223
start_time = config->start_tsf_in_aux_domain;
2224
rtwvif_go = aux->rtwvif_link;
2225
duration = config->mcc_interval - aux->duration;
2226
} else {
2227
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2228
"MCC find no GO: skip updating beacon NoA\n");
2229
return;
2230
}
2231
2232
rtw89_p2p_noa_renew(rtwvif_go);
2233
2234
if (enable) {
2235
duration += RTW89_MCC_SWITCH_CH_TIME;
2236
noa_desc.start_time = cpu_to_le32(start_time);
2237
noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval));
2238
noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration));
2239
noa_desc.count = 255;
2240
rtw89_p2p_noa_append(rtwvif_go, &noa_desc);
2241
}
2242
2243
/* without chanctx, we cannot get beacon from mac80211 stack */
2244
if (!rtwvif_go->chanctx_assigned)
2245
return;
2246
2247
rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_go);
2248
}
2249
2250
static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev)
2251
{
2252
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2253
struct rtw89_mcc_role *ref = &mcc->role_ref;
2254
struct rtw89_mcc_role *aux = &mcc->role_aux;
2255
2256
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
2257
return;
2258
2259
if (ref->is_go)
2260
rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, true);
2261
else if (aux->is_go)
2262
rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, true);
2263
2264
rtw89_mcc_handle_beacon_noa(rtwdev, true);
2265
}
2266
2267
static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)
2268
{
2269
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2270
struct rtw89_mcc_role *ref = &mcc->role_ref;
2271
struct rtw89_mcc_role *aux = &mcc->role_aux;
2272
2273
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
2274
return;
2275
2276
if (ref->is_go)
2277
rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, false);
2278
else if (aux->is_go)
2279
rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, false);
2280
2281
rtw89_mcc_handle_beacon_noa(rtwdev, false);
2282
}
2283
2284
static bool rtw89_mcc_ignore_bcn(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
2285
{
2286
enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
2287
2288
if (role->is_go)
2289
return true;
2290
else if (chip_gen == RTW89_CHIP_BE && role->is_gc)
2291
return true;
2292
else
2293
return false;
2294
}
2295
2296
static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
2297
{
2298
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2299
struct rtw89_mcc_role *ref = &mcc->role_ref;
2300
struct rtw89_mcc_role *aux = &mcc->role_aux;
2301
int ret;
2302
2303
if (rtwdev->scanning)
2304
rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
2305
2306
rtw89_leave_lps(rtwdev);
2307
2308
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n");
2309
2310
ret = rtw89_mcc_fill_all_roles(rtwdev);
2311
if (ret)
2312
return ret;
2313
2314
if (ref->is_go || aux->is_go)
2315
mcc->mode = RTW89_MCC_MODE_GO_STA;
2316
else
2317
mcc->mode = RTW89_MCC_MODE_GC_STA;
2318
2319
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode);
2320
2321
mcc->group = RTW89_MCC_DFLT_GROUP;
2322
2323
ret = rtw89_mcc_fill_config(rtwdev);
2324
if (ret)
2325
return ret;
2326
2327
if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) {
2328
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false);
2329
} else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) {
2330
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false);
2331
} else {
2332
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true);
2333
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true);
2334
}
2335
2336
if (rtw89_concurrent_via_mrc(rtwdev))
2337
ret = __mrc_fw_start(rtwdev, false);
2338
else
2339
ret = __mcc_fw_start(rtwdev, false);
2340
2341
if (ret)
2342
return ret;
2343
2344
rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);
2345
2346
rtw89_mcc_start_beacon_noa(rtwdev);
2347
rtw89_phy_dig_suspend(rtwdev);
2348
2349
rtw89_mcc_prepare(rtwdev, true);
2350
return 0;
2351
}
2352
2353
struct rtw89_mcc_stop_sel {
2354
struct {
2355
const struct rtw89_vif_link *target;
2356
} hint;
2357
2358
/* selection content */
2359
bool filled;
2360
u8 mac_id;
2361
u8 slot_idx;
2362
};
2363
2364
static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel,
2365
const struct rtw89_mcc_role *mcc_role)
2366
{
2367
sel->mac_id = mcc_role->rtwvif_link->mac_id;
2368
sel->slot_idx = mcc_role->slot_idx;
2369
sel->filled = true;
2370
}
2371
2372
static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,
2373
struct rtw89_mcc_role *mcc_role,
2374
unsigned int ordered_idx,
2375
void *data)
2376
{
2377
struct rtw89_mcc_stop_sel *sel = data;
2378
2379
if (mcc_role->rtwvif_link == sel->hint.target) {
2380
rtw89_mcc_stop_sel_fill(sel, mcc_role);
2381
return 1; /* break iteration */
2382
}
2383
2384
if (sel->filled)
2385
return 0;
2386
2387
if (!mcc_role->rtwvif_link->chanctx_assigned)
2388
return 0;
2389
2390
rtw89_mcc_stop_sel_fill(sel, mcc_role);
2391
return 0;
2392
}
2393
2394
static void rtw89_mcc_stop(struct rtw89_dev *rtwdev,
2395
const struct rtw89_chanctx_pause_parm *pause)
2396
{
2397
struct rtw89_hal *hal = &rtwdev->hal;
2398
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2399
struct rtw89_mcc_role *ref = &mcc->role_ref;
2400
struct rtw89_mcc_role *aux = &mcc->role_aux;
2401
struct rtw89_mcc_stop_sel sel = {
2402
.hint.target = pause ? pause->trigger : NULL,
2403
};
2404
bool rsn_scan;
2405
int ret;
2406
2407
if (!pause) {
2408
wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->chanctx_work);
2409
bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
2410
}
2411
2412
rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN;
2413
if (rsn_scan && ref->is_go)
2414
sel.hint.target = ref->rtwvif_link;
2415
else if (rsn_scan && aux->is_go)
2416
sel.hint.target = aux->rtwvif_link;
2417
2418
/* by default, stop at ref */
2419
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel);
2420
if (!sel.filled)
2421
rtw89_mcc_stop_sel_fill(&sel, ref);
2422
2423
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop at <macid %d>\n", sel.mac_id);
2424
2425
if (rtw89_concurrent_via_mrc(rtwdev)) {
2426
ret = rtw89_fw_h2c_mrc_del(rtwdev, mcc->group, sel.slot_idx);
2427
if (ret)
2428
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2429
"MRC h2c failed to trigger del: %d\n", ret);
2430
} else {
2431
ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group,
2432
sel.mac_id, true);
2433
if (ret)
2434
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2435
"MCC h2c failed to trigger stop: %d\n", ret);
2436
2437
ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true);
2438
if (ret)
2439
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2440
"MCC h2c failed to delete group: %d\n", ret);
2441
}
2442
2443
rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
2444
2445
rtw89_mcc_stop_beacon_noa(rtwdev);
2446
rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false);
2447
rtw89_phy_dig_resume(rtwdev, true);
2448
2449
rtw89_mcc_prepare(rtwdev, false);
2450
}
2451
2452
static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
2453
{
2454
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2455
bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn;
2456
bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn;
2457
struct rtw89_mcc_config *config = &mcc->config;
2458
struct rtw89_mcc_role *ref = &mcc->role_ref;
2459
struct rtw89_mcc_role *aux = &mcc->role_aux;
2460
struct rtw89_mcc_config old_cfg = *config;
2461
bool courtesy_changed;
2462
bool sync_changed;
2463
int ret;
2464
2465
if (rtwdev->scanning)
2466
rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
2467
2468
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC update\n");
2469
2470
ret = rtw89_mcc_fill_config(rtwdev);
2471
if (ret)
2472
return ret;
2473
2474
if (old_ref_ignore_bcn != ref->ignore_bcn)
2475
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn);
2476
else if (old_aux_ignore_bcn != aux->ignore_bcn)
2477
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn);
2478
2479
if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy,
2480
sizeof(old_cfg.pattern.courtesy)) == 0)
2481
courtesy_changed = false;
2482
else
2483
courtesy_changed = true;
2484
2485
if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
2486
config->pattern.plan != RTW89_MCC_PLAN_NO_BT ||
2487
courtesy_changed) {
2488
if (rtw89_concurrent_via_mrc(rtwdev))
2489
ret = __mrc_fw_start(rtwdev, true);
2490
else
2491
ret = __mcc_fw_start(rtwdev, true);
2492
2493
if (ret)
2494
return ret;
2495
} else {
2496
if (memcmp(&old_cfg.sync, &config->sync, sizeof(old_cfg.sync)) == 0)
2497
sync_changed = false;
2498
else
2499
sync_changed = true;
2500
2501
if (rtw89_concurrent_via_mrc(rtwdev))
2502
ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed);
2503
else
2504
ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
2505
2506
if (ret)
2507
return ret;
2508
}
2509
2510
rtw89_mcc_handle_beacon_noa(rtwdev, true);
2511
return 0;
2512
}
2513
2514
static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev,
2515
struct rtw89_mcc_role *mcc_role,
2516
unsigned int ordered_idx,
2517
void *data)
2518
{
2519
struct rtw89_mcc_role **role = data;
2520
2521
if (mcc_role->is_gc)
2522
*role = mcc_role;
2523
2524
return 0;
2525
}
2526
2527
static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev)
2528
{
2529
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2530
struct rtw89_mcc_role *role = NULL;
2531
2532
if (mcc->mode != RTW89_MCC_MODE_GC_STA)
2533
return NULL;
2534
2535
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role);
2536
2537
return role;
2538
}
2539
2540
void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work)
2541
{
2542
struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link,
2543
mcc_gc_detect_beacon_work.work);
2544
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
2545
enum rtw89_entity_mode mode;
2546
struct rtw89_dev *rtwdev;
2547
2548
lockdep_assert_wiphy(wiphy);
2549
2550
rtwdev = rtwvif_link->rtwvif->rtwdev;
2551
2552
mode = rtw89_get_entity_mode(rtwdev);
2553
if (mode != RTW89_ENTITY_MODE_MCC)
2554
return;
2555
2556
if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf)
2557
rtwvif_link->detect_bcn_count = 0;
2558
else
2559
rtwvif_link->detect_bcn_count++;
2560
2561
if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES)
2562
rtw89_chanctx_proceed(rtwdev, NULL);
2563
else
2564
ieee80211_connection_loss(vif);
2565
}
2566
2567
bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev,
2568
struct rtw89_vif_link *rtwvif_link)
2569
{
2570
enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
2571
struct rtw89_chanctx_pause_parm pause_parm = {
2572
.rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS,
2573
.trigger = rtwvif_link,
2574
};
2575
struct ieee80211_bss_conf *bss_conf;
2576
struct rtw89_mcc_role *role;
2577
u16 bcn_int;
2578
2579
if (mode != RTW89_ENTITY_MODE_MCC)
2580
return false;
2581
2582
role = rtw89_mcc_get_gc_role(rtwdev);
2583
if (!role)
2584
return false;
2585
2586
if (role->rtwvif_link != rtwvif_link)
2587
return false;
2588
2589
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2590
"MCC GC beacon loss, pause MCC to detect GO beacon\n");
2591
2592
rcu_read_lock();
2593
2594
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
2595
bcn_int = bss_conf->beacon_int;
2596
2597
rcu_read_unlock();
2598
2599
rtw89_chanctx_pause(rtwdev, &pause_parm);
2600
rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);
2601
wiphy_delayed_work_queue(rtwdev->hw->wiphy,
2602
&rtwvif_link->mcc_gc_detect_beacon_work,
2603
usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int)));
2604
2605
return true;
2606
}
2607
2608
static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev,
2609
struct rtw89_mcc_role *role)
2610
{
2611
struct ieee80211_vif *vif;
2612
bool start_detect;
2613
int ret;
2614
2615
ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false,
2616
RTW89_MCC_PROBE_TIMEOUT);
2617
if (ret)
2618
role->probe_count++;
2619
else
2620
role->probe_count = 0;
2621
2622
if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES)
2623
return;
2624
2625
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2626
"MCC <macid %d> can not detect AP/GO\n", role->rtwvif_link->mac_id);
2627
2628
start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link);
2629
if (start_detect)
2630
return;
2631
2632
vif = rtwvif_link_to_vif(role->rtwvif_link);
2633
ieee80211_connection_loss(vif);
2634
}
2635
2636
static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
2637
{
2638
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2639
struct rtw89_mcc_config *config = &mcc->config;
2640
struct rtw89_mcc_pattern *pattern = &config->pattern;
2641
struct rtw89_mcc_role *ref = &mcc->role_ref;
2642
struct rtw89_mcc_role *aux = &mcc->role_aux;
2643
u16 tolerance;
2644
u16 bcn_ofst;
2645
u16 diff;
2646
2647
if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn)
2648
rtw89_mcc_detect_connection(rtwdev, aux);
2649
else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn)
2650
rtw89_mcc_detect_connection(rtwdev, ref);
2651
2652
if (mcc->mode != RTW89_MCC_MODE_GC_STA)
2653
return;
2654
2655
bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
2656
if (bcn_ofst == config->beacon_offset)
2657
return;
2658
2659
if (bcn_ofst > config->beacon_offset) {
2660
diff = bcn_ofst - config->beacon_offset;
2661
if (pattern->tob_aux < 0)
2662
tolerance = -pattern->tob_aux;
2663
else if (pattern->toa_aux > 0)
2664
tolerance = pattern->toa_aux;
2665
else
2666
return; /* no chance to improve */
2667
} else {
2668
diff = config->beacon_offset - bcn_ofst;
2669
if (pattern->toa_aux < 0)
2670
tolerance = -pattern->toa_aux;
2671
else if (pattern->tob_aux > 0)
2672
tolerance = pattern->tob_aux;
2673
else
2674
return; /* no chance to improve */
2675
}
2676
2677
if (diff <= tolerance)
2678
return;
2679
2680
rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE);
2681
}
2682
2683
static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
2684
struct rtw89_mcc_role *upd)
2685
{
2686
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2687
int ret;
2688
2689
ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
2690
upd->rtwvif_link->mac_id,
2691
upd->macid_bitmap);
2692
if (ret) {
2693
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2694
"MCC h2c failed to update macid bitmap: %d\n", ret);
2695
return ret;
2696
}
2697
2698
return 0;
2699
}
2700
2701
static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
2702
struct rtw89_mcc_role *cur,
2703
struct rtw89_mcc_role *upd)
2704
{
2705
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2706
struct rtw89_fw_mrc_upd_bitmap_arg arg = {};
2707
u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(cur);
2708
u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(upd);
2709
u32 add = new & ~old;
2710
u32 del = old & ~new;
2711
int ret;
2712
int i;
2713
2714
arg.sch_idx = mcc->group;
2715
arg.macid = upd->rtwvif_link->mac_id;
2716
2717
for (i = 0; i < 32; i++) {
2718
if (add & BIT(i)) {
2719
arg.client_macid = i;
2720
arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD;
2721
2722
ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
2723
if (ret)
2724
goto err;
2725
}
2726
}
2727
2728
for (i = 0; i < 32; i++) {
2729
if (del & BIT(i)) {
2730
arg.client_macid = i;
2731
arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL;
2732
2733
ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
2734
if (ret)
2735
goto err;
2736
}
2737
}
2738
2739
return 0;
2740
2741
err:
2742
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2743
"MRC h2c failed to update bitmap: %d\n", ret);
2744
return ret;
2745
}
2746
2747
static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
2748
struct rtw89_mcc_role *mcc_role,
2749
unsigned int ordered_idx,
2750
void *data)
2751
{
2752
struct rtw89_mcc_role upd = {
2753
.rtwvif_link = mcc_role->rtwvif_link,
2754
};
2755
int ret;
2756
2757
if (!mcc_role->is_go)
2758
return 0;
2759
2760
rtw89_mcc_fill_role_macid_bitmap(rtwdev, &upd);
2761
if (memcmp(mcc_role->macid_bitmap, upd.macid_bitmap,
2762
sizeof(mcc_role->macid_bitmap)) == 0)
2763
return 0;
2764
2765
if (rtw89_concurrent_via_mrc(rtwdev))
2766
ret = __mrc_fw_upd_macid_bitmap(rtwdev, mcc_role, &upd);
2767
else
2768
ret = __mcc_fw_upd_macid_bitmap(rtwdev, &upd);
2769
2770
if (ret)
2771
return ret;
2772
2773
memcpy(mcc_role->macid_bitmap, upd.macid_bitmap,
2774
sizeof(mcc_role->macid_bitmap));
2775
return 0;
2776
}
2777
2778
static void rtw89_mcc_update_macid_bitmap(struct rtw89_dev *rtwdev)
2779
{
2780
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2781
2782
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
2783
return;
2784
2785
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_map_iterator, NULL);
2786
}
2787
2788
static int rtw89_mcc_upd_lmt_iterator(struct rtw89_dev *rtwdev,
2789
struct rtw89_mcc_role *mcc_role,
2790
unsigned int ordered_idx,
2791
void *data)
2792
{
2793
memset(&mcc_role->limit, 0, sizeof(mcc_role->limit));
2794
rtw89_mcc_fill_role_limit(rtwdev, mcc_role);
2795
return 0;
2796
}
2797
2798
static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev)
2799
{
2800
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2801
2802
if (mcc->mode != RTW89_MCC_MODE_GC_STA)
2803
return;
2804
2805
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL);
2806
}
2807
2808
static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev,
2809
struct rtw89_mcc_role *mcc_role,
2810
unsigned int ordered_idx,
2811
void *data)
2812
{
2813
struct rtw89_mcc_links_info *info = data;
2814
2815
info->links[ordered_idx] = mcc_role->rtwvif_link;
2816
return 0;
2817
}
2818
2819
void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info)
2820
{
2821
enum rtw89_entity_mode mode;
2822
2823
memset(info, 0, sizeof(*info));
2824
2825
mode = rtw89_get_entity_mode(rtwdev);
2826
if (unlikely(mode != RTW89_ENTITY_MODE_MCC))
2827
return;
2828
2829
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info);
2830
}
2831
2832
void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work)
2833
{
2834
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
2835
chanctx_work.work);
2836
struct rtw89_hal *hal = &rtwdev->hal;
2837
bool update_mcc_pattern = false;
2838
enum rtw89_entity_mode mode;
2839
u32 changed = 0;
2840
int ret;
2841
int i;
2842
2843
lockdep_assert_wiphy(wiphy);
2844
2845
if (hal->entity_pause)
2846
return;
2847
2848
for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) {
2849
if (test_and_clear_bit(i, hal->changes))
2850
changed |= BIT(i);
2851
}
2852
2853
mode = rtw89_get_entity_mode(rtwdev);
2854
switch (mode) {
2855
case RTW89_ENTITY_MODE_MCC_PREPARE:
2856
rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC);
2857
rtw89_set_channel(rtwdev);
2858
2859
ret = rtw89_mcc_start(rtwdev);
2860
if (ret)
2861
rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
2862
break;
2863
case RTW89_ENTITY_MODE_MCC:
2864
if (changed & BIT(RTW89_CHANCTX_BCN_OFFSET_CHANGE) ||
2865
changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE) ||
2866
changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE) ||
2867
changed & BIT(RTW89_CHANCTX_TSF32_TOGGLE_CHANGE))
2868
update_mcc_pattern = true;
2869
if (changed & BIT(RTW89_CHANCTX_REMOTE_STA_CHANGE))
2870
rtw89_mcc_update_macid_bitmap(rtwdev);
2871
if (changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE))
2872
rtw89_mcc_update_limit(rtwdev);
2873
if (changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE))
2874
rtw89_mcc_fill_bt_role(rtwdev);
2875
if (update_mcc_pattern) {
2876
ret = rtw89_mcc_update(rtwdev);
2877
if (ret)
2878
rtw89_warn(rtwdev, "failed to update MCC: %d\n",
2879
ret);
2880
}
2881
break;
2882
default:
2883
break;
2884
}
2885
}
2886
2887
void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
2888
enum rtw89_chanctx_changes change)
2889
{
2890
struct rtw89_hal *hal = &rtwdev->hal;
2891
enum rtw89_entity_mode mode;
2892
u32 delay;
2893
2894
mode = rtw89_get_entity_mode(rtwdev);
2895
switch (mode) {
2896
default:
2897
return;
2898
case RTW89_ENTITY_MODE_MCC_PREPARE:
2899
delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
2900
rtw89_phy_dig_suspend(rtwdev);
2901
break;
2902
case RTW89_ENTITY_MODE_MCC:
2903
delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC);
2904
break;
2905
}
2906
2907
if (change != RTW89_CHANCTX_CHANGE_DFLT) {
2908
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "set chanctx change %d\n",
2909
change);
2910
set_bit(change, hal->changes);
2911
}
2912
2913
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2914
"queue chanctx work for mode %d with delay %d us\n",
2915
mode, delay);
2916
wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->chanctx_work,
2917
usecs_to_jiffies(delay));
2918
}
2919
2920
void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
2921
{
2922
rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT);
2923
}
2924
2925
static enum rtw89_mr_wtype __rtw89_query_mr_wtype(struct rtw89_dev *rtwdev)
2926
{
2927
struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
2928
enum rtw89_chanctx_idx chanctx_idx;
2929
struct ieee80211_vif *vif;
2930
struct rtw89_vif *rtwvif;
2931
unsigned int num_mld = 0;
2932
unsigned int num_ml = 0;
2933
unsigned int cnt = 0;
2934
u8 role_idx;
2935
u8 idx;
2936
2937
for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) {
2938
rtwvif = mgnt->active_roles[role_idx];
2939
if (!rtwvif)
2940
continue;
2941
2942
cnt++;
2943
2944
vif = rtwvif_to_vif(rtwvif);
2945
if (!ieee80211_vif_is_mld(vif))
2946
continue;
2947
2948
num_mld++;
2949
2950
for (idx = 0; idx < __RTW89_MLD_MAX_LINK_NUM; idx++) {
2951
chanctx_idx = mgnt->chanctx_tbl[role_idx][idx];
2952
if (chanctx_idx != RTW89_CHANCTX_IDLE)
2953
num_ml++;
2954
}
2955
}
2956
2957
if (num_mld > 1)
2958
goto err;
2959
2960
switch (cnt) {
2961
case 0:
2962
return RTW89_MR_WTYPE_NONE;
2963
case 1:
2964
if (!num_mld)
2965
return RTW89_MR_WTYPE_NONMLD;
2966
switch (num_ml) {
2967
case 1:
2968
return RTW89_MR_WTYPE_MLD1L1R;
2969
case 2:
2970
return RTW89_MR_WTYPE_MLD2L1R;
2971
default:
2972
break;
2973
}
2974
break;
2975
case 2:
2976
if (!num_mld)
2977
return RTW89_MR_WTYPE_NONMLD_NONMLD;
2978
switch (num_ml) {
2979
case 1:
2980
return RTW89_MR_WTYPE_MLD1L1R_NONMLD;
2981
case 2:
2982
return RTW89_MR_WTYPE_MLD2L1R_NONMLD;
2983
default:
2984
break;
2985
}
2986
break;
2987
default:
2988
break;
2989
}
2990
2991
err:
2992
rtw89_warn(rtwdev, "%s: unhandled cnt %u mld %u ml %u\n", __func__,
2993
cnt, num_mld, num_ml);
2994
return RTW89_MR_WTYPE_UNKNOWN;
2995
}
2996
2997
static enum rtw89_mr_wmode __rtw89_query_mr_wmode(struct rtw89_dev *rtwdev,
2998
u8 inst_idx)
2999
{
3000
struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
3001
unsigned int num[NUM_NL80211_IFTYPES] = {};
3002
enum rtw89_chanctx_idx chanctx_idx;
3003
struct ieee80211_vif *vif;
3004
struct rtw89_vif *rtwvif;
3005
unsigned int cnt = 0;
3006
u8 role_idx;
3007
3008
if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM))
3009
return RTW89_MR_WMODE_UNKNOWN;
3010
3011
for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) {
3012
chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx];
3013
if (chanctx_idx == RTW89_CHANCTX_IDLE)
3014
continue;
3015
3016
rtwvif = mgnt->active_roles[role_idx];
3017
if (unlikely(!rtwvif))
3018
continue;
3019
3020
vif = rtwvif_to_vif(rtwvif);
3021
num[vif->type]++;
3022
cnt++;
3023
}
3024
3025
switch (cnt) {
3026
case 0:
3027
return RTW89_MR_WMODE_NONE;
3028
case 1:
3029
if (num[NL80211_IFTYPE_STATION])
3030
return RTW89_MR_WMODE_1CLIENT;
3031
if (num[NL80211_IFTYPE_AP])
3032
return RTW89_MR_WMODE_1AP;
3033
break;
3034
case 2:
3035
if (num[NL80211_IFTYPE_STATION] == 2)
3036
return RTW89_MR_WMODE_2CLIENTS;
3037
if (num[NL80211_IFTYPE_AP] == 2)
3038
return RTW89_MR_WMODE_2APS;
3039
if (num[NL80211_IFTYPE_STATION] && num[NL80211_IFTYPE_AP])
3040
return RTW89_MR_WMODE_1AP_1CLIENT;
3041
break;
3042
default:
3043
break;
3044
}
3045
3046
rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt);
3047
return RTW89_MR_WMODE_UNKNOWN;
3048
}
3049
3050
static enum rtw89_mr_ctxtype __rtw89_query_mr_ctxtype(struct rtw89_dev *rtwdev,
3051
u8 inst_idx)
3052
{
3053
struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
3054
DECLARE_BITMAP(map, NUM_OF_RTW89_CHANCTX) = {};
3055
unsigned int num[RTW89_BAND_NUM] = {};
3056
enum rtw89_chanctx_idx chanctx_idx;
3057
const struct rtw89_chan *chan;
3058
unsigned int cnt = 0;
3059
u8 role_idx;
3060
3061
if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM))
3062
return RTW89_MR_CTX_UNKNOWN;
3063
3064
for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) {
3065
chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx];
3066
if (chanctx_idx == RTW89_CHANCTX_IDLE)
3067
continue;
3068
3069
if (__test_and_set_bit(chanctx_idx, map))
3070
continue;
3071
3072
chan = rtw89_chan_get(rtwdev, chanctx_idx);
3073
num[chan->band_type]++;
3074
cnt++;
3075
}
3076
3077
switch (cnt) {
3078
case 0:
3079
return RTW89_MR_CTX_NONE;
3080
case 1:
3081
if (num[RTW89_BAND_2G])
3082
return RTW89_MR_CTX1_2GHZ;
3083
if (num[RTW89_BAND_5G])
3084
return RTW89_MR_CTX1_5GHZ;
3085
if (num[RTW89_BAND_6G])
3086
return RTW89_MR_CTX1_6GHZ;
3087
break;
3088
case 2:
3089
if (num[RTW89_BAND_2G] == 2)
3090
return RTW89_MR_CTX2_2GHZ;
3091
if (num[RTW89_BAND_5G] == 2)
3092
return RTW89_MR_CTX2_5GHZ;
3093
if (num[RTW89_BAND_6G] == 2)
3094
return RTW89_MR_CTX2_6GHZ;
3095
if (num[RTW89_BAND_2G] && num[RTW89_BAND_5G])
3096
return RTW89_MR_CTX2_2GHZ_5GHZ;
3097
if (num[RTW89_BAND_2G] && num[RTW89_BAND_6G])
3098
return RTW89_MR_CTX2_2GHZ_6GHZ;
3099
if (num[RTW89_BAND_5G] && num[RTW89_BAND_6G])
3100
return RTW89_MR_CTX2_5GHZ_6GHZ;
3101
break;
3102
default:
3103
break;
3104
}
3105
3106
rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt);
3107
return RTW89_MR_CTX_UNKNOWN;
3108
}
3109
3110
void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx,
3111
struct rtw89_mr_chanctx_info *info)
3112
{
3113
lockdep_assert_wiphy(rtwdev->hw->wiphy);
3114
3115
info->wtype = __rtw89_query_mr_wtype(rtwdev);
3116
info->wmode = __rtw89_query_mr_wmode(rtwdev, inst_idx);
3117
info->ctxtype = __rtw89_query_mr_ctxtype(rtwdev, inst_idx);
3118
}
3119
3120
void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
3121
{
3122
struct rtw89_hal *hal = &rtwdev->hal;
3123
enum rtw89_entity_mode mode;
3124
3125
lockdep_assert_wiphy(rtwdev->hw->wiphy);
3126
3127
if (hal->entity_pause)
3128
return;
3129
3130
mode = rtw89_get_entity_mode(rtwdev);
3131
switch (mode) {
3132
case RTW89_ENTITY_MODE_MCC:
3133
rtw89_mcc_track(rtwdev);
3134
break;
3135
default:
3136
break;
3137
}
3138
}
3139
3140
void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
3141
const struct rtw89_chanctx_pause_parm *pause_parm)
3142
{
3143
struct rtw89_hal *hal = &rtwdev->hal;
3144
enum rtw89_entity_mode mode;
3145
3146
lockdep_assert_wiphy(rtwdev->hw->wiphy);
3147
3148
if (hal->entity_pause)
3149
return;
3150
3151
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", pause_parm->rsn);
3152
3153
mode = rtw89_get_entity_mode(rtwdev);
3154
switch (mode) {
3155
case RTW89_ENTITY_MODE_MCC:
3156
rtw89_mcc_stop(rtwdev, pause_parm);
3157
break;
3158
default:
3159
break;
3160
}
3161
3162
hal->entity_pause = true;
3163
}
3164
3165
static void rtw89_chanctx_proceed_cb(struct rtw89_dev *rtwdev,
3166
const struct rtw89_chanctx_cb_parm *parm)
3167
{
3168
int ret;
3169
3170
if (!parm || !parm->cb)
3171
return;
3172
3173
ret = parm->cb(rtwdev, parm->data);
3174
if (ret)
3175
rtw89_warn(rtwdev, "%s (%s): cb failed: %d\n", __func__,
3176
parm->caller ?: "unknown", ret);
3177
}
3178
3179
/* pass @cb_parm if there is a @cb_parm->cb which needs to invoke right after
3180
* call rtw89_set_channel() and right before proceed entity according to mode.
3181
*/
3182
void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev,
3183
const struct rtw89_chanctx_cb_parm *cb_parm)
3184
{
3185
struct rtw89_hal *hal = &rtwdev->hal;
3186
enum rtw89_entity_mode mode;
3187
int ret;
3188
3189
lockdep_assert_wiphy(rtwdev->hw->wiphy);
3190
3191
if (unlikely(!hal->entity_pause)) {
3192
rtw89_chanctx_proceed_cb(rtwdev, cb_parm);
3193
return;
3194
}
3195
3196
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx proceed\n");
3197
3198
hal->entity_pause = false;
3199
rtw89_set_channel(rtwdev);
3200
3201
rtw89_chanctx_proceed_cb(rtwdev, cb_parm);
3202
3203
mode = rtw89_get_entity_mode(rtwdev);
3204
switch (mode) {
3205
case RTW89_ENTITY_MODE_MCC:
3206
ret = rtw89_mcc_start(rtwdev);
3207
if (ret)
3208
rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
3209
break;
3210
default:
3211
break;
3212
}
3213
3214
rtw89_queue_chanctx_work(rtwdev);
3215
}
3216
3217
static void __rtw89_swap_chanctx(struct rtw89_vif *rtwvif,
3218
enum rtw89_chanctx_idx idx1,
3219
enum rtw89_chanctx_idx idx2)
3220
{
3221
struct rtw89_vif_link *rtwvif_link;
3222
unsigned int link_id;
3223
3224
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
3225
if (!rtwvif_link->chanctx_assigned)
3226
continue;
3227
3228
if (rtwvif_link->chanctx_idx == idx1)
3229
rtwvif_link->chanctx_idx = idx2;
3230
else if (rtwvif_link->chanctx_idx == idx2)
3231
rtwvif_link->chanctx_idx = idx1;
3232
}
3233
}
3234
3235
static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
3236
enum rtw89_chanctx_idx idx1,
3237
enum rtw89_chanctx_idx idx2)
3238
{
3239
struct rtw89_hal *hal = &rtwdev->hal;
3240
struct rtw89_vif *rtwvif;
3241
u8 cur;
3242
3243
if (idx1 == idx2)
3244
return;
3245
3246
#if defined(__FreeBSD__)
3247
/*
3248
* __rtw89_config_entity_chandef() might set RTW89_CHANCTX_0 but no
3249
* cfg assigned.
3250
* A mac80211 (*config)() with IEEE80211_CONF_CHANGE_CHANNEL could do
3251
* that if rtw89_config_default_chandef() from rtw89_entity_init() does
3252
* not already.
3253
* A mac80211: (*assign_vif_chanctx)() following will find idx 0 filled
3254
* and rtw89_chanctx_ops_add() will call here. Trying to swap results
3255
* in a NULL pointer deref as hal->chanctx[idx1].cfg is NULL.
3256
* Catch this for now until fully understood or a proper solution is
3257
* found.
3258
*/
3259
if (hal->chanctx[idx1].cfg == NULL || hal->chanctx[idx2].cfg == NULL) {
3260
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
3261
"%s: !swapping idx1 %d cfg %p, idx2 %d cfg %p\n", __func__,
3262
idx1, hal->chanctx[idx1].cfg, idx2, hal->chanctx[idx2].cfg);
3263
return;
3264
}
3265
#endif
3266
3267
hal->chanctx[idx1].cfg->idx = idx2;
3268
hal->chanctx[idx2].cfg->idx = idx1;
3269
3270
swap(hal->chanctx[idx1], hal->chanctx[idx2]);
3271
3272
rtw89_for_each_rtwvif(rtwdev, rtwvif)
3273
__rtw89_swap_chanctx(rtwvif, idx1, idx2);
3274
3275
cur = atomic_read(&hal->roc_chanctx_idx);
3276
if (cur == idx1)
3277
atomic_set(&hal->roc_chanctx_idx, idx2);
3278
else if (cur == idx2)
3279
atomic_set(&hal->roc_chanctx_idx, idx1);
3280
}
3281
3282
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
3283
struct ieee80211_chanctx_conf *ctx)
3284
{
3285
struct rtw89_hal *hal = &rtwdev->hal;
3286
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
3287
const struct rtw89_chip_info *chip = rtwdev->chip;
3288
u8 idx;
3289
3290
idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_CHANCTX);
3291
if (idx >= chip->support_chanctx_num)
3292
return -ENOENT;
3293
3294
rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
3295
cfg->idx = idx;
3296
cfg->ref_count = 0;
3297
hal->chanctx[idx].cfg = cfg;
3298
return 0;
3299
}
3300
3301
void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
3302
struct ieee80211_chanctx_conf *ctx)
3303
{
3304
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
3305
3306
rtw89_config_entity_chandef(rtwdev, cfg->idx, NULL);
3307
}
3308
3309
void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
3310
struct ieee80211_chanctx_conf *ctx,
3311
u32 changed)
3312
{
3313
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
3314
u8 idx = cfg->idx;
3315
3316
if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
3317
rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
3318
rtw89_set_channel(rtwdev);
3319
}
3320
3321
if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING)
3322
rtw89_chan_update_punctured(rtwdev, idx, &ctx->def);
3323
}
3324
3325
int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
3326
struct rtw89_vif_link *rtwvif_link,
3327
struct ieee80211_chanctx_conf *ctx)
3328
{
3329
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
3330
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
3331
struct rtw89_hal *hal = &rtwdev->hal;
3332
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
3333
struct rtw89_entity_weight w = {};
3334
int ret;
3335
3336
rtwvif_link->chanctx_idx = cfg->idx;
3337
rtwvif_link->chanctx_assigned = true;
3338
cfg->ref_count++;
3339
3340
if (rtwdev->scanning)
3341
rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
3342
3343
if (list_empty(&rtwvif->mgnt_entry))
3344
list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list);
3345
3346
if (cfg->idx == RTW89_CHANCTX_0)
3347
goto out;
3348
3349
rtw89_entity_calculate_weight(rtwdev, &w);
3350
if (w.active_chanctxs != 1)
3351
goto out;
3352
3353
/* put the first active chanctx at RTW89_CHANCTX_0 */
3354
rtw89_swap_chanctx(rtwdev, cfg->idx, RTW89_CHANCTX_0);
3355
3356
out:
3357
ret = rtw89_set_channel(rtwdev);
3358
if (ret)
3359
return ret;
3360
3361
rtw89_tas_reset(rtwdev, true);
3362
3363
return 0;
3364
}
3365
3366
void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
3367
struct rtw89_vif_link *rtwvif_link,
3368
struct ieee80211_chanctx_conf *ctx)
3369
{
3370
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
3371
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
3372
struct rtw89_hal *hal = &rtwdev->hal;
3373
enum rtw89_chanctx_idx roll;
3374
enum rtw89_entity_mode cur;
3375
enum rtw89_entity_mode new;
3376
int ret;
3377
3378
rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;
3379
rtwvif_link->chanctx_assigned = false;
3380
cfg->ref_count--;
3381
3382
if (rtwdev->scanning)
3383
rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
3384
3385
if (!rtw89_vif_is_active_role(rtwvif))
3386
list_del_init(&rtwvif->mgnt_entry);
3387
3388
if (cfg->ref_count != 0)
3389
goto out;
3390
3391
if (cfg->idx != RTW89_CHANCTX_0)
3392
goto out;
3393
3394
roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_CHANCTX,
3395
cfg->idx + 1);
3396
/* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
3397
if (roll == NUM_OF_RTW89_CHANCTX)
3398
goto out;
3399
3400
/* RTW89_CHANCTX_0 is going to release, and another exists.
3401
* Make another roll down to RTW89_CHANCTX_0 to replace.
3402
*/
3403
rtw89_swap_chanctx(rtwdev, cfg->idx, roll);
3404
3405
out:
3406
if (!hal->entity_pause) {
3407
cur = rtw89_get_entity_mode(rtwdev);
3408
switch (cur) {
3409
case RTW89_ENTITY_MODE_MCC:
3410
rtw89_mcc_stop(rtwdev, NULL);
3411
break;
3412
default:
3413
break;
3414
}
3415
}
3416
3417
ret = rtw89_set_channel(rtwdev);
3418
if (ret)
3419
return;
3420
3421
if (hal->entity_pause)
3422
return;
3423
3424
new = rtw89_get_entity_mode(rtwdev);
3425
switch (new) {
3426
case RTW89_ENTITY_MODE_MCC:
3427
/* re-plan MCC for chanctx changes. */
3428
ret = rtw89_mcc_start(rtwdev);
3429
if (ret)
3430
rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
3431
break;
3432
default:
3433
break;
3434
}
3435
}
3436
3437
int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev,
3438
struct rtw89_vif_link *rtwvif_link,
3439
struct ieee80211_chanctx_conf *old_ctx,
3440
struct ieee80211_chanctx_conf *new_ctx,
3441
bool replace)
3442
{
3443
int ret;
3444
3445
rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx);
3446
3447
if (!replace)
3448
goto assign;
3449
3450
rtw89_chanctx_ops_remove(rtwdev, old_ctx);
3451
ret = rtw89_chanctx_ops_add(rtwdev, new_ctx);
3452
if (ret) {
3453
rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n",
3454
__func__, ret);
3455
return ret;
3456
}
3457
3458
assign:
3459
ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx);
3460
if (ret) {
3461
rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n",
3462
__func__, ret);
3463
return ret;
3464
}
3465
3466
_rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def);
3467
3468
return 0;
3469
}
3470
3471