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 | |
13 | static 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 | |
57 | static 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 | |
90 | static 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 | |
103 | void 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 | |
126 | bool 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 | |
144 | static 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 | |
157 | void 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 | |
164 | void 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 | |
196 | static 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 | |
204 | void 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 | |
215 | static 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 | |
241 | enum 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 | |
303 | static 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 | |
325 | static 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 | */ |
338 | static |
339 | int 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 | |
365 | static 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 | |
384 | static 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 | |
409 | static 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 | |
439 | static 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 | |
466 | static |
467 | void 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 | |
479 | static |
480 | u32 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 | |
497 | out: |
498 | return bitmap; |
499 | } |
500 | |
501 | static 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 | |
514 | static 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 | |
525 | static 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 | |
542 | static 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 | |
566 | fill: |
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 | |
612 | static 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 | |
646 | static 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 | |
658 | struct rtw89_mcc_fill_role_selector { |
659 | struct rtw89_vif *bind_vif[NUM_OF_RTW89_SUB_ENTITY]; |
660 | }; |
661 | |
662 | static_assert((u8)NUM_OF_RTW89_SUB_ENTITY >= NUM_OF_RTW89_MCC_ROLES); |
663 | |
664 | static 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 | |
690 | static 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 | |
718 | static 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 | */ |
773 | static 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 | |
807 | calc: |
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 | */ |
838 | static 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 | |
925 | static 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 | |
980 | done: |
981 | rtw89_mcc_assign_pattern(rtwdev, new: &ptrn); |
982 | return 0; |
983 | } |
984 | |
985 | static 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 | |
1004 | static 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 | |
1027 | static 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 | |
1063 | struct 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 | |
1071 | static 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 | |
1097 | static 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 | |
1112 | static 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 | |
1144 | static |
1145 | void 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 | |
1193 | static 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 | |
1228 | static 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 | |
1279 | static 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 | |
1313 | static 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 | |
1356 | bottom: |
1357 | return rtw89_mcc_fill_start_tsf(rtwdev); |
1358 | } |
1359 | |
1360 | static 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 | |
1413 | static |
1414 | void __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 | |
1444 | static 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 | |
1465 | static |
1466 | void __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 | |
1479 | static 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 | |
1564 | static 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 | |
1592 | static 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 | |
1688 | static 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 | |
1729 | static 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 | |
1783 | static 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 | |
1836 | static 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 | |
1853 | static 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 | |
1870 | static 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 | |
1915 | static 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 | |
1946 | static 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 | |
1991 | static 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 | |
2024 | static 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 | |
2042 | static 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 | |
2082 | err: |
2083 | rtw89_debug(rtwdev, mask: RTW89_DBG_CHAN, |
2084 | fmt: "MRC h2c failed to update bitmap: %d\n" , ret); |
2085 | return ret; |
2086 | } |
2087 | |
2088 | static 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 | |
2119 | static 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 | |
2129 | static 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 | |
2139 | static 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 | |
2149 | void 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 | |
2208 | void 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 | |
2240 | void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) |
2241 | { |
2242 | rtw89_queue_chanctx_change(rtwdev, change: RTW89_CHANCTX_CHANGE_DFLT); |
2243 | } |
2244 | |
2245 | void 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 | |
2265 | void 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 | |
2290 | void 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 | |
2320 | static 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 | |
2355 | int 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 | |
2374 | void 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 | |
2383 | void 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 | |
2396 | int 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 | |
2417 | out: |
2418 | return rtw89_set_channel(rtwdev); |
2419 | } |
2420 | |
2421 | void 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 | |
2452 | out: |
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 | |