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 "ps.h"
11#include "util.h"
12
13static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
14 u8 center_chan)
15{
16 switch (band) {
17 default:
18 case RTW89_BAND_2G:
19 switch (center_chan) {
20 default:
21 case 1 ... 14:
22 return RTW89_CH_2G;
23 }
24 case RTW89_BAND_5G:
25 switch (center_chan) {
26 default:
27 case 36 ... 64:
28 return RTW89_CH_5G_BAND_1;
29 case 100 ... 144:
30 return RTW89_CH_5G_BAND_3;
31 case 149 ... 177:
32 return RTW89_CH_5G_BAND_4;
33 }
34 case RTW89_BAND_6G:
35 switch (center_chan) {
36 default:
37 case 1 ... 29:
38 return RTW89_CH_6G_BAND_IDX0;
39 case 33 ... 61:
40 return RTW89_CH_6G_BAND_IDX1;
41 case 65 ... 93:
42 return RTW89_CH_6G_BAND_IDX2;
43 case 97 ... 125:
44 return RTW89_CH_6G_BAND_IDX3;
45 case 129 ... 157:
46 return RTW89_CH_6G_BAND_IDX4;
47 case 161 ... 189:
48 return RTW89_CH_6G_BAND_IDX5;
49 case 193 ... 221:
50 return RTW89_CH_6G_BAND_IDX6;
51 case 225 ... 253:
52 return RTW89_CH_6G_BAND_IDX7;
53 }
54 }
55}
56
57static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
58 u32 center_freq,
59 u32 primary_freq)
60{
61 u8 primary_chan_idx;
62 u32 offset;
63
64 switch (bw) {
65 default:
66 case RTW89_CHANNEL_WIDTH_20:
67 primary_chan_idx = RTW89_SC_DONT_CARE;
68 break;
69 case RTW89_CHANNEL_WIDTH_40:
70 if (primary_freq > center_freq)
71 primary_chan_idx = RTW89_SC_20_UPPER;
72 else
73 primary_chan_idx = RTW89_SC_20_LOWER;
74 break;
75 case RTW89_CHANNEL_WIDTH_80:
76 case RTW89_CHANNEL_WIDTH_160:
77 if (primary_freq > center_freq) {
78 offset = (primary_freq - center_freq - 10) / 20;
79 primary_chan_idx = RTW89_SC_20_UPPER + offset * 2;
80 } else {
81 offset = (center_freq - primary_freq - 10) / 20;
82 primary_chan_idx = RTW89_SC_20_LOWER + offset * 2;
83 }
84 break;
85 }
86
87 return primary_chan_idx;
88}
89
90static u8 rtw89_get_primary_sb_idx(u8 central_ch, u8 pri_ch,
91 enum rtw89_bandwidth bw)
92{
93 static const u8 prisb_cal_ofst[RTW89_CHANNEL_WIDTH_ORDINARY_NUM] = {
94 0, 2, 6, 14, 30
95 };
96
97 if (bw >= RTW89_CHANNEL_WIDTH_ORDINARY_NUM)
98 return 0;
99
100 return (prisb_cal_ofst[bw] + pri_ch - central_ch) / 4;
101}
102
103void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
104 enum rtw89_band band, enum rtw89_bandwidth bandwidth)
105{
106 enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(hw_band: band);
107 u32 center_freq, primary_freq;
108
109 memset(chan, 0, sizeof(*chan));
110 chan->channel = center_chan;
111 chan->primary_channel = primary_chan;
112 chan->band_type = band;
113 chan->band_width = bandwidth;
114
115 center_freq = ieee80211_channel_to_frequency(chan: center_chan, band: nl_band);
116 primary_freq = ieee80211_channel_to_frequency(chan: primary_chan, band: nl_band);
117
118 chan->freq = center_freq;
119 chan->subband_type = rtw89_get_subband_type(band, center_chan);
120 chan->pri_ch_idx = rtw89_get_primary_chan_idx(bw: bandwidth, center_freq,
121 primary_freq);
122 chan->pri_sb_idx = rtw89_get_primary_sb_idx(central_ch: center_chan, pri_ch: primary_chan,
123 bw: bandwidth);
124}
125
126bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
127 enum rtw89_sub_entity_idx idx,
128 const struct rtw89_chan *new)
129{
130 struct rtw89_hal *hal = &rtwdev->hal;
131 struct rtw89_chan *chan = &hal->sub[idx].chan;
132 struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd;
133 bool band_changed;
134
135 rcd->prev_primary_channel = chan->primary_channel;
136 rcd->prev_band_type = chan->band_type;
137 band_changed = new->band_type != chan->band_type;
138 rcd->band_changed = band_changed;
139
140 *chan = *new;
141 return band_changed;
142}
143
144static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
145 enum rtw89_sub_entity_idx idx,
146 const struct cfg80211_chan_def *chandef,
147 bool from_stack)
148{
149 struct rtw89_hal *hal = &rtwdev->hal;
150
151 hal->sub[idx].chandef = *chandef;
152
153 if (from_stack)
154 set_bit(nr: idx, addr: hal->entity_map);
155}
156
157void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
158 enum rtw89_sub_entity_idx idx,
159 const struct cfg80211_chan_def *chandef)
160{
161 __rtw89_config_entity_chandef(rtwdev, idx, chandef, from_stack: true);
162}
163
164void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
165 enum rtw89_sub_entity_idx idx,
166 const struct cfg80211_chan_def *chandef)
167{
168 struct rtw89_hal *hal = &rtwdev->hal;
169 enum rtw89_sub_entity_idx cur;
170
171 if (chandef) {
172 cur = atomic_cmpxchg(v: &hal->roc_entity_idx,
173 old: RTW89_SUB_ENTITY_IDLE, new: idx);
174 if (cur != RTW89_SUB_ENTITY_IDLE) {
175 rtw89_debug(rtwdev, mask: RTW89_DBG_TXRX,
176 fmt: "ROC still processing on entity %d\n", idx);
177 return;
178 }
179
180 hal->roc_chandef = *chandef;
181 } else {
182 cur = atomic_cmpxchg(v: &hal->roc_entity_idx, old: idx,
183 new: RTW89_SUB_ENTITY_IDLE);
184 if (cur == idx)
185 return;
186
187 if (cur == RTW89_SUB_ENTITY_IDLE)
188 rtw89_debug(rtwdev, mask: RTW89_DBG_TXRX,
189 fmt: "ROC already finished on entity %d\n", idx);
190 else
191 rtw89_debug(rtwdev, mask: RTW89_DBG_TXRX,
192 fmt: "ROC is processing on entity %d\n", cur);
193 }
194}
195
196static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
197{
198 struct cfg80211_chan_def chandef = {0};
199
200 rtw89_get_default_chandef(chandef: &chandef);
201 __rtw89_config_entity_chandef(rtwdev, idx: RTW89_SUB_ENTITY_0, chandef: &chandef, from_stack: false);
202}
203
204void rtw89_entity_init(struct rtw89_dev *rtwdev)
205{
206 struct rtw89_hal *hal = &rtwdev->hal;
207
208 hal->entity_pause = false;
209 bitmap_zero(dst: hal->entity_map, nbits: NUM_OF_RTW89_SUB_ENTITY);
210 bitmap_zero(dst: hal->changes, nbits: NUM_OF_RTW89_CHANCTX_CHANGES);
211 atomic_set(v: &hal->roc_entity_idx, i: RTW89_SUB_ENTITY_IDLE);
212 rtw89_config_default_chandef(rtwdev);
213}
214
215static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
216 struct rtw89_entity_weight *w)
217{
218 struct rtw89_hal *hal = &rtwdev->hal;
219 const struct rtw89_chanctx_cfg *cfg;
220 struct rtw89_vif *rtwvif;
221 int idx;
222
223 for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY) {
224 cfg = hal->sub[idx].cfg;
225 if (!cfg) {
226 /* doesn't run with chanctx ops; one channel at most */
227 w->active_chanctxs = 1;
228 break;
229 }
230
231 if (cfg->ref_count > 0)
232 w->active_chanctxs++;
233 }
234
235 rtw89_for_each_rtwvif(rtwdev, rtwvif) {
236 if (rtwvif->chanctx_assigned)
237 w->active_roles++;
238 }
239}
240
241enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
242{
243 DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_SUB_ENTITY) = {};
244 struct rtw89_hal *hal = &rtwdev->hal;
245 const struct cfg80211_chan_def *chandef;
246 struct rtw89_entity_weight w = {};
247 enum rtw89_entity_mode mode;
248 struct rtw89_chan chan;
249 u8 idx;
250
251 lockdep_assert_held(&rtwdev->mutex);
252
253 bitmap_copy(dst: recalc_map, src: hal->entity_map, nbits: NUM_OF_RTW89_SUB_ENTITY);
254
255 rtw89_entity_calculate_weight(rtwdev, w: &w);
256 switch (w.active_chanctxs) {
257 default:
258 rtw89_warn(rtwdev, "unknown ent chanctxs weight: %d\n",
259 w.active_chanctxs);
260 bitmap_zero(dst: recalc_map, nbits: NUM_OF_RTW89_SUB_ENTITY);
261 fallthrough;
262 case 0:
263 rtw89_config_default_chandef(rtwdev);
264 set_bit(nr: RTW89_SUB_ENTITY_0, addr: recalc_map);
265 fallthrough;
266 case 1:
267 mode = RTW89_ENTITY_MODE_SCC;
268 break;
269 case 2 ... NUM_OF_RTW89_SUB_ENTITY:
270 if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) {
271 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
272 fmt: "unhandled ent: %d chanctxs %d roles\n",
273 w.active_chanctxs, w.active_roles);
274 return RTW89_ENTITY_MODE_UNHANDLED;
275 }
276
277 mode = rtw89_get_entity_mode(rtwdev);
278 if (mode == RTW89_ENTITY_MODE_MCC)
279 break;
280
281 mode = RTW89_ENTITY_MODE_MCC_PREPARE;
282 break;
283 }
284
285 for_each_set_bit(idx, recalc_map, NUM_OF_RTW89_SUB_ENTITY) {
286 chandef = rtw89_chandef_get(rtwdev, idx);
287 rtw89_get_channel_params(chandef, chan: &chan);
288 if (chan.channel == 0) {
289 WARN(1, "Invalid channel on chanctx %d\n", idx);
290 return RTW89_ENTITY_MODE_INVALID;
291 }
292
293 rtw89_assign_entity_chan(rtwdev, idx, new: &chan);
294 }
295
296 if (hal->entity_pause)
297 return rtw89_get_entity_mode(rtwdev);
298
299 rtw89_set_entity_mode(rtwdev, mode);
300 return mode;
301}
302
303static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
304 enum rtw89_chanctx_state state)
305{
306 const struct rtw89_chip_info *chip = rtwdev->chip;
307 const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
308 int i;
309
310 if (!listener)
311 return;
312
313 for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
314 if (!listener->callbacks[i])
315 continue;
316
317 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
318 fmt: "chanctx notify listener: cb %d, state %d\n",
319 i, state);
320
321 listener->callbacks[i](rtwdev, state);
322 }
323}
324
325static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev)
326{
327 enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
328
329 return chip_gen == RTW89_CHIP_BE;
330}
331
332/* This function centrally manages how MCC roles are sorted and iterated.
333 * And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES.
334 * So, if data needs to pass an array for ordered_idx, the array can declare
335 * with NUM_OF_RTW89_MCC_ROLES. Besides, the entire iteration will stop
336 * immediately as long as iterator returns a non-zero value.
337 */
338static
339int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev,
340 int (*iterator)(struct rtw89_dev *rtwdev,
341 struct rtw89_mcc_role *mcc_role,
342 unsigned int ordered_idx,
343 void *data),
344 void *data)
345{
346 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
347 struct rtw89_mcc_role * const roles[] = {
348 &mcc->role_ref,
349 &mcc->role_aux,
350 };
351 unsigned int idx;
352 int ret;
353
354 BUILD_BUG_ON(ARRAY_SIZE(roles) != NUM_OF_RTW89_MCC_ROLES);
355
356 for (idx = 0; idx < NUM_OF_RTW89_MCC_ROLES; idx++) {
357 ret = iterator(rtwdev, roles[idx], idx, data);
358 if (ret)
359 return ret;
360 }
361
362 return 0;
363}
364
365static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
366 struct rtw89_mcc_role *role, u64 tsf)
367{
368 struct rtw89_vif *rtwvif = role->rtwvif;
369 u32 bcn_intvl_us = ieee80211_tu_to_usec(tu: role->beacon_interval);
370 u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf);
371 u32 remainder;
372
373 if (tsf < sync_tsf) {
374 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
375 fmt: "MCC get tbtt ofst: tsf might not update yet\n");
376 sync_tsf = 0;
377 }
378
379 div_u64_rem(dividend: tsf - sync_tsf, divisor: bcn_intvl_us, remainder: &remainder);
380
381 return remainder;
382}
383
384static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
385{
386 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
387 struct rtw89_mcc_role *ref = &mcc->role_ref;
388 struct rtw89_mcc_role *aux = &mcc->role_aux;
389 struct rtw89_mac_mcc_tsf_rpt rpt = {};
390 struct rtw89_fw_mcc_tsf_req req = {};
391 int ret;
392
393 req.group = mcc->group;
394 req.macid_x = ref->rtwvif->mac_id;
395 req.macid_y = aux->rtwvif->mac_id;
396 ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, req: &req, rpt: &rpt);
397 if (ret) {
398 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
399 fmt: "MCC h2c failed to request tsf: %d\n", ret);
400 return ret;
401 }
402
403 *tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
404 *tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
405
406 return 0;
407}
408
409static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
410{
411 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
412 struct rtw89_mcc_role *ref = &mcc->role_ref;
413 struct rtw89_mcc_role *aux = &mcc->role_aux;
414 struct rtw89_fw_mrc_req_tsf_arg arg = {};
415 struct rtw89_mac_mrc_tsf_rpt rpt = {};
416 int ret;
417
418 BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
419
420 arg.num = 2;
421 arg.infos[0].band = ref->rtwvif->mac_idx;
422 arg.infos[0].port = ref->rtwvif->port;
423 arg.infos[1].band = aux->rtwvif->mac_idx;
424 arg.infos[1].port = aux->rtwvif->port;
425
426 ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, arg: &arg, rpt: &rpt);
427 if (ret) {
428 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
429 fmt: "MRC h2c failed to request tsf: %d\n", ret);
430 return ret;
431 }
432
433 *tsf_ref = rpt.tsfs[0];
434 *tsf_aux = rpt.tsfs[1];
435
436 return 0;
437}
438
439static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
440{
441 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
442 struct rtw89_mcc_role *ref = &mcc->role_ref;
443 struct rtw89_mcc_role *aux = &mcc->role_aux;
444 u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(tu: ref->beacon_interval);
445 u32 tbtt_ofst_ref, tbtt_ofst_aux;
446 u64 tsf_ref, tsf_aux;
447 int ret;
448
449 if (rtw89_concurrent_via_mrc(rtwdev))
450 ret = __mrc_fw_req_tsf(rtwdev, tsf_ref: &tsf_ref, tsf_aux: &tsf_aux);
451 else
452 ret = __mcc_fw_req_tsf(rtwdev, tsf_ref: &tsf_ref, tsf_aux: &tsf_aux);
453
454 if (ret)
455 return RTW89_MCC_DFLT_BCN_OFST_TIME;
456
457 tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, role: ref, tsf: tsf_ref);
458 tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, role: aux, tsf: tsf_aux);
459
460 while (tbtt_ofst_ref < tbtt_ofst_aux)
461 tbtt_ofst_ref += bcn_intvl_ref_us;
462
463 return (tbtt_ofst_ref - tbtt_ofst_aux) / 1024;
464}
465
466static
467void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role,
468 unsigned int bit)
469{
470 unsigned int idx = bit / 8;
471 unsigned int pos = bit % 8;
472
473 if (idx >= ARRAY_SIZE(mcc_role->macid_bitmap))
474 return;
475
476 mcc_role->macid_bitmap[idx] |= BIT(pos);
477}
478
479static
480u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role)
481{
482 unsigned int macid;
483 unsigned int i, j;
484 u32 bitmap = 0;
485
486 for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) {
487 for (j = 0; j < 8; j++) {
488 macid = i * 8 + j;
489 if (macid >= 32)
490 goto out;
491
492 if (mcc_role->macid_bitmap[i] & BIT(j))
493 bitmap |= BIT(macid);
494 }
495 }
496
497out:
498 return bitmap;
499}
500
501static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
502{
503 struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
504 struct rtw89_vif *rtwvif = rtwsta->rtwvif;
505 struct rtw89_mcc_role *mcc_role = data;
506 struct rtw89_vif *target = mcc_role->rtwvif;
507
508 if (rtwvif != target)
509 return;
510
511 rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, bit: rtwsta->mac_id);
512}
513
514static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
515 struct rtw89_mcc_role *mcc_role)
516{
517 struct rtw89_vif *rtwvif = mcc_role->rtwvif;
518
519 rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, bit: rtwvif->mac_id);
520 ieee80211_iterate_stations_atomic(hw: rtwdev->hw,
521 iterator: rtw89_mcc_role_macid_sta_iter,
522 data: mcc_role);
523}
524
525static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev,
526 struct rtw89_mcc_role *mcc_role)
527{
528 struct rtw89_mcc_policy *policy = &mcc_role->policy;
529
530 policy->c2h_rpt = RTW89_FW_MCC_C2H_RPT_ALL;
531 policy->tx_null_early = RTW89_MCC_DFLT_TX_NULL_EARLY;
532 policy->in_curr_ch = false;
533 policy->dis_sw_retry = true;
534 policy->sw_retry_count = false;
535
536 if (mcc_role->is_go)
537 policy->dis_tx_null = true;
538 else
539 policy->dis_tx_null = false;
540}
541
542static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
543 struct rtw89_mcc_role *mcc_role)
544{
545 struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif: mcc_role->rtwvif);
546 struct ieee80211_p2p_noa_desc *noa_desc;
547 u32 bcn_intvl_us = ieee80211_tu_to_usec(tu: mcc_role->beacon_interval);
548 u32 max_toa_us, max_tob_us, max_dur_us;
549 u32 start_time, interval, duration;
550 u64 tsf, tsf_lmt;
551 int ret;
552 int i;
553
554 if (!mcc_role->is_go && !mcc_role->is_gc)
555 return;
556
557 /* find the first periodic NoA */
558 for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
559 noa_desc = &vif->bss_conf.p2p_noa_attr.desc[i];
560 if (noa_desc->count == 255)
561 goto fill;
562 }
563
564 return;
565
566fill:
567 start_time = le32_to_cpu(noa_desc->start_time);
568 interval = le32_to_cpu(noa_desc->interval);
569 duration = le32_to_cpu(noa_desc->duration);
570
571 if (interval != bcn_intvl_us) {
572 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
573 fmt: "MCC role limit: mismatch interval: %d vs. %d\n",
574 interval, bcn_intvl_us);
575 return;
576 }
577
578 ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif: mcc_role->rtwvif, tsf: &tsf);
579 if (ret) {
580 rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
581 return;
582 }
583
584 tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time;
585 max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, role: mcc_role, tsf: tsf_lmt);
586 max_dur_us = interval - duration;
587 max_tob_us = max_dur_us - max_toa_us;
588
589 if (!max_toa_us || !max_tob_us) {
590 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
591 fmt: "MCC role limit: hit boundary\n");
592 return;
593 }
594
595 if (max_dur_us < max_toa_us) {
596 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
597 fmt: "MCC role limit: insufficient duration\n");
598 return;
599 }
600
601 mcc_role->limit.max_toa = max_toa_us / 1024;
602 mcc_role->limit.max_tob = max_tob_us / 1024;
603 mcc_role->limit.max_dur = max_dur_us / 1024;
604 mcc_role->limit.enable = true;
605
606 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
607 fmt: "MCC role limit: max_toa %d, max_tob %d, max_dur %d\n",
608 mcc_role->limit.max_toa, mcc_role->limit.max_tob,
609 mcc_role->limit.max_dur);
610}
611
612static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
613 struct rtw89_vif *rtwvif,
614 struct rtw89_mcc_role *role)
615{
616 struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
617 const struct rtw89_chan *chan;
618
619 memset(role, 0, sizeof(*role));
620 role->rtwvif = rtwvif;
621 role->beacon_interval = vif->bss_conf.beacon_int;
622
623 if (!role->beacon_interval) {
624 rtw89_warn(rtwdev,
625 "cannot handle MCC role without beacon interval\n");
626 return -EINVAL;
627 }
628
629 role->duration = role->beacon_interval / 2;
630
631 chan = rtw89_chan_get(rtwdev, idx: rtwvif->sub_entity_idx);
632 role->is_2ghz = chan->band_type == RTW89_BAND_2G;
633 role->is_go = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
634 role->is_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
635
636 rtw89_mcc_fill_role_macid_bitmap(rtwdev, mcc_role: role);
637 rtw89_mcc_fill_role_policy(rtwdev, mcc_role: role);
638 rtw89_mcc_fill_role_limit(rtwdev, mcc_role: role);
639
640 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
641 fmt: "MCC role: bcn_intvl %d, is_2ghz %d, is_go %d, is_gc %d\n",
642 role->beacon_interval, role->is_2ghz, role->is_go, role->is_gc);
643 return 0;
644}
645
646static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev)
647{
648 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
649 struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
650
651 memset(bt_role, 0, sizeof(*bt_role));
652 bt_role->duration = rtw89_coex_query_bt_req_len(rtwdev, phy_idx: RTW89_PHY_0);
653
654 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC bt role: dur %d\n",
655 bt_role->duration);
656}
657
658struct rtw89_mcc_fill_role_selector {
659 struct rtw89_vif *bind_vif[NUM_OF_RTW89_SUB_ENTITY];
660};
661
662static_assert((u8)NUM_OF_RTW89_SUB_ENTITY >= NUM_OF_RTW89_MCC_ROLES);
663
664static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
665 struct rtw89_mcc_role *mcc_role,
666 unsigned int ordered_idx,
667 void *data)
668{
669 struct rtw89_mcc_fill_role_selector *sel = data;
670 struct rtw89_vif *role_vif = sel->bind_vif[ordered_idx];
671 int ret;
672
673 if (!role_vif) {
674 rtw89_warn(rtwdev, "cannot handle MCC without role[%d]\n",
675 ordered_idx);
676 return -EINVAL;
677 }
678
679 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
680 fmt: "MCC fill role[%d] with vif <macid %d>\n",
681 ordered_idx, role_vif->mac_id);
682
683 ret = rtw89_mcc_fill_role(rtwdev, rtwvif: role_vif, role: mcc_role);
684 if (ret)
685 return ret;
686
687 return 0;
688}
689
690static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
691{
692 struct rtw89_mcc_fill_role_selector sel = {};
693 struct rtw89_vif *rtwvif;
694 int ret;
695
696 rtw89_for_each_rtwvif(rtwdev, rtwvif) {
697 if (!rtwvif->chanctx_assigned)
698 continue;
699
700 if (sel.bind_vif[rtwvif->sub_entity_idx]) {
701 rtw89_warn(rtwdev,
702 "MCC skip extra vif <macid %d> on chanctx[%d]\n",
703 rtwvif->mac_id, rtwvif->sub_entity_idx);
704 continue;
705 }
706
707 sel.bind_vif[rtwvif->sub_entity_idx] = rtwvif;
708 }
709
710 ret = rtw89_iterate_mcc_roles(rtwdev, iterator: rtw89_mcc_fill_role_iterator, data: &sel);
711 if (ret)
712 return ret;
713
714 rtw89_mcc_fill_bt_role(rtwdev);
715 return 0;
716}
717
718static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
719 const struct rtw89_mcc_pattern *new)
720{
721 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
722 struct rtw89_mcc_role *ref = &mcc->role_ref;
723 struct rtw89_mcc_role *aux = &mcc->role_aux;
724 struct rtw89_mcc_config *config = &mcc->config;
725 struct rtw89_mcc_pattern *pattern = &config->pattern;
726
727 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
728 fmt: "MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",
729 new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux);
730
731 *pattern = *new;
732 memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
733
734 if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) {
735 pattern->courtesy.macid_tgt = aux->rtwvif->mac_id;
736 pattern->courtesy.macid_src = ref->rtwvif->mac_id;
737 pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
738 pattern->courtesy.enable = true;
739 } else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) {
740 pattern->courtesy.macid_tgt = ref->rtwvif->mac_id;
741 pattern->courtesy.macid_src = aux->rtwvif->mac_id;
742 pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
743 pattern->courtesy.enable = true;
744 }
745
746 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
747 fmt: "MCC pattern flags: plan %d, courtesy_en %d\n",
748 pattern->plan, pattern->courtesy.enable);
749
750 if (!pattern->courtesy.enable)
751 return;
752
753 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
754 fmt: "MCC pattern courtesy: tgt %d, src %d, slot %d\n",
755 pattern->courtesy.macid_tgt, pattern->courtesy.macid_src,
756 pattern->courtesy.slot_num);
757}
758
759/* The follow-up roughly shows the relationship between the parameters
760 * for pattern calculation.
761 *
762 * |< duration ref >| (if mid bt) |< duration aux >|
763 * |< tob ref >|< toa ref >| ... |< tob aux >|< toa aux >|
764 * V V
765 * tbtt ref tbtt aux
766 * |< beacon offset >|
767 *
768 * In loose pattern calculation, we only ensure at least tob_ref and
769 * toa_ref have positive results. If tob_aux or toa_aux is negative
770 * unfortunately, FW will be notified to handle it with courtesy
771 * mechanism.
772 */
773static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
774 struct rtw89_mcc_pattern *ptrn,
775 bool hdl_bt)
776{
777 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
778 struct rtw89_mcc_role *ref = &mcc->role_ref;
779 struct rtw89_mcc_role *aux = &mcc->role_aux;
780 struct rtw89_mcc_config *config = &mcc->config;
781 u16 bcn_ofst = config->beacon_offset;
782 u16 bt_dur_in_mid = 0;
783 u16 max_bcn_ofst;
784 s16 upper, lower;
785 u16 res;
786
787 *ptrn = (typeof(*ptrn)){
788 .plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
789 };
790
791 if (!hdl_bt)
792 goto calc;
793
794 max_bcn_ofst = ref->duration + aux->duration;
795 if (ref->limit.enable)
796 max_bcn_ofst = min_t(u16, max_bcn_ofst,
797 ref->limit.max_toa + aux->duration);
798 else if (aux->limit.enable)
799 max_bcn_ofst = min_t(u16, max_bcn_ofst,
800 ref->duration + aux->limit.max_tob);
801
802 if (bcn_ofst > max_bcn_ofst && bcn_ofst >= mcc->bt_role.duration) {
803 bt_dur_in_mid = mcc->bt_role.duration;
804 ptrn->plan = RTW89_MCC_PLAN_MID_BT;
805 }
806
807calc:
808 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
809 fmt: "MCC calc ptrn_ls: plan %d, bcn_ofst %d\n",
810 ptrn->plan, bcn_ofst);
811
812 res = bcn_ofst - bt_dur_in_mid;
813 upper = min_t(s16, ref->duration, res);
814 lower = 0;
815
816 if (ref->limit.enable) {
817 upper = min_t(s16, upper, ref->limit.max_toa);
818 lower = max_t(s16, lower, ref->duration - ref->limit.max_tob);
819 } else if (aux->limit.enable) {
820 upper = min_t(s16, upper,
821 res - (aux->duration - aux->limit.max_toa));
822 lower = max_t(s16, lower, res - aux->limit.max_tob);
823 }
824
825 if (lower < upper)
826 ptrn->toa_ref = (upper + lower) / 2;
827 else
828 ptrn->toa_ref = lower;
829
830 ptrn->tob_ref = ref->duration - ptrn->toa_ref;
831 ptrn->tob_aux = res - ptrn->toa_ref;
832 ptrn->toa_aux = aux->duration - ptrn->tob_aux;
833}
834
835/* In strict pattern calculation, we consider timing that might need
836 * for HW stuffs, i.e. min_tob and min_toa.
837 */
838static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,
839 struct rtw89_mcc_pattern *ptrn)
840{
841 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
842 struct rtw89_mcc_role *ref = &mcc->role_ref;
843 struct rtw89_mcc_role *aux = &mcc->role_aux;
844 struct rtw89_mcc_config *config = &mcc->config;
845 u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME;
846 u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME;
847 u16 bcn_ofst = config->beacon_offset;
848 s16 upper_toa_ref, lower_toa_ref;
849 s16 upper_tob_aux, lower_tob_aux;
850 u16 bt_dur_in_mid;
851 s16 res;
852
853 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
854 fmt: "MCC calc ptrn_st: plan %d, bcn_ofst %d\n",
855 ptrn->plan, bcn_ofst);
856
857 if (ptrn->plan == RTW89_MCC_PLAN_MID_BT)
858 bt_dur_in_mid = mcc->bt_role.duration;
859 else
860 bt_dur_in_mid = 0;
861
862 if (ref->duration < min_tob + min_toa) {
863 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
864 fmt: "MCC calc ptrn_st: not meet ref dur cond\n");
865 return -EINVAL;
866 }
867
868 if (aux->duration < min_tob + min_toa) {
869 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
870 fmt: "MCC calc ptrn_st: not meet aux dur cond\n");
871 return -EINVAL;
872 }
873
874 res = bcn_ofst - min_toa - min_tob - bt_dur_in_mid;
875 if (res < 0) {
876 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
877 fmt: "MCC calc ptrn_st: not meet bcn_ofst cond\n");
878 return -EINVAL;
879 }
880
881 upper_toa_ref = min_t(s16, min_toa + res, ref->duration - min_tob);
882 lower_toa_ref = min_toa;
883 upper_tob_aux = min_t(s16, min_tob + res, aux->duration - min_toa);
884 lower_tob_aux = min_tob;
885
886 if (ref->limit.enable) {
887 if (min_tob > ref->limit.max_tob || min_toa > ref->limit.max_toa) {
888 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
889 fmt: "MCC calc ptrn_st: conflict ref limit\n");
890 return -EINVAL;
891 }
892
893 upper_toa_ref = min_t(s16, upper_toa_ref, ref->limit.max_toa);
894 lower_toa_ref = max_t(s16, lower_toa_ref,
895 ref->duration - ref->limit.max_tob);
896 } else if (aux->limit.enable) {
897 if (min_tob > aux->limit.max_tob || min_toa > aux->limit.max_toa) {
898 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
899 fmt: "MCC calc ptrn_st: conflict aux limit\n");
900 return -EINVAL;
901 }
902
903 upper_tob_aux = min_t(s16, upper_tob_aux, aux->limit.max_tob);
904 lower_tob_aux = max_t(s16, lower_tob_aux,
905 aux->duration - aux->limit.max_toa);
906 }
907
908 upper_toa_ref = min_t(s16, upper_toa_ref,
909 bcn_ofst - bt_dur_in_mid - lower_tob_aux);
910 lower_toa_ref = max_t(s16, lower_toa_ref,
911 bcn_ofst - bt_dur_in_mid - upper_tob_aux);
912 if (lower_toa_ref > upper_toa_ref) {
913 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
914 fmt: "MCC calc ptrn_st: conflict boundary\n");
915 return -EINVAL;
916 }
917
918 ptrn->toa_ref = (upper_toa_ref + lower_toa_ref) / 2;
919 ptrn->tob_ref = ref->duration - ptrn->toa_ref;
920 ptrn->tob_aux = bcn_ofst - ptrn->toa_ref - bt_dur_in_mid;
921 ptrn->toa_aux = aux->duration - ptrn->tob_aux;
922 return 0;
923}
924
925static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
926{
927 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
928 struct rtw89_mcc_role *ref = &mcc->role_ref;
929 struct rtw89_mcc_role *aux = &mcc->role_aux;
930 bool sel_plan[NUM_OF_RTW89_MCC_PLAN] = {};
931 struct rtw89_mcc_pattern ptrn;
932 int ret;
933 int i;
934
935 if (ref->limit.enable && aux->limit.enable) {
936 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
937 fmt: "MCC calc ptrn: not support dual limited roles\n");
938 return -EINVAL;
939 }
940
941 if (ref->limit.enable &&
942 ref->duration > ref->limit.max_tob + ref->limit.max_toa) {
943 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
944 fmt: "MCC calc ptrn: not fit ref limit\n");
945 return -EINVAL;
946 }
947
948 if (aux->limit.enable &&
949 aux->duration > aux->limit.max_tob + aux->limit.max_toa) {
950 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
951 fmt: "MCC calc ptrn: not fit aux limit\n");
952 return -EINVAL;
953 }
954
955 if (hdl_bt) {
956 sel_plan[RTW89_MCC_PLAN_TAIL_BT] = true;
957 sel_plan[RTW89_MCC_PLAN_MID_BT] = true;
958 } else {
959 sel_plan[RTW89_MCC_PLAN_NO_BT] = true;
960 }
961
962 for (i = 0; i < NUM_OF_RTW89_MCC_PLAN; i++) {
963 if (!sel_plan[i])
964 continue;
965
966 ptrn = (typeof(ptrn)){
967 .plan = i,
968 };
969
970 ret = __rtw89_mcc_calc_pattern_strict(rtwdev, ptrn: &ptrn);
971 if (ret)
972 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
973 fmt: "MCC calc ptrn_st with plan %d: fail\n", i);
974 else
975 goto done;
976 }
977
978 __rtw89_mcc_calc_pattern_loose(rtwdev, ptrn: &ptrn, hdl_bt);
979
980done:
981 rtw89_mcc_assign_pattern(rtwdev, new: &ptrn);
982 return 0;
983}
984
985static void rtw89_mcc_set_default_pattern(struct rtw89_dev *rtwdev)
986{
987 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
988 struct rtw89_mcc_role *ref = &mcc->role_ref;
989 struct rtw89_mcc_role *aux = &mcc->role_aux;
990 struct rtw89_mcc_pattern tmp = {};
991
992 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
993 fmt: "MCC use default pattern unexpectedly\n");
994
995 tmp.plan = RTW89_MCC_PLAN_NO_BT;
996 tmp.tob_ref = ref->duration / 2;
997 tmp.toa_ref = ref->duration - tmp.tob_ref;
998 tmp.tob_aux = aux->duration / 2;
999 tmp.toa_aux = aux->duration - tmp.tob_aux;
1000
1001 rtw89_mcc_assign_pattern(rtwdev, new: &tmp);
1002}
1003
1004static void rtw89_mcc_set_duration_go_sta(struct rtw89_dev *rtwdev,
1005 struct rtw89_mcc_role *role_go,
1006 struct rtw89_mcc_role *role_sta)
1007{
1008 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1009 struct rtw89_mcc_config *config = &mcc->config;
1010 u16 mcc_intvl = config->mcc_interval;
1011 u16 dur_go, dur_sta;
1012
1013 dur_go = clamp_t(u16, role_go->duration, RTW89_MCC_MIN_GO_DURATION,
1014 mcc_intvl - RTW89_MCC_MIN_STA_DURATION);
1015 if (role_go->limit.enable)
1016 dur_go = min(dur_go, role_go->limit.max_dur);
1017 dur_sta = mcc_intvl - dur_go;
1018
1019 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1020 fmt: "MCC set dur: (go, sta) {%d, %d} -> {%d, %d}\n",
1021 role_go->duration, role_sta->duration, dur_go, dur_sta);
1022
1023 role_go->duration = dur_go;
1024 role_sta->duration = dur_sta;
1025}
1026
1027static void rtw89_mcc_set_duration_gc_sta(struct rtw89_dev *rtwdev)
1028{
1029 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1030 struct rtw89_mcc_role *ref = &mcc->role_ref;
1031 struct rtw89_mcc_role *aux = &mcc->role_aux;
1032 struct rtw89_mcc_config *config = &mcc->config;
1033 u16 mcc_intvl = config->mcc_interval;
1034 u16 dur_ref, dur_aux;
1035
1036 if (ref->duration < RTW89_MCC_MIN_STA_DURATION) {
1037 dur_ref = RTW89_MCC_MIN_STA_DURATION;
1038 dur_aux = mcc_intvl - dur_ref;
1039 } else if (aux->duration < RTW89_MCC_MIN_STA_DURATION) {
1040 dur_aux = RTW89_MCC_MIN_STA_DURATION;
1041 dur_ref = mcc_intvl - dur_aux;
1042 } else {
1043 dur_ref = ref->duration;
1044 dur_aux = mcc_intvl - dur_ref;
1045 }
1046
1047 if (ref->limit.enable) {
1048 dur_ref = min(dur_ref, ref->limit.max_dur);
1049 dur_aux = mcc_intvl - dur_ref;
1050 } else if (aux->limit.enable) {
1051 dur_aux = min(dur_aux, aux->limit.max_dur);
1052 dur_ref = mcc_intvl - dur_aux;
1053 }
1054
1055 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1056 fmt: "MCC set dur: (ref, aux) {%d ~ %d} -> {%d ~ %d}\n",
1057 ref->duration, aux->duration, dur_ref, dur_aux);
1058
1059 ref->duration = dur_ref;
1060 aux->duration = dur_aux;
1061}
1062
1063struct rtw89_mcc_mod_dur_data {
1064 u16 available;
1065 struct {
1066 u16 dur;
1067 u16 room;
1068 } parm[NUM_OF_RTW89_MCC_ROLES];
1069};
1070
1071static int rtw89_mcc_mod_dur_get_iterator(struct rtw89_dev *rtwdev,
1072 struct rtw89_mcc_role *mcc_role,
1073 unsigned int ordered_idx,
1074 void *data)
1075{
1076 struct rtw89_mcc_mod_dur_data *p = data;
1077 u16 min;
1078
1079 p->parm[ordered_idx].dur = mcc_role->duration;
1080
1081 if (mcc_role->is_go)
1082 min = RTW89_MCC_MIN_GO_DURATION;
1083 else
1084 min = RTW89_MCC_MIN_STA_DURATION;
1085
1086 p->parm[ordered_idx].room = max_t(s32, p->parm[ordered_idx].dur - min, 0);
1087
1088 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1089 fmt: "MCC mod dur: chk role[%u]: dur %u, min %u, room %u\n",
1090 ordered_idx, p->parm[ordered_idx].dur, min,
1091 p->parm[ordered_idx].room);
1092
1093 p->available += p->parm[ordered_idx].room;
1094 return 0;
1095}
1096
1097static int rtw89_mcc_mod_dur_put_iterator(struct rtw89_dev *rtwdev,
1098 struct rtw89_mcc_role *mcc_role,
1099 unsigned int ordered_idx,
1100 void *data)
1101{
1102 struct rtw89_mcc_mod_dur_data *p = data;
1103
1104 mcc_role->duration = p->parm[ordered_idx].dur;
1105
1106 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1107 fmt: "MCC mod dur: set role[%u]: dur %u\n",
1108 ordered_idx, p->parm[ordered_idx].dur);
1109 return 0;
1110}
1111
1112static void rtw89_mcc_mod_duration_dual_2ghz_with_bt(struct rtw89_dev *rtwdev)
1113{
1114 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1115 struct rtw89_mcc_config *config = &mcc->config;
1116 struct rtw89_mcc_mod_dur_data data = {};
1117 u16 mcc_intvl = config->mcc_interval;
1118 u16 bt_dur = mcc->bt_role.duration;
1119 u16 wifi_dur;
1120
1121 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1122 fmt: "MCC mod dur (dual 2ghz): mcc_intvl %u, raw bt_dur %u\n",
1123 mcc_intvl, bt_dur);
1124
1125 rtw89_iterate_mcc_roles(rtwdev, iterator: rtw89_mcc_mod_dur_get_iterator, data: &data);
1126
1127 bt_dur = clamp_t(u16, bt_dur, 1, data.available / 3);
1128 wifi_dur = mcc_intvl - bt_dur;
1129
1130 if (data.parm[0].room <= data.parm[1].room) {
1131 data.parm[0].dur -= min_t(u16, bt_dur / 2, data.parm[0].room);
1132 data.parm[1].dur = wifi_dur - data.parm[0].dur;
1133 } else {
1134 data.parm[1].dur -= min_t(u16, bt_dur / 2, data.parm[1].room);
1135 data.parm[0].dur = wifi_dur - data.parm[1].dur;
1136 }
1137
1138 rtw89_iterate_mcc_roles(rtwdev, iterator: rtw89_mcc_mod_dur_put_iterator, data: &data);
1139
1140 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC mod dur: set bt: dur %u\n", bt_dur);
1141 mcc->bt_role.duration = bt_dur;
1142}
1143
1144static
1145void rtw89_mcc_mod_duration_diff_band_with_bt(struct rtw89_dev *rtwdev,
1146 struct rtw89_mcc_role *role_2ghz,
1147 struct rtw89_mcc_role *role_non_2ghz)
1148{
1149 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1150 struct rtw89_mcc_config *config = &mcc->config;
1151 u16 dur_2ghz, dur_non_2ghz;
1152 u16 bt_dur, mcc_intvl;
1153
1154 dur_2ghz = role_2ghz->duration;
1155 dur_non_2ghz = role_non_2ghz->duration;
1156 mcc_intvl = config->mcc_interval;
1157 bt_dur = mcc->bt_role.duration;
1158
1159 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1160 fmt: "MCC mod dur (diff band): mcc_intvl %u, bt_dur %u\n",
1161 mcc_intvl, bt_dur);
1162
1163 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1164 fmt: "MCC mod dur: check dur_2ghz %u, dur_non_2ghz %u\n",
1165 dur_2ghz, dur_non_2ghz);
1166
1167 if (dur_non_2ghz >= bt_dur) {
1168 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1169 fmt: "MCC mod dur: dur_non_2ghz is enough for bt\n");
1170 return;
1171 }
1172
1173 dur_non_2ghz = bt_dur;
1174 dur_2ghz = mcc_intvl - dur_non_2ghz;
1175
1176 if (role_non_2ghz->limit.enable) {
1177 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1178 fmt: "MCC mod dur: dur_non_2ghz is limited with max %u\n",
1179 role_non_2ghz->limit.max_dur);
1180
1181 dur_non_2ghz = min(dur_non_2ghz, role_non_2ghz->limit.max_dur);
1182 dur_2ghz = mcc_intvl - dur_non_2ghz;
1183 }
1184
1185 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1186 fmt: "MCC mod dur: set dur_2ghz %u, dur_non_2ghz %u\n",
1187 dur_2ghz, dur_non_2ghz);
1188
1189 role_2ghz->duration = dur_2ghz;
1190 role_non_2ghz->duration = dur_non_2ghz;
1191}
1192
1193static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)
1194{
1195 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1196 struct rtw89_mcc_role *ref = &mcc->role_ref;
1197 struct rtw89_mcc_role *aux = &mcc->role_aux;
1198 struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1199
1200 if (!bt_role->duration)
1201 return false;
1202
1203 if (ref->is_2ghz && aux->is_2ghz) {
1204 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1205 fmt: "MCC dual roles are on 2GHz; consider BT duration\n");
1206
1207 rtw89_mcc_mod_duration_dual_2ghz_with_bt(rtwdev);
1208 return true;
1209 }
1210
1211 if (!ref->is_2ghz && !aux->is_2ghz) {
1212 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1213 fmt: "MCC dual roles are not on 2GHz; ignore BT duration\n");
1214 return false;
1215 }
1216
1217 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1218 fmt: "MCC one role is on 2GHz; modify another for BT duration\n");
1219
1220 if (ref->is_2ghz)
1221 rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, role_2ghz: ref, role_non_2ghz: aux);
1222 else
1223 rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, role_2ghz: aux, role_non_2ghz: ref);
1224
1225 return false;
1226}
1227
1228static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
1229 struct rtw89_mcc_role *tgt,
1230 struct rtw89_mcc_role *src,
1231 bool ref_is_src)
1232{
1233 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1234 struct rtw89_mcc_config *config = &mcc->config;
1235 u16 beacon_offset_us = ieee80211_tu_to_usec(tu: config->beacon_offset);
1236 u32 bcn_intvl_src_us = ieee80211_tu_to_usec(tu: src->beacon_interval);
1237 u32 cur_tbtt_ofst_src;
1238 u32 tsf_ofst_tgt;
1239 u32 remainder;
1240 u64 tbtt_tgt;
1241 u64 tsf_src;
1242 int ret;
1243
1244 ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif: src->rtwvif, tsf: &tsf_src);
1245 if (ret) {
1246 rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
1247 return;
1248 }
1249
1250 cur_tbtt_ofst_src = rtw89_mcc_get_tbtt_ofst(rtwdev, role: src, tsf: tsf_src);
1251
1252 if (ref_is_src)
1253 tbtt_tgt = tsf_src - cur_tbtt_ofst_src + beacon_offset_us;
1254 else
1255 tbtt_tgt = tsf_src - cur_tbtt_ofst_src +
1256 (bcn_intvl_src_us - beacon_offset_us);
1257
1258 div_u64_rem(dividend: tbtt_tgt, divisor: bcn_intvl_src_us, remainder: &remainder);
1259 tsf_ofst_tgt = bcn_intvl_src_us - remainder;
1260
1261 config->sync.macid_tgt = tgt->rtwvif->mac_id;
1262 config->sync.band_tgt = tgt->rtwvif->mac_idx;
1263 config->sync.port_tgt = tgt->rtwvif->port;
1264 config->sync.macid_src = src->rtwvif->mac_id;
1265 config->sync.band_src = src->rtwvif->mac_idx;
1266 config->sync.port_src = src->rtwvif->port;
1267 config->sync.offset = tsf_ofst_tgt / 1024;
1268 config->sync.enable = true;
1269
1270 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1271 fmt: "MCC sync tbtt: tgt %d, src %d, offset %d\n",
1272 config->sync.macid_tgt, config->sync.macid_src,
1273 config->sync.offset);
1274
1275 rtw89_mac_port_tsf_sync(rtwdev, rtwvif: tgt->rtwvif, rtwvif_src: src->rtwvif,
1276 offset_tu: config->sync.offset);
1277}
1278
1279static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
1280{
1281 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1282 struct rtw89_mcc_role *ref = &mcc->role_ref;
1283 struct rtw89_mcc_config *config = &mcc->config;
1284 u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(tu: ref->beacon_interval);
1285 u32 tob_ref_us = ieee80211_tu_to_usec(tu: config->pattern.tob_ref);
1286 struct rtw89_vif *rtwvif = ref->rtwvif;
1287 u64 tsf, start_tsf;
1288 u32 cur_tbtt_ofst;
1289 u64 min_time;
1290 int ret;
1291
1292 ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, tsf: &tsf);
1293 if (ret) {
1294 rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
1295 return ret;
1296 }
1297
1298 min_time = tsf;
1299 if (ref->is_go)
1300 min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);
1301 else
1302 min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);
1303
1304 cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, role: ref, tsf);
1305 start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us;
1306 while (start_tsf < min_time)
1307 start_tsf += bcn_intvl_ref_us;
1308
1309 config->start_tsf = start_tsf;
1310 return 0;
1311}
1312
1313static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
1314{
1315 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1316 struct rtw89_mcc_role *ref = &mcc->role_ref;
1317 struct rtw89_mcc_role *aux = &mcc->role_aux;
1318 struct rtw89_mcc_config *config = &mcc->config;
1319 bool hdl_bt;
1320 int ret;
1321
1322 memset(config, 0, sizeof(*config));
1323
1324 switch (mcc->mode) {
1325 case RTW89_MCC_MODE_GO_STA:
1326 config->beacon_offset = RTW89_MCC_DFLT_BCN_OFST_TIME;
1327 if (ref->is_go) {
1328 rtw89_mcc_sync_tbtt(rtwdev, tgt: ref, src: aux, ref_is_src: false);
1329 config->mcc_interval = ref->beacon_interval;
1330 rtw89_mcc_set_duration_go_sta(rtwdev, role_go: ref, role_sta: aux);
1331 } else {
1332 rtw89_mcc_sync_tbtt(rtwdev, tgt: aux, src: ref, ref_is_src: true);
1333 config->mcc_interval = aux->beacon_interval;
1334 rtw89_mcc_set_duration_go_sta(rtwdev, role_go: aux, role_sta: ref);
1335 }
1336 break;
1337 case RTW89_MCC_MODE_GC_STA:
1338 config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
1339 config->mcc_interval = ref->beacon_interval;
1340 rtw89_mcc_set_duration_gc_sta(rtwdev);
1341 break;
1342 default:
1343 rtw89_warn(rtwdev, "MCC unknown mode: %d\n", mcc->mode);
1344 return -EFAULT;
1345 }
1346
1347 hdl_bt = rtw89_mcc_duration_decision_on_bt(rtwdev);
1348 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC handle bt: %d\n", hdl_bt);
1349
1350 ret = rtw89_mcc_calc_pattern(rtwdev, hdl_bt);
1351 if (!ret)
1352 goto bottom;
1353
1354 rtw89_mcc_set_default_pattern(rtwdev);
1355
1356bottom:
1357 return rtw89_mcc_fill_start_tsf(rtwdev);
1358}
1359
1360static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
1361{
1362 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1363 struct rtw89_mcc_config *config = &mcc->config;
1364 struct rtw89_mcc_pattern *pattern = &config->pattern;
1365 struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
1366 struct rtw89_mcc_policy *policy = &role->policy;
1367 struct rtw89_fw_mcc_add_req req = {};
1368 const struct rtw89_chan *chan;
1369 int ret;
1370
1371 chan = rtw89_chan_get(rtwdev, idx: role->rtwvif->sub_entity_idx);
1372 req.central_ch_seg0 = chan->channel;
1373 req.primary_ch = chan->primary_channel;
1374 req.bandwidth = chan->band_width;
1375 req.ch_band_type = chan->band_type;
1376
1377 req.macid = role->rtwvif->mac_id;
1378 req.group = mcc->group;
1379 req.c2h_rpt = policy->c2h_rpt;
1380 req.tx_null_early = policy->tx_null_early;
1381 req.dis_tx_null = policy->dis_tx_null;
1382 req.in_curr_ch = policy->in_curr_ch;
1383 req.sw_retry_count = policy->sw_retry_count;
1384 req.dis_sw_retry = policy->dis_sw_retry;
1385 req.duration = role->duration;
1386 req.btc_in_2g = false;
1387
1388 if (courtesy->enable && courtesy->macid_src == req.macid) {
1389 req.courtesy_target = courtesy->macid_tgt;
1390 req.courtesy_num = courtesy->slot_num;
1391 req.courtesy_en = true;
1392 }
1393
1394 ret = rtw89_fw_h2c_add_mcc(rtwdev, p: &req);
1395 if (ret) {
1396 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1397 fmt: "MCC h2c failed to add wifi role: %d\n", ret);
1398 return ret;
1399 }
1400
1401 ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, group: mcc->group,
1402 macid: role->rtwvif->mac_id,
1403 bitmap: role->macid_bitmap);
1404 if (ret) {
1405 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1406 fmt: "MCC h2c failed to set macid bitmap: %d\n", ret);
1407 return ret;
1408 }
1409
1410 return 0;
1411}
1412
1413static
1414void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
1415 struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
1416{
1417 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1418 struct rtw89_mcc_role *ref = &mcc->role_ref;
1419 struct rtw89_mcc_policy *policy = &role->policy;
1420 struct rtw89_fw_mrc_add_slot_arg *slot_arg;
1421 const struct rtw89_chan *chan;
1422
1423 slot_arg = &arg->slots[slot_idx];
1424 role->slot_idx = slot_idx;
1425
1426 slot_arg->duration = role->duration;
1427 slot_arg->role_num = 1;
1428
1429 chan = rtw89_chan_get(rtwdev, idx: role->rtwvif->sub_entity_idx);
1430
1431 slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
1432 slot_arg->roles[0].is_master = role == ref;
1433 slot_arg->roles[0].band = chan->band_type;
1434 slot_arg->roles[0].bw = chan->band_width;
1435 slot_arg->roles[0].central_ch = chan->channel;
1436 slot_arg->roles[0].primary_ch = chan->primary_channel;
1437 slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
1438 slot_arg->roles[0].null_early = policy->tx_null_early;
1439 slot_arg->roles[0].macid = role->rtwvif->mac_id;
1440 slot_arg->roles[0].macid_main_bitmap =
1441 rtw89_mcc_role_fw_macid_bitmap_to_u32(mcc_role: role);
1442}
1443
1444static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
1445{
1446 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1447 struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1448 struct rtw89_fw_mcc_add_req req = {};
1449 int ret;
1450
1451 req.group = mcc->group;
1452 req.duration = bt_role->duration;
1453 req.btc_in_2g = true;
1454
1455 ret = rtw89_fw_h2c_add_mcc(rtwdev, p: &req);
1456 if (ret) {
1457 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1458 fmt: "MCC h2c failed to add bt role: %d\n", ret);
1459 return ret;
1460 }
1461
1462 return 0;
1463}
1464
1465static
1466void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev,
1467 struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
1468{
1469 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1470 struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
1471 struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx];
1472
1473 slot_arg->duration = bt_role->duration;
1474 slot_arg->role_num = 1;
1475
1476 slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT;
1477}
1478
1479static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
1480{
1481 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1482 struct rtw89_mcc_role *ref = &mcc->role_ref;
1483 struct rtw89_mcc_role *aux = &mcc->role_aux;
1484 struct rtw89_mcc_config *config = &mcc->config;
1485 struct rtw89_mcc_pattern *pattern = &config->pattern;
1486 struct rtw89_mcc_sync *sync = &config->sync;
1487 struct rtw89_fw_mcc_start_req req = {};
1488 int ret;
1489
1490 if (replace) {
1491 req.old_group = mcc->group;
1492 req.old_group_action = RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE;
1493 mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
1494 }
1495
1496 req.group = mcc->group;
1497
1498 switch (pattern->plan) {
1499 case RTW89_MCC_PLAN_TAIL_BT:
1500 ret = __mcc_fw_add_role(rtwdev, role: ref);
1501 if (ret)
1502 return ret;
1503 ret = __mcc_fw_add_role(rtwdev, role: aux);
1504 if (ret)
1505 return ret;
1506 ret = __mcc_fw_add_bt_role(rtwdev);
1507 if (ret)
1508 return ret;
1509
1510 req.btc_in_group = true;
1511 break;
1512 case RTW89_MCC_PLAN_MID_BT:
1513 ret = __mcc_fw_add_role(rtwdev, role: ref);
1514 if (ret)
1515 return ret;
1516 ret = __mcc_fw_add_bt_role(rtwdev);
1517 if (ret)
1518 return ret;
1519 ret = __mcc_fw_add_role(rtwdev, role: aux);
1520 if (ret)
1521 return ret;
1522
1523 req.btc_in_group = true;
1524 break;
1525 case RTW89_MCC_PLAN_NO_BT:
1526 ret = __mcc_fw_add_role(rtwdev, role: ref);
1527 if (ret)
1528 return ret;
1529 ret = __mcc_fw_add_role(rtwdev, role: aux);
1530 if (ret)
1531 return ret;
1532
1533 req.btc_in_group = false;
1534 break;
1535 default:
1536 rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
1537 return -EFAULT;
1538 }
1539
1540 if (sync->enable) {
1541 ret = rtw89_fw_h2c_mcc_sync(rtwdev, group: req.group, source: sync->macid_src,
1542 target: sync->macid_tgt, offset: sync->offset);
1543 if (ret) {
1544 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1545 fmt: "MCC h2c failed to trigger sync: %d\n", ret);
1546 return ret;
1547 }
1548 }
1549
1550 req.macid = ref->rtwvif->mac_id;
1551 req.tsf_high = config->start_tsf >> 32;
1552 req.tsf_low = config->start_tsf;
1553
1554 ret = rtw89_fw_h2c_start_mcc(rtwdev, p: &req);
1555 if (ret) {
1556 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1557 fmt: "MCC h2c failed to trigger start: %d\n", ret);
1558 return ret;
1559 }
1560
1561 return 0;
1562}
1563
1564static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
1565 struct rtw89_fw_mrc_add_arg *arg)
1566{
1567 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1568 struct rtw89_mcc_role *ref = &mcc->role_ref;
1569 struct rtw89_mcc_role *aux = &mcc->role_aux;
1570 struct rtw89_mcc_config *config = &mcc->config;
1571 struct rtw89_mcc_pattern *pattern = &config->pattern;
1572 struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
1573 struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
1574 u8 slot_idx_tgt;
1575
1576 if (!courtesy->enable)
1577 return;
1578
1579 if (courtesy->macid_src == ref->rtwvif->mac_id) {
1580 slot_arg_src = &arg->slots[ref->slot_idx];
1581 slot_idx_tgt = aux->slot_idx;
1582 } else {
1583 slot_arg_src = &arg->slots[aux->slot_idx];
1584 slot_idx_tgt = ref->slot_idx;
1585 }
1586
1587 slot_arg_src->courtesy_target = slot_idx_tgt;
1588 slot_arg_src->courtesy_period = courtesy->slot_num;
1589 slot_arg_src->courtesy_en = true;
1590}
1591
1592static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
1593{
1594 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1595 struct rtw89_mcc_role *ref = &mcc->role_ref;
1596 struct rtw89_mcc_role *aux = &mcc->role_aux;
1597 struct rtw89_mcc_config *config = &mcc->config;
1598 struct rtw89_mcc_pattern *pattern = &config->pattern;
1599 struct rtw89_mcc_sync *sync = &config->sync;
1600 struct rtw89_fw_mrc_start_arg start_arg = {};
1601 struct rtw89_fw_mrc_add_arg add_arg = {};
1602 int ret;
1603
1604 BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM <
1605 NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */);
1606
1607 if (replace) {
1608 start_arg.old_sch_idx = mcc->group;
1609 start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD;
1610 mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
1611 }
1612
1613 add_arg.sch_idx = mcc->group;
1614 add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY;
1615
1616 switch (pattern->plan) {
1617 case RTW89_MCC_PLAN_TAIL_BT:
1618 __mrc_fw_add_role(rtwdev, role: ref, arg: &add_arg, slot_idx: 0);
1619 __mrc_fw_add_role(rtwdev, role: aux, arg: &add_arg, slot_idx: 1);
1620 __mrc_fw_add_bt_role(rtwdev, arg: &add_arg, slot_idx: 2);
1621
1622 add_arg.slot_num = 3;
1623 add_arg.btc_in_sch = true;
1624 break;
1625 case RTW89_MCC_PLAN_MID_BT:
1626 __mrc_fw_add_role(rtwdev, role: ref, arg: &add_arg, slot_idx: 0);
1627 __mrc_fw_add_bt_role(rtwdev, arg: &add_arg, slot_idx: 1);
1628 __mrc_fw_add_role(rtwdev, role: aux, arg: &add_arg, slot_idx: 2);
1629
1630 add_arg.slot_num = 3;
1631 add_arg.btc_in_sch = true;
1632 break;
1633 case RTW89_MCC_PLAN_NO_BT:
1634 __mrc_fw_add_role(rtwdev, role: ref, arg: &add_arg, slot_idx: 0);
1635 __mrc_fw_add_role(rtwdev, role: aux, arg: &add_arg, slot_idx: 1);
1636
1637 add_arg.slot_num = 2;
1638 add_arg.btc_in_sch = false;
1639 break;
1640 default:
1641 rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
1642 return -EFAULT;
1643 }
1644
1645 __mrc_fw_add_courtesy(rtwdev, arg: &add_arg);
1646
1647 ret = rtw89_fw_h2c_mrc_add(rtwdev, arg: &add_arg);
1648 if (ret) {
1649 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1650 fmt: "MRC h2c failed to trigger add: %d\n", ret);
1651 return ret;
1652 }
1653
1654 if (sync->enable) {
1655 struct rtw89_fw_mrc_sync_arg sync_arg = {
1656 .offset = sync->offset,
1657 .src = {
1658 .band = sync->band_src,
1659 .port = sync->port_src,
1660 },
1661 .dest = {
1662 .band = sync->band_tgt,
1663 .port = sync->port_tgt,
1664 },
1665 };
1666
1667 ret = rtw89_fw_h2c_mrc_sync(rtwdev, arg: &sync_arg);
1668 if (ret) {
1669 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1670 fmt: "MRC h2c failed to trigger sync: %d\n", ret);
1671 return ret;
1672 }
1673 }
1674
1675 start_arg.sch_idx = mcc->group;
1676 start_arg.start_tsf = config->start_tsf;
1677
1678 ret = rtw89_fw_h2c_mrc_start(rtwdev, arg: &start_arg);
1679 if (ret) {
1680 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1681 fmt: "MRC h2c failed to trigger start: %d\n", ret);
1682 return ret;
1683 }
1684
1685 return 0;
1686}
1687
1688static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
1689{
1690 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1691 struct rtw89_mcc_config *config = &mcc->config;
1692 struct rtw89_mcc_sync *sync = &config->sync;
1693 struct rtw89_mcc_role *ref = &mcc->role_ref;
1694 struct rtw89_mcc_role *aux = &mcc->role_aux;
1695 struct rtw89_fw_mcc_duration req = {
1696 .group = mcc->group,
1697 .btc_in_group = false,
1698 .start_macid = ref->rtwvif->mac_id,
1699 .macid_x = ref->rtwvif->mac_id,
1700 .macid_y = aux->rtwvif->mac_id,
1701 .duration_x = ref->duration,
1702 .duration_y = aux->duration,
1703 .start_tsf_high = config->start_tsf >> 32,
1704 .start_tsf_low = config->start_tsf,
1705 };
1706 int ret;
1707
1708 ret = rtw89_fw_h2c_mcc_set_duration(rtwdev, p: &req);
1709 if (ret) {
1710 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1711 fmt: "MCC h2c failed to set duration: %d\n", ret);
1712 return ret;
1713 }
1714
1715 if (!sync->enable || !sync_changed)
1716 return 0;
1717
1718 ret = rtw89_fw_h2c_mcc_sync(rtwdev, group: mcc->group, source: sync->macid_src,
1719 target: sync->macid_tgt, offset: sync->offset);
1720 if (ret) {
1721 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1722 fmt: "MCC h2c failed to trigger sync: %d\n", ret);
1723 return ret;
1724 }
1725
1726 return 0;
1727}
1728
1729static int __mrc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
1730{
1731 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1732 struct rtw89_mcc_config *config = &mcc->config;
1733 struct rtw89_mcc_sync *sync = &config->sync;
1734 struct rtw89_mcc_role *ref = &mcc->role_ref;
1735 struct rtw89_mcc_role *aux = &mcc->role_aux;
1736 struct rtw89_fw_mrc_upd_duration_arg dur_arg = {
1737 .sch_idx = mcc->group,
1738 .start_tsf = config->start_tsf,
1739 .slot_num = 2,
1740 .slots[0] = {
1741 .slot_idx = ref->slot_idx,
1742 .duration = ref->duration,
1743 },
1744 .slots[1] = {
1745 .slot_idx = aux->slot_idx,
1746 .duration = aux->duration,
1747 },
1748 };
1749 struct rtw89_fw_mrc_sync_arg sync_arg = {
1750 .offset = sync->offset,
1751 .src = {
1752 .band = sync->band_src,
1753 .port = sync->port_src,
1754 },
1755 .dest = {
1756 .band = sync->band_tgt,
1757 .port = sync->port_tgt,
1758 },
1759
1760 };
1761 int ret;
1762
1763 ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, arg: &dur_arg);
1764 if (ret) {
1765 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1766 fmt: "MRC h2c failed to update duration: %d\n", ret);
1767 return ret;
1768 }
1769
1770 if (!sync->enable || !sync_changed)
1771 return 0;
1772
1773 ret = rtw89_fw_h2c_mrc_sync(rtwdev, arg: &sync_arg);
1774 if (ret) {
1775 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1776 fmt: "MRC h2c failed to trigger sync: %d\n", ret);
1777 return ret;
1778 }
1779
1780 return 0;
1781}
1782
1783static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
1784{
1785 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1786 struct rtw89_mcc_role *ref = &mcc->role_ref;
1787 struct rtw89_mcc_role *aux = &mcc->role_aux;
1788 struct rtw89_mcc_config *config = &mcc->config;
1789 struct rtw89_mcc_pattern *pattern = &config->pattern;
1790 struct rtw89_mcc_sync *sync = &config->sync;
1791 struct ieee80211_p2p_noa_desc noa_desc = {};
1792 u64 start_time = config->start_tsf;
1793 u32 interval = config->mcc_interval;
1794 struct rtw89_vif *rtwvif_go;
1795 u32 duration;
1796
1797 if (mcc->mode != RTW89_MCC_MODE_GO_STA)
1798 return;
1799
1800 if (ref->is_go) {
1801 rtwvif_go = ref->rtwvif;
1802 start_time += ieee80211_tu_to_usec(tu: ref->duration);
1803 duration = config->mcc_interval - ref->duration;
1804 } else if (aux->is_go) {
1805 rtwvif_go = aux->rtwvif;
1806 start_time += ieee80211_tu_to_usec(tu: pattern->tob_ref) +
1807 ieee80211_tu_to_usec(tu: config->beacon_offset) +
1808 ieee80211_tu_to_usec(tu: pattern->toa_aux);
1809 duration = config->mcc_interval - aux->duration;
1810
1811 /* convert time domain from sta(ref) to GO(aux) */
1812 start_time += ieee80211_tu_to_usec(tu: sync->offset);
1813 } else {
1814 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1815 fmt: "MCC find no GO: skip updating beacon NoA\n");
1816 return;
1817 }
1818
1819 rtw89_p2p_noa_renew(rtwvif: rtwvif_go);
1820
1821 if (enable) {
1822 noa_desc.start_time = cpu_to_le32(start_time);
1823 noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval));
1824 noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration));
1825 noa_desc.count = 255;
1826 rtw89_p2p_noa_append(rtwvif: rtwvif_go, desc: &noa_desc);
1827 }
1828
1829 /* without chanctx, we cannot get beacon from mac80211 stack */
1830 if (!rtwvif_go->chanctx_assigned)
1831 return;
1832
1833 rtw89_chip_h2c_update_beacon(rtwdev, rtwvif: rtwvif_go);
1834}
1835
1836static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev)
1837{
1838 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1839 struct rtw89_mcc_role *ref = &mcc->role_ref;
1840 struct rtw89_mcc_role *aux = &mcc->role_aux;
1841
1842 if (mcc->mode != RTW89_MCC_MODE_GO_STA)
1843 return;
1844
1845 if (ref->is_go)
1846 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif: ref->rtwvif, en: true);
1847 else if (aux->is_go)
1848 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif: aux->rtwvif, en: true);
1849
1850 rtw89_mcc_handle_beacon_noa(rtwdev, enable: true);
1851}
1852
1853static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)
1854{
1855 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1856 struct rtw89_mcc_role *ref = &mcc->role_ref;
1857 struct rtw89_mcc_role *aux = &mcc->role_aux;
1858
1859 if (mcc->mode != RTW89_MCC_MODE_GO_STA)
1860 return;
1861
1862 if (ref->is_go)
1863 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif: ref->rtwvif, en: false);
1864 else if (aux->is_go)
1865 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif: aux->rtwvif, en: false);
1866
1867 rtw89_mcc_handle_beacon_noa(rtwdev, enable: false);
1868}
1869
1870static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
1871{
1872 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1873 struct rtw89_mcc_role *ref = &mcc->role_ref;
1874 struct rtw89_mcc_role *aux = &mcc->role_aux;
1875 int ret;
1876
1877 if (rtwdev->scanning)
1878 rtw89_hw_scan_abort(rtwdev, vif: rtwdev->scan_info.scanning_vif);
1879
1880 rtw89_leave_lps(rtwdev);
1881
1882 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC start\n");
1883
1884 ret = rtw89_mcc_fill_all_roles(rtwdev);
1885 if (ret)
1886 return ret;
1887
1888 if (ref->is_go || aux->is_go)
1889 mcc->mode = RTW89_MCC_MODE_GO_STA;
1890 else
1891 mcc->mode = RTW89_MCC_MODE_GC_STA;
1892
1893 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC sel mode: %d\n", mcc->mode);
1894
1895 mcc->group = RTW89_MCC_DFLT_GROUP;
1896
1897 ret = rtw89_mcc_fill_config(rtwdev);
1898 if (ret)
1899 return ret;
1900
1901 if (rtw89_concurrent_via_mrc(rtwdev))
1902 ret = __mrc_fw_start(rtwdev, replace: false);
1903 else
1904 ret = __mcc_fw_start(rtwdev, replace: false);
1905
1906 if (ret)
1907 return ret;
1908
1909 rtw89_chanctx_notify(rtwdev, state: RTW89_CHANCTX_STATE_MCC_START);
1910
1911 rtw89_mcc_start_beacon_noa(rtwdev);
1912 return 0;
1913}
1914
1915static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
1916{
1917 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1918 struct rtw89_mcc_role *ref = &mcc->role_ref;
1919 int ret;
1920
1921 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC stop\n");
1922
1923 if (rtw89_concurrent_via_mrc(rtwdev)) {
1924 ret = rtw89_fw_h2c_mrc_del(rtwdev, sch_idx: mcc->group);
1925 if (ret)
1926 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1927 fmt: "MRC h2c failed to trigger del: %d\n", ret);
1928 } else {
1929 ret = rtw89_fw_h2c_stop_mcc(rtwdev, group: mcc->group,
1930 macid: ref->rtwvif->mac_id, prev_groups: true);
1931 if (ret)
1932 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1933 fmt: "MCC h2c failed to trigger stop: %d\n", ret);
1934
1935 ret = rtw89_fw_h2c_del_mcc_group(rtwdev, group: mcc->group, prev_groups: true);
1936 if (ret)
1937 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
1938 fmt: "MCC h2c failed to delete group: %d\n", ret);
1939 }
1940
1941 rtw89_chanctx_notify(rtwdev, state: RTW89_CHANCTX_STATE_MCC_STOP);
1942
1943 rtw89_mcc_stop_beacon_noa(rtwdev);
1944}
1945
1946static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
1947{
1948 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1949 struct rtw89_mcc_config *config = &mcc->config;
1950 struct rtw89_mcc_config old_cfg = *config;
1951 bool sync_changed;
1952 int ret;
1953
1954 if (rtwdev->scanning)
1955 rtw89_hw_scan_abort(rtwdev, vif: rtwdev->scan_info.scanning_vif);
1956
1957 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "MCC update\n");
1958
1959 ret = rtw89_mcc_fill_config(rtwdev);
1960 if (ret)
1961 return ret;
1962
1963 if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
1964 config->pattern.plan != RTW89_MCC_PLAN_NO_BT) {
1965 if (rtw89_concurrent_via_mrc(rtwdev))
1966 ret = __mrc_fw_start(rtwdev, replace: true);
1967 else
1968 ret = __mcc_fw_start(rtwdev, replace: true);
1969
1970 if (ret)
1971 return ret;
1972 } else {
1973 if (memcmp(p: &old_cfg.sync, q: &config->sync, size: sizeof(old_cfg.sync)) == 0)
1974 sync_changed = false;
1975 else
1976 sync_changed = true;
1977
1978 if (rtw89_concurrent_via_mrc(rtwdev))
1979 ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed);
1980 else
1981 ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
1982
1983 if (ret)
1984 return ret;
1985 }
1986
1987 rtw89_mcc_handle_beacon_noa(rtwdev, enable: true);
1988 return 0;
1989}
1990
1991static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
1992{
1993 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
1994 struct rtw89_mcc_config *config = &mcc->config;
1995 struct rtw89_mcc_pattern *pattern = &config->pattern;
1996 s16 tolerance;
1997 u16 bcn_ofst;
1998 u16 diff;
1999
2000 if (mcc->mode != RTW89_MCC_MODE_GC_STA)
2001 return;
2002
2003 bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
2004 if (bcn_ofst > config->beacon_offset) {
2005 diff = bcn_ofst - config->beacon_offset;
2006 if (pattern->tob_aux < 0)
2007 tolerance = -pattern->tob_aux;
2008 else
2009 tolerance = pattern->toa_aux;
2010 } else {
2011 diff = config->beacon_offset - bcn_ofst;
2012 if (pattern->toa_aux < 0)
2013 tolerance = -pattern->toa_aux;
2014 else
2015 tolerance = pattern->tob_aux;
2016 }
2017
2018 if (diff <= tolerance)
2019 return;
2020
2021 rtw89_queue_chanctx_change(rtwdev, change: RTW89_CHANCTX_BCN_OFFSET_CHANGE);
2022}
2023
2024static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
2025 struct rtw89_mcc_role *upd)
2026{
2027 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2028 int ret;
2029
2030 ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, group: mcc->group,
2031 macid: upd->rtwvif->mac_id,
2032 bitmap: upd->macid_bitmap);
2033 if (ret) {
2034 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
2035 fmt: "MCC h2c failed to update macid bitmap: %d\n", ret);
2036 return ret;
2037 }
2038
2039 return 0;
2040}
2041
2042static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
2043 struct rtw89_mcc_role *cur,
2044 struct rtw89_mcc_role *upd)
2045{
2046 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2047 struct rtw89_fw_mrc_upd_bitmap_arg arg = {};
2048 u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(mcc_role: cur);
2049 u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(mcc_role: upd);
2050 u32 add = new & ~old;
2051 u32 del = old & ~new;
2052 int ret;
2053 int i;
2054
2055 arg.sch_idx = mcc->group;
2056 arg.macid = upd->rtwvif->mac_id;
2057
2058 for (i = 0; i < 32; i++) {
2059 if (add & BIT(i)) {
2060 arg.client_macid = i;
2061 arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD;
2062
2063 ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, arg: &arg);
2064 if (ret)
2065 goto err;
2066 }
2067 }
2068
2069 for (i = 0; i < 32; i++) {
2070 if (del & BIT(i)) {
2071 arg.client_macid = i;
2072 arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL;
2073
2074 ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, arg: &arg);
2075 if (ret)
2076 goto err;
2077 }
2078 }
2079
2080 return 0;
2081
2082err:
2083 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
2084 fmt: "MRC h2c failed to update bitmap: %d\n", ret);
2085 return ret;
2086}
2087
2088static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
2089 struct rtw89_mcc_role *mcc_role,
2090 unsigned int ordered_idx,
2091 void *data)
2092{
2093 struct rtw89_mcc_role upd = {
2094 .rtwvif = mcc_role->rtwvif,
2095 };
2096 int ret;
2097
2098 if (!mcc_role->is_go)
2099 return 0;
2100
2101 rtw89_mcc_fill_role_macid_bitmap(rtwdev, mcc_role: &upd);
2102 if (memcmp(p: mcc_role->macid_bitmap, q: upd.macid_bitmap,
2103 size: sizeof(mcc_role->macid_bitmap)) == 0)
2104 return 0;
2105
2106 if (rtw89_concurrent_via_mrc(rtwdev))
2107 ret = __mrc_fw_upd_macid_bitmap(rtwdev, cur: mcc_role, upd: &upd);
2108 else
2109 ret = __mcc_fw_upd_macid_bitmap(rtwdev, upd: &upd);
2110
2111 if (ret)
2112 return ret;
2113
2114 memcpy(mcc_role->macid_bitmap, upd.macid_bitmap,
2115 sizeof(mcc_role->macid_bitmap));
2116 return 0;
2117}
2118
2119static void rtw89_mcc_update_macid_bitmap(struct rtw89_dev *rtwdev)
2120{
2121 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2122
2123 if (mcc->mode != RTW89_MCC_MODE_GO_STA)
2124 return;
2125
2126 rtw89_iterate_mcc_roles(rtwdev, iterator: rtw89_mcc_upd_map_iterator, NULL);
2127}
2128
2129static int rtw89_mcc_upd_lmt_iterator(struct rtw89_dev *rtwdev,
2130 struct rtw89_mcc_role *mcc_role,
2131 unsigned int ordered_idx,
2132 void *data)
2133{
2134 memset(&mcc_role->limit, 0, sizeof(mcc_role->limit));
2135 rtw89_mcc_fill_role_limit(rtwdev, mcc_role);
2136 return 0;
2137}
2138
2139static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev)
2140{
2141 struct rtw89_mcc_info *mcc = &rtwdev->mcc;
2142
2143 if (mcc->mode != RTW89_MCC_MODE_GC_STA)
2144 return;
2145
2146 rtw89_iterate_mcc_roles(rtwdev, iterator: rtw89_mcc_upd_lmt_iterator, NULL);
2147}
2148
2149void rtw89_chanctx_work(struct work_struct *work)
2150{
2151 struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
2152 chanctx_work.work);
2153 struct rtw89_hal *hal = &rtwdev->hal;
2154 bool update_mcc_pattern = false;
2155 enum rtw89_entity_mode mode;
2156 u32 changed = 0;
2157 int ret;
2158 int i;
2159
2160 mutex_lock(&rtwdev->mutex);
2161
2162 if (hal->entity_pause) {
2163 mutex_unlock(lock: &rtwdev->mutex);
2164 return;
2165 }
2166
2167 for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) {
2168 if (test_and_clear_bit(nr: i, addr: hal->changes))
2169 changed |= BIT(i);
2170 }
2171
2172 mode = rtw89_get_entity_mode(rtwdev);
2173 switch (mode) {
2174 case RTW89_ENTITY_MODE_MCC_PREPARE:
2175 rtw89_set_entity_mode(rtwdev, mode: RTW89_ENTITY_MODE_MCC);
2176 rtw89_set_channel(rtwdev);
2177
2178 ret = rtw89_mcc_start(rtwdev);
2179 if (ret)
2180 rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
2181 break;
2182 case RTW89_ENTITY_MODE_MCC:
2183 if (changed & BIT(RTW89_CHANCTX_BCN_OFFSET_CHANGE) ||
2184 changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE) ||
2185 changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE) ||
2186 changed & BIT(RTW89_CHANCTX_TSF32_TOGGLE_CHANGE))
2187 update_mcc_pattern = true;
2188 if (changed & BIT(RTW89_CHANCTX_REMOTE_STA_CHANGE))
2189 rtw89_mcc_update_macid_bitmap(rtwdev);
2190 if (changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE))
2191 rtw89_mcc_update_limit(rtwdev);
2192 if (changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE))
2193 rtw89_mcc_fill_bt_role(rtwdev);
2194 if (update_mcc_pattern) {
2195 ret = rtw89_mcc_update(rtwdev);
2196 if (ret)
2197 rtw89_warn(rtwdev, "failed to update MCC: %d\n",
2198 ret);
2199 }
2200 break;
2201 default:
2202 break;
2203 }
2204
2205 mutex_unlock(lock: &rtwdev->mutex);
2206}
2207
2208void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
2209 enum rtw89_chanctx_changes change)
2210{
2211 struct rtw89_hal *hal = &rtwdev->hal;
2212 enum rtw89_entity_mode mode;
2213 u32 delay;
2214
2215 mode = rtw89_get_entity_mode(rtwdev);
2216 switch (mode) {
2217 default:
2218 return;
2219 case RTW89_ENTITY_MODE_MCC_PREPARE:
2220 delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
2221 break;
2222 case RTW89_ENTITY_MODE_MCC:
2223 delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC);
2224 break;
2225 }
2226
2227 if (change != RTW89_CHANCTX_CHANGE_DFLT) {
2228 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "set chanctx change %d\n",
2229 change);
2230 set_bit(nr: change, addr: hal->changes);
2231 }
2232
2233 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN,
2234 fmt: "queue chanctx work for mode %d with delay %d us\n",
2235 mode, delay);
2236 ieee80211_queue_delayed_work(hw: rtwdev->hw, dwork: &rtwdev->chanctx_work,
2237 delay: usecs_to_jiffies(u: delay));
2238}
2239
2240void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
2241{
2242 rtw89_queue_chanctx_change(rtwdev, change: RTW89_CHANCTX_CHANGE_DFLT);
2243}
2244
2245void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
2246{
2247 struct rtw89_hal *hal = &rtwdev->hal;
2248 enum rtw89_entity_mode mode;
2249
2250 lockdep_assert_held(&rtwdev->mutex);
2251
2252 if (hal->entity_pause)
2253 return;
2254
2255 mode = rtw89_get_entity_mode(rtwdev);
2256 switch (mode) {
2257 case RTW89_ENTITY_MODE_MCC:
2258 rtw89_mcc_track(rtwdev);
2259 break;
2260 default:
2261 break;
2262 }
2263}
2264
2265void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
2266 enum rtw89_chanctx_pause_reasons rsn)
2267{
2268 struct rtw89_hal *hal = &rtwdev->hal;
2269 enum rtw89_entity_mode mode;
2270
2271 lockdep_assert_held(&rtwdev->mutex);
2272
2273 if (hal->entity_pause)
2274 return;
2275
2276 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "chanctx pause (rsn: %d)\n", rsn);
2277
2278 mode = rtw89_get_entity_mode(rtwdev);
2279 switch (mode) {
2280 case RTW89_ENTITY_MODE_MCC:
2281 rtw89_mcc_stop(rtwdev);
2282 break;
2283 default:
2284 break;
2285 }
2286
2287 hal->entity_pause = true;
2288}
2289
2290void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev)
2291{
2292 struct rtw89_hal *hal = &rtwdev->hal;
2293 enum rtw89_entity_mode mode;
2294 int ret;
2295
2296 lockdep_assert_held(&rtwdev->mutex);
2297
2298 if (!hal->entity_pause)
2299 return;
2300
2301 rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, fmt: "chanctx proceed\n");
2302
2303 hal->entity_pause = false;
2304 rtw89_set_channel(rtwdev);
2305
2306 mode = rtw89_get_entity_mode(rtwdev);
2307 switch (mode) {
2308 case RTW89_ENTITY_MODE_MCC:
2309 ret = rtw89_mcc_start(rtwdev);
2310 if (ret)
2311 rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
2312 break;
2313 default:
2314 break;
2315 }
2316
2317 rtw89_queue_chanctx_work(rtwdev);
2318}
2319
2320static void rtw89_swap_sub_entity(struct rtw89_dev *rtwdev,
2321 enum rtw89_sub_entity_idx idx1,
2322 enum rtw89_sub_entity_idx idx2)
2323{
2324 struct rtw89_hal *hal = &rtwdev->hal;
2325 struct rtw89_sub_entity tmp;
2326 struct rtw89_vif *rtwvif;
2327 u8 cur;
2328
2329 if (idx1 == idx2)
2330 return;
2331
2332 hal->sub[idx1].cfg->idx = idx2;
2333 hal->sub[idx2].cfg->idx = idx1;
2334
2335 tmp = hal->sub[idx1];
2336 hal->sub[idx1] = hal->sub[idx2];
2337 hal->sub[idx2] = tmp;
2338
2339 rtw89_for_each_rtwvif(rtwdev, rtwvif) {
2340 if (!rtwvif->chanctx_assigned)
2341 continue;
2342 if (rtwvif->sub_entity_idx == idx1)
2343 rtwvif->sub_entity_idx = idx2;
2344 else if (rtwvif->sub_entity_idx == idx2)
2345 rtwvif->sub_entity_idx = idx1;
2346 }
2347
2348 cur = atomic_read(v: &hal->roc_entity_idx);
2349 if (cur == idx1)
2350 atomic_set(v: &hal->roc_entity_idx, i: idx2);
2351 else if (cur == idx2)
2352 atomic_set(v: &hal->roc_entity_idx, i: idx1);
2353}
2354
2355int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
2356 struct ieee80211_chanctx_conf *ctx)
2357{
2358 struct rtw89_hal *hal = &rtwdev->hal;
2359 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2360 const struct rtw89_chip_info *chip = rtwdev->chip;
2361 u8 idx;
2362
2363 idx = find_first_zero_bit(addr: hal->entity_map, size: NUM_OF_RTW89_SUB_ENTITY);
2364 if (idx >= chip->support_chanctx_num)
2365 return -ENOENT;
2366
2367 rtw89_config_entity_chandef(rtwdev, idx, chandef: &ctx->def);
2368 cfg->idx = idx;
2369 cfg->ref_count = 0;
2370 hal->sub[idx].cfg = cfg;
2371 return 0;
2372}
2373
2374void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
2375 struct ieee80211_chanctx_conf *ctx)
2376{
2377 struct rtw89_hal *hal = &rtwdev->hal;
2378 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2379
2380 clear_bit(nr: cfg->idx, addr: hal->entity_map);
2381}
2382
2383void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
2384 struct ieee80211_chanctx_conf *ctx,
2385 u32 changed)
2386{
2387 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2388 u8 idx = cfg->idx;
2389
2390 if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
2391 rtw89_config_entity_chandef(rtwdev, idx, chandef: &ctx->def);
2392 rtw89_set_channel(rtwdev);
2393 }
2394}
2395
2396int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
2397 struct rtw89_vif *rtwvif,
2398 struct ieee80211_chanctx_conf *ctx)
2399{
2400 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2401 struct rtw89_entity_weight w = {};
2402
2403 rtwvif->sub_entity_idx = cfg->idx;
2404 rtwvif->chanctx_assigned = true;
2405 cfg->ref_count++;
2406
2407 if (cfg->idx == RTW89_SUB_ENTITY_0)
2408 goto out;
2409
2410 rtw89_entity_calculate_weight(rtwdev, w: &w);
2411 if (w.active_chanctxs != 1)
2412 goto out;
2413
2414 /* put the first active chanctx at RTW89_SUB_ENTITY_0 */
2415 rtw89_swap_sub_entity(rtwdev, idx1: cfg->idx, idx2: RTW89_SUB_ENTITY_0);
2416
2417out:
2418 return rtw89_set_channel(rtwdev);
2419}
2420
2421void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
2422 struct rtw89_vif *rtwvif,
2423 struct ieee80211_chanctx_conf *ctx)
2424{
2425 struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2426 struct rtw89_hal *hal = &rtwdev->hal;
2427 struct rtw89_entity_weight w = {};
2428 enum rtw89_sub_entity_idx roll;
2429 enum rtw89_entity_mode cur;
2430
2431 rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
2432 rtwvif->chanctx_assigned = false;
2433 cfg->ref_count--;
2434
2435 if (cfg->ref_count != 0)
2436 goto out;
2437
2438 if (cfg->idx != RTW89_SUB_ENTITY_0)
2439 goto out;
2440
2441 roll = find_next_bit(addr: hal->entity_map, size: NUM_OF_RTW89_SUB_ENTITY,
2442 offset: cfg->idx + 1);
2443 /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
2444 if (roll == NUM_OF_RTW89_SUB_ENTITY)
2445 goto out;
2446
2447 /* RTW89_SUB_ENTITY_0 is going to release, and another exists.
2448 * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
2449 */
2450 rtw89_swap_sub_entity(rtwdev, idx1: cfg->idx, idx2: roll);
2451
2452out:
2453 rtw89_entity_calculate_weight(rtwdev, w: &w);
2454
2455 cur = rtw89_get_entity_mode(rtwdev);
2456 switch (cur) {
2457 case RTW89_ENTITY_MODE_MCC:
2458 /* If still multi-roles, re-plan MCC for chanctx changes.
2459 * Otherwise, just stop MCC.
2460 */
2461 rtw89_mcc_stop(rtwdev);
2462 if (w.active_roles == NUM_OF_RTW89_MCC_ROLES)
2463 rtw89_mcc_start(rtwdev);
2464 break;
2465 default:
2466 break;
2467 }
2468
2469 rtw89_set_channel(rtwdev);
2470}
2471

source code of linux/drivers/net/wireless/realtek/rtw89/chan.c