18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2020-2022 Realtek Corporation
38e93258fSBjoern A. Zeeb */
48e93258fSBjoern A. Zeeb
58e93258fSBjoern A. Zeeb #include "chan.h"
66d67aabdSBjoern A. Zeeb #include "coex.h"
78e93258fSBjoern A. Zeeb #include "debug.h"
86d67aabdSBjoern A. Zeeb #include "fw.h"
96d67aabdSBjoern A. Zeeb #include "mac.h"
106d67aabdSBjoern A. Zeeb #include "ps.h"
11e2340276SBjoern A. Zeeb #include "util.h"
128e93258fSBjoern A. Zeeb
13df279a26SBjoern A. Zeeb static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
14df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx1,
15df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx2);
16df279a26SBjoern A. Zeeb
rtw89_get_subband_type(enum rtw89_band band,u8 center_chan)178e93258fSBjoern A. Zeeb static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
188e93258fSBjoern A. Zeeb u8 center_chan)
198e93258fSBjoern A. Zeeb {
208e93258fSBjoern A. Zeeb switch (band) {
218e93258fSBjoern A. Zeeb default:
228e93258fSBjoern A. Zeeb case RTW89_BAND_2G:
238e93258fSBjoern A. Zeeb switch (center_chan) {
248e93258fSBjoern A. Zeeb default:
258e93258fSBjoern A. Zeeb case 1 ... 14:
268e93258fSBjoern A. Zeeb return RTW89_CH_2G;
278e93258fSBjoern A. Zeeb }
288e93258fSBjoern A. Zeeb case RTW89_BAND_5G:
298e93258fSBjoern A. Zeeb switch (center_chan) {
308e93258fSBjoern A. Zeeb default:
318e93258fSBjoern A. Zeeb case 36 ... 64:
328e93258fSBjoern A. Zeeb return RTW89_CH_5G_BAND_1;
338e93258fSBjoern A. Zeeb case 100 ... 144:
348e93258fSBjoern A. Zeeb return RTW89_CH_5G_BAND_3;
358e93258fSBjoern A. Zeeb case 149 ... 177:
368e93258fSBjoern A. Zeeb return RTW89_CH_5G_BAND_4;
378e93258fSBjoern A. Zeeb }
388e93258fSBjoern A. Zeeb case RTW89_BAND_6G:
398e93258fSBjoern A. Zeeb switch (center_chan) {
408e93258fSBjoern A. Zeeb default:
418e93258fSBjoern A. Zeeb case 1 ... 29:
428e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX0;
438e93258fSBjoern A. Zeeb case 33 ... 61:
448e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX1;
458e93258fSBjoern A. Zeeb case 65 ... 93:
468e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX2;
478e93258fSBjoern A. Zeeb case 97 ... 125:
488e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX3;
498e93258fSBjoern A. Zeeb case 129 ... 157:
508e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX4;
518e93258fSBjoern A. Zeeb case 161 ... 189:
528e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX5;
538e93258fSBjoern A. Zeeb case 193 ... 221:
548e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX6;
558e93258fSBjoern A. Zeeb case 225 ... 253:
568e93258fSBjoern A. Zeeb return RTW89_CH_6G_BAND_IDX7;
578e93258fSBjoern A. Zeeb }
588e93258fSBjoern A. Zeeb }
598e93258fSBjoern A. Zeeb }
608e93258fSBjoern A. Zeeb
rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,u32 center_freq,u32 primary_freq)618e93258fSBjoern A. Zeeb static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
628e93258fSBjoern A. Zeeb u32 center_freq,
638e93258fSBjoern A. Zeeb u32 primary_freq)
648e93258fSBjoern A. Zeeb {
658e93258fSBjoern A. Zeeb u8 primary_chan_idx;
668e93258fSBjoern A. Zeeb u32 offset;
678e93258fSBjoern A. Zeeb
688e93258fSBjoern A. Zeeb switch (bw) {
698e93258fSBjoern A. Zeeb default:
708e93258fSBjoern A. Zeeb case RTW89_CHANNEL_WIDTH_20:
718e93258fSBjoern A. Zeeb primary_chan_idx = RTW89_SC_DONT_CARE;
728e93258fSBjoern A. Zeeb break;
738e93258fSBjoern A. Zeeb case RTW89_CHANNEL_WIDTH_40:
748e93258fSBjoern A. Zeeb if (primary_freq > center_freq)
758e93258fSBjoern A. Zeeb primary_chan_idx = RTW89_SC_20_UPPER;
768e93258fSBjoern A. Zeeb else
778e93258fSBjoern A. Zeeb primary_chan_idx = RTW89_SC_20_LOWER;
788e93258fSBjoern A. Zeeb break;
798e93258fSBjoern A. Zeeb case RTW89_CHANNEL_WIDTH_80:
808e93258fSBjoern A. Zeeb case RTW89_CHANNEL_WIDTH_160:
818e93258fSBjoern A. Zeeb if (primary_freq > center_freq) {
828e93258fSBjoern A. Zeeb offset = (primary_freq - center_freq - 10) / 20;
838e93258fSBjoern A. Zeeb primary_chan_idx = RTW89_SC_20_UPPER + offset * 2;
848e93258fSBjoern A. Zeeb } else {
858e93258fSBjoern A. Zeeb offset = (center_freq - primary_freq - 10) / 20;
868e93258fSBjoern A. Zeeb primary_chan_idx = RTW89_SC_20_LOWER + offset * 2;
878e93258fSBjoern A. Zeeb }
888e93258fSBjoern A. Zeeb break;
898e93258fSBjoern A. Zeeb }
908e93258fSBjoern A. Zeeb
918e93258fSBjoern A. Zeeb return primary_chan_idx;
928e93258fSBjoern A. Zeeb }
938e93258fSBjoern A. Zeeb
rtw89_get_primary_sb_idx(u8 central_ch,u8 pri_ch,enum rtw89_bandwidth bw)946d67aabdSBjoern A. Zeeb static u8 rtw89_get_primary_sb_idx(u8 central_ch, u8 pri_ch,
956d67aabdSBjoern A. Zeeb enum rtw89_bandwidth bw)
966d67aabdSBjoern A. Zeeb {
976d67aabdSBjoern A. Zeeb static const u8 prisb_cal_ofst[RTW89_CHANNEL_WIDTH_ORDINARY_NUM] = {
986d67aabdSBjoern A. Zeeb 0, 2, 6, 14, 30
996d67aabdSBjoern A. Zeeb };
1006d67aabdSBjoern A. Zeeb
1016d67aabdSBjoern A. Zeeb if (bw >= RTW89_CHANNEL_WIDTH_ORDINARY_NUM)
1026d67aabdSBjoern A. Zeeb return 0;
1036d67aabdSBjoern A. Zeeb
1046d67aabdSBjoern A. Zeeb return (prisb_cal_ofst[bw] + pri_ch - central_ch) / 4;
1056d67aabdSBjoern A. Zeeb }
1066d67aabdSBjoern A. Zeeb
rtw89_chan_create(struct rtw89_chan * chan,u8 center_chan,u8 primary_chan,enum rtw89_band band,enum rtw89_bandwidth bandwidth)1078e93258fSBjoern A. Zeeb void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
1088e93258fSBjoern A. Zeeb enum rtw89_band band, enum rtw89_bandwidth bandwidth)
1098e93258fSBjoern A. Zeeb {
1108e93258fSBjoern A. Zeeb enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
1118e93258fSBjoern A. Zeeb u32 center_freq, primary_freq;
1128e93258fSBjoern A. Zeeb
1138e93258fSBjoern A. Zeeb memset(chan, 0, sizeof(*chan));
1148e93258fSBjoern A. Zeeb chan->channel = center_chan;
1158e93258fSBjoern A. Zeeb chan->primary_channel = primary_chan;
1168e93258fSBjoern A. Zeeb chan->band_type = band;
1178e93258fSBjoern A. Zeeb chan->band_width = bandwidth;
1188e93258fSBjoern A. Zeeb
1198e93258fSBjoern A. Zeeb center_freq = ieee80211_channel_to_frequency(center_chan, nl_band);
1208e93258fSBjoern A. Zeeb primary_freq = ieee80211_channel_to_frequency(primary_chan, nl_band);
1218e93258fSBjoern A. Zeeb
1228e93258fSBjoern A. Zeeb chan->freq = center_freq;
1238e93258fSBjoern A. Zeeb chan->subband_type = rtw89_get_subband_type(band, center_chan);
1248e93258fSBjoern A. Zeeb chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq,
1258e93258fSBjoern A. Zeeb primary_freq);
1266d67aabdSBjoern A. Zeeb chan->pri_sb_idx = rtw89_get_primary_sb_idx(center_chan, primary_chan,
1276d67aabdSBjoern A. Zeeb bandwidth);
1288e93258fSBjoern A. Zeeb }
1298e93258fSBjoern A. Zeeb
rtw89_assign_entity_chan(struct rtw89_dev * rtwdev,enum rtw89_chanctx_idx idx,const struct rtw89_chan * new)1308e93258fSBjoern A. Zeeb bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
131df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx,
1328e93258fSBjoern A. Zeeb const struct rtw89_chan *new)
1338e93258fSBjoern A. Zeeb {
1348e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
135df279a26SBjoern A. Zeeb struct rtw89_chan *chan = &hal->chanctx[idx].chan;
136df279a26SBjoern A. Zeeb struct rtw89_chan_rcd *rcd = &hal->chanctx[idx].rcd;
1378e93258fSBjoern A. Zeeb bool band_changed;
1388e93258fSBjoern A. Zeeb
1398e93258fSBjoern A. Zeeb rcd->prev_primary_channel = chan->primary_channel;
1408e93258fSBjoern A. Zeeb rcd->prev_band_type = chan->band_type;
1418e93258fSBjoern A. Zeeb band_changed = new->band_type != chan->band_type;
1426d67aabdSBjoern A. Zeeb rcd->band_changed = band_changed;
1438e93258fSBjoern A. Zeeb
1448e93258fSBjoern A. Zeeb *chan = *new;
1458e93258fSBjoern A. Zeeb return band_changed;
1468e93258fSBjoern A. Zeeb }
1478e93258fSBjoern A. Zeeb
rtw89_iterate_entity_chan(struct rtw89_dev * rtwdev,int (* iterator)(const struct rtw89_chan * chan,void * data),void * data)1486d67aabdSBjoern A. Zeeb int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,
1496d67aabdSBjoern A. Zeeb int (*iterator)(const struct rtw89_chan *chan,
1506d67aabdSBjoern A. Zeeb void *data),
1516d67aabdSBjoern A. Zeeb void *data)
1526d67aabdSBjoern A. Zeeb {
1536d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
1546d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan;
1556d67aabdSBjoern A. Zeeb int ret;
1566d67aabdSBjoern A. Zeeb u8 idx;
1576d67aabdSBjoern A. Zeeb
1586d67aabdSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
1596d67aabdSBjoern A. Zeeb
160df279a26SBjoern A. Zeeb for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) {
1616d67aabdSBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, idx);
1626d67aabdSBjoern A. Zeeb ret = iterator(chan, data);
1636d67aabdSBjoern A. Zeeb if (ret)
1646d67aabdSBjoern A. Zeeb return ret;
1656d67aabdSBjoern A. Zeeb }
1666d67aabdSBjoern A. Zeeb
1676d67aabdSBjoern A. Zeeb return 0;
1686d67aabdSBjoern A. Zeeb }
1696d67aabdSBjoern A. Zeeb
__rtw89_config_entity_chandef(struct rtw89_dev * rtwdev,enum rtw89_chanctx_idx idx,const struct cfg80211_chan_def * chandef,bool from_stack)1708e93258fSBjoern A. Zeeb static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
171df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx,
1728e93258fSBjoern A. Zeeb const struct cfg80211_chan_def *chandef,
1738e93258fSBjoern A. Zeeb bool from_stack)
1748e93258fSBjoern A. Zeeb {
1758e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
1768e93258fSBjoern A. Zeeb
177df279a26SBjoern A. Zeeb hal->chanctx[idx].chandef = *chandef;
1788e93258fSBjoern A. Zeeb
1798e93258fSBjoern A. Zeeb if (from_stack)
1808e93258fSBjoern A. Zeeb set_bit(idx, hal->entity_map);
1818e93258fSBjoern A. Zeeb }
1828e93258fSBjoern A. Zeeb
rtw89_config_entity_chandef(struct rtw89_dev * rtwdev,enum rtw89_chanctx_idx idx,const struct cfg80211_chan_def * chandef)1838e93258fSBjoern A. Zeeb void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
184df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx,
1858e93258fSBjoern A. Zeeb const struct cfg80211_chan_def *chandef)
1868e93258fSBjoern A. Zeeb {
1878e93258fSBjoern A. Zeeb __rtw89_config_entity_chandef(rtwdev, idx, chandef, true);
1888e93258fSBjoern A. Zeeb }
1898e93258fSBjoern A. Zeeb
rtw89_config_roc_chandef(struct rtw89_dev * rtwdev,enum rtw89_chanctx_idx idx,const struct cfg80211_chan_def * chandef)190e2340276SBjoern A. Zeeb void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
191df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx,
192e2340276SBjoern A. Zeeb const struct cfg80211_chan_def *chandef)
193e2340276SBjoern A. Zeeb {
194e2340276SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
195df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx cur;
196e2340276SBjoern A. Zeeb
197e2340276SBjoern A. Zeeb if (chandef) {
198df279a26SBjoern A. Zeeb cur = atomic_cmpxchg(&hal->roc_chanctx_idx,
199df279a26SBjoern A. Zeeb RTW89_CHANCTX_IDLE, idx);
200df279a26SBjoern A. Zeeb if (cur != RTW89_CHANCTX_IDLE) {
201e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
202e2340276SBjoern A. Zeeb "ROC still processing on entity %d\n", idx);
203e2340276SBjoern A. Zeeb return;
204e2340276SBjoern A. Zeeb }
205e2340276SBjoern A. Zeeb
206e2340276SBjoern A. Zeeb hal->roc_chandef = *chandef;
207e2340276SBjoern A. Zeeb } else {
208df279a26SBjoern A. Zeeb cur = atomic_cmpxchg(&hal->roc_chanctx_idx, idx,
209df279a26SBjoern A. Zeeb RTW89_CHANCTX_IDLE);
210e2340276SBjoern A. Zeeb if (cur == idx)
211e2340276SBjoern A. Zeeb return;
212e2340276SBjoern A. Zeeb
213df279a26SBjoern A. Zeeb if (cur == RTW89_CHANCTX_IDLE)
214e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
215e2340276SBjoern A. Zeeb "ROC already finished on entity %d\n", idx);
216e2340276SBjoern A. Zeeb else
217e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
218e2340276SBjoern A. Zeeb "ROC is processing on entity %d\n", cur);
219e2340276SBjoern A. Zeeb }
220e2340276SBjoern A. Zeeb }
221e2340276SBjoern A. Zeeb
rtw89_config_default_chandef(struct rtw89_dev * rtwdev)2228e93258fSBjoern A. Zeeb static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
2238e93258fSBjoern A. Zeeb {
2248e93258fSBjoern A. Zeeb struct cfg80211_chan_def chandef = {0};
2258e93258fSBjoern A. Zeeb
2268e93258fSBjoern A. Zeeb rtw89_get_default_chandef(&chandef);
227df279a26SBjoern A. Zeeb __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef, false);
2288e93258fSBjoern A. Zeeb }
2298e93258fSBjoern A. Zeeb
rtw89_entity_init(struct rtw89_dev * rtwdev)2308e93258fSBjoern A. Zeeb void rtw89_entity_init(struct rtw89_dev *rtwdev)
2318e93258fSBjoern A. Zeeb {
2328e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
233df279a26SBjoern A. Zeeb struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
2348e93258fSBjoern A. Zeeb
2356d67aabdSBjoern A. Zeeb hal->entity_pause = false;
236df279a26SBjoern A. Zeeb bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX);
2376d67aabdSBjoern A. Zeeb bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
238df279a26SBjoern A. Zeeb atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE);
239df279a26SBjoern A. Zeeb
240df279a26SBjoern A. Zeeb INIT_LIST_HEAD(&mgnt->active_list);
241df279a26SBjoern A. Zeeb
2428e93258fSBjoern A. Zeeb rtw89_config_default_chandef(rtwdev);
2438e93258fSBjoern A. Zeeb }
2448e93258fSBjoern A. Zeeb
rtw89_vif_is_active_role(struct rtw89_vif * rtwvif)245df279a26SBjoern A. Zeeb static bool rtw89_vif_is_active_role(struct rtw89_vif *rtwvif)
246df279a26SBjoern A. Zeeb {
247df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link;
248df279a26SBjoern A. Zeeb unsigned int link_id;
249df279a26SBjoern A. Zeeb
250df279a26SBjoern A. Zeeb rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
251df279a26SBjoern A. Zeeb if (rtwvif_link->chanctx_assigned)
252df279a26SBjoern A. Zeeb return true;
253df279a26SBjoern A. Zeeb
254df279a26SBjoern A. Zeeb return false;
255df279a26SBjoern A. Zeeb }
256df279a26SBjoern A. Zeeb
rtw89_entity_calculate_weight(struct rtw89_dev * rtwdev,struct rtw89_entity_weight * w)2576d67aabdSBjoern A. Zeeb static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
2586d67aabdSBjoern A. Zeeb struct rtw89_entity_weight *w)
2598e93258fSBjoern A. Zeeb {
2608e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
2616d67aabdSBjoern A. Zeeb const struct rtw89_chanctx_cfg *cfg;
2626d67aabdSBjoern A. Zeeb struct rtw89_vif *rtwvif;
2636d67aabdSBjoern A. Zeeb int idx;
2648e93258fSBjoern A. Zeeb
265df279a26SBjoern A. Zeeb for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) {
266df279a26SBjoern A. Zeeb cfg = hal->chanctx[idx].cfg;
2676d67aabdSBjoern A. Zeeb if (!cfg) {
2686d67aabdSBjoern A. Zeeb /* doesn't run with chanctx ops; one channel at most */
2696d67aabdSBjoern A. Zeeb w->active_chanctxs = 1;
2706d67aabdSBjoern A. Zeeb break;
2716d67aabdSBjoern A. Zeeb }
2726d67aabdSBjoern A. Zeeb
2736d67aabdSBjoern A. Zeeb if (cfg->ref_count > 0)
2746d67aabdSBjoern A. Zeeb w->active_chanctxs++;
2756d67aabdSBjoern A. Zeeb }
2766d67aabdSBjoern A. Zeeb
2776d67aabdSBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, rtwvif) {
278df279a26SBjoern A. Zeeb if (rtw89_vif_is_active_role(rtwvif))
2796d67aabdSBjoern A. Zeeb w->active_roles++;
2806d67aabdSBjoern A. Zeeb }
2816d67aabdSBjoern A. Zeeb }
2826d67aabdSBjoern A. Zeeb
rtw89_normalize_link_chanctx(struct rtw89_dev * rtwdev,struct rtw89_vif_link * rtwvif_link)283df279a26SBjoern A. Zeeb static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
284df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link)
285df279a26SBjoern A. Zeeb {
286df279a26SBjoern A. Zeeb struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
287df279a26SBjoern A. Zeeb struct rtw89_vif_link *cur;
288df279a26SBjoern A. Zeeb
289df279a26SBjoern A. Zeeb if (unlikely(!rtwvif_link->chanctx_assigned))
290df279a26SBjoern A. Zeeb return;
291df279a26SBjoern A. Zeeb
292df279a26SBjoern A. Zeeb cur = rtw89_vif_get_link_inst(rtwvif, 0);
293df279a26SBjoern A. Zeeb if (!cur || !cur->chanctx_assigned)
294df279a26SBjoern A. Zeeb return;
295df279a26SBjoern A. Zeeb
296df279a26SBjoern A. Zeeb if (cur == rtwvif_link)
297df279a26SBjoern A. Zeeb return;
298df279a26SBjoern A. Zeeb
299df279a26SBjoern A. Zeeb rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx);
300df279a26SBjoern A. Zeeb }
301df279a26SBjoern A. Zeeb
__rtw89_mgnt_chan_get(struct rtw89_dev * rtwdev,const char * caller_message,u8 link_index)302df279a26SBjoern A. Zeeb const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
303df279a26SBjoern A. Zeeb const char *caller_message,
304df279a26SBjoern A. Zeeb u8 link_index)
305df279a26SBjoern A. Zeeb {
306df279a26SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
307df279a26SBjoern A. Zeeb struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
308df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx chanctx_idx;
309df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx roc_idx;
310df279a26SBjoern A. Zeeb enum rtw89_entity_mode mode;
311df279a26SBjoern A. Zeeb u8 role_index;
312df279a26SBjoern A. Zeeb
313df279a26SBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
314df279a26SBjoern A. Zeeb
315df279a26SBjoern A. Zeeb if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) {
316df279a26SBjoern A. Zeeb WARN(1, "link index %u is invalid (max link inst num: %d)\n",
317df279a26SBjoern A. Zeeb link_index, __RTW89_MLD_MAX_LINK_NUM);
318df279a26SBjoern A. Zeeb goto dflt;
319df279a26SBjoern A. Zeeb }
320df279a26SBjoern A. Zeeb
321df279a26SBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
322df279a26SBjoern A. Zeeb switch (mode) {
323df279a26SBjoern A. Zeeb case RTW89_ENTITY_MODE_SCC_OR_SMLD:
324df279a26SBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
325df279a26SBjoern A. Zeeb role_index = 0;
326df279a26SBjoern A. Zeeb break;
327df279a26SBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC_PREPARE:
328df279a26SBjoern A. Zeeb role_index = 1;
329df279a26SBjoern A. Zeeb break;
330df279a26SBjoern A. Zeeb default:
331df279a26SBjoern A. Zeeb WARN(1, "Invalid ent mode: %d\n", mode);
332df279a26SBjoern A. Zeeb goto dflt;
333df279a26SBjoern A. Zeeb }
334df279a26SBjoern A. Zeeb
335df279a26SBjoern A. Zeeb chanctx_idx = mgnt->chanctx_tbl[role_index][link_index];
336df279a26SBjoern A. Zeeb if (chanctx_idx == RTW89_CHANCTX_IDLE)
337df279a26SBjoern A. Zeeb goto dflt;
338df279a26SBjoern A. Zeeb
339df279a26SBjoern A. Zeeb roc_idx = atomic_read(&hal->roc_chanctx_idx);
340df279a26SBjoern A. Zeeb if (roc_idx != RTW89_CHANCTX_IDLE) {
341df279a26SBjoern A. Zeeb /* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX).
342df279a26SBjoern A. Zeeb * If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get
343df279a26SBjoern A. Zeeb * the ongoing ROC chanctx.
344df279a26SBjoern A. Zeeb */
345df279a26SBjoern A. Zeeb if (link_index == RTW89_ROC_BY_LINK_INDEX)
346df279a26SBjoern A. Zeeb chanctx_idx = roc_idx;
347df279a26SBjoern A. Zeeb }
348df279a26SBjoern A. Zeeb
349df279a26SBjoern A. Zeeb return rtw89_chan_get(rtwdev, chanctx_idx);
350df279a26SBjoern A. Zeeb
351df279a26SBjoern A. Zeeb dflt:
352df279a26SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
353df279a26SBjoern A. Zeeb "%s (%s): prefetch NULL on link index %u\n",
354df279a26SBjoern A. Zeeb __func__, caller_message ?: "", link_index);
355df279a26SBjoern A. Zeeb
356df279a26SBjoern A. Zeeb return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
357df279a26SBjoern A. Zeeb }
358df279a26SBjoern A. Zeeb EXPORT_SYMBOL(__rtw89_mgnt_chan_get);
359df279a26SBjoern A. Zeeb
rtw89_entity_recalc_mgnt_roles(struct rtw89_dev * rtwdev)360df279a26SBjoern A. Zeeb static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
361df279a26SBjoern A. Zeeb {
362df279a26SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
363df279a26SBjoern A. Zeeb struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
364df279a26SBjoern A. Zeeb struct rtw89_vif_link *link;
365df279a26SBjoern A. Zeeb struct rtw89_vif *role;
366df279a26SBjoern A. Zeeb u8 pos = 0;
367df279a26SBjoern A. Zeeb int i, j;
368df279a26SBjoern A. Zeeb
369df279a26SBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
370df279a26SBjoern A. Zeeb
371df279a26SBjoern A. Zeeb for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++)
372df279a26SBjoern A. Zeeb mgnt->active_roles[i] = NULL;
373df279a26SBjoern A. Zeeb
374df279a26SBjoern A. Zeeb for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) {
375df279a26SBjoern A. Zeeb for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++)
376df279a26SBjoern A. Zeeb mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE;
377df279a26SBjoern A. Zeeb }
378df279a26SBjoern A. Zeeb
379df279a26SBjoern A. Zeeb /* To be consistent with legacy behavior, expect the first active role
380df279a26SBjoern A. Zeeb * which uses RTW89_CHANCTX_0 to put at position 0, and make its first
381df279a26SBjoern A. Zeeb * link instance take RTW89_CHANCTX_0. (normalizing)
382df279a26SBjoern A. Zeeb */
383df279a26SBjoern A. Zeeb list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
384df279a26SBjoern A. Zeeb for (i = 0; i < role->links_inst_valid_num; i++) {
385df279a26SBjoern A. Zeeb link = rtw89_vif_get_link_inst(role, i);
386df279a26SBjoern A. Zeeb if (!link || !link->chanctx_assigned)
387df279a26SBjoern A. Zeeb continue;
388df279a26SBjoern A. Zeeb
389df279a26SBjoern A. Zeeb if (link->chanctx_idx == RTW89_CHANCTX_0) {
390df279a26SBjoern A. Zeeb rtw89_normalize_link_chanctx(rtwdev, link);
391df279a26SBjoern A. Zeeb
392df279a26SBjoern A. Zeeb list_del(&role->mgnt_entry);
393df279a26SBjoern A. Zeeb list_add(&role->mgnt_entry, &mgnt->active_list);
394df279a26SBjoern A. Zeeb goto fill;
395df279a26SBjoern A. Zeeb }
396df279a26SBjoern A. Zeeb }
397df279a26SBjoern A. Zeeb }
398df279a26SBjoern A. Zeeb
399df279a26SBjoern A. Zeeb fill:
400df279a26SBjoern A. Zeeb list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
401df279a26SBjoern A. Zeeb if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) {
402df279a26SBjoern A. Zeeb rtw89_warn(rtwdev,
403df279a26SBjoern A. Zeeb "%s: active roles are over max iface num\n",
404df279a26SBjoern A. Zeeb __func__);
405df279a26SBjoern A. Zeeb break;
406df279a26SBjoern A. Zeeb }
407df279a26SBjoern A. Zeeb
408df279a26SBjoern A. Zeeb for (i = 0; i < role->links_inst_valid_num; i++) {
409df279a26SBjoern A. Zeeb link = rtw89_vif_get_link_inst(role, i);
410df279a26SBjoern A. Zeeb if (!link || !link->chanctx_assigned)
411df279a26SBjoern A. Zeeb continue;
412df279a26SBjoern A. Zeeb
413df279a26SBjoern A. Zeeb mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
414df279a26SBjoern A. Zeeb }
415df279a26SBjoern A. Zeeb
416df279a26SBjoern A. Zeeb mgnt->active_roles[pos++] = role;
417df279a26SBjoern A. Zeeb }
418df279a26SBjoern A. Zeeb }
419df279a26SBjoern A. Zeeb
rtw89_entity_recalc(struct rtw89_dev * rtwdev)4206d67aabdSBjoern A. Zeeb enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
4216d67aabdSBjoern A. Zeeb {
422df279a26SBjoern A. Zeeb DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {};
4236d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
4246d67aabdSBjoern A. Zeeb const struct cfg80211_chan_def *chandef;
4256d67aabdSBjoern A. Zeeb struct rtw89_entity_weight w = {};
4266d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
4276d67aabdSBjoern A. Zeeb struct rtw89_chan chan;
4286d67aabdSBjoern A. Zeeb u8 idx;
4296d67aabdSBjoern A. Zeeb
4306d67aabdSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
4316d67aabdSBjoern A. Zeeb
432df279a26SBjoern A. Zeeb bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_CHANCTX);
4336d67aabdSBjoern A. Zeeb
4346d67aabdSBjoern A. Zeeb rtw89_entity_calculate_weight(rtwdev, &w);
4356d67aabdSBjoern A. Zeeb switch (w.active_chanctxs) {
4368e93258fSBjoern A. Zeeb default:
4376d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "unknown ent chanctxs weight: %d\n",
4386d67aabdSBjoern A. Zeeb w.active_chanctxs);
439df279a26SBjoern A. Zeeb bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX);
4408e93258fSBjoern A. Zeeb fallthrough;
4418e93258fSBjoern A. Zeeb case 0:
4428e93258fSBjoern A. Zeeb rtw89_config_default_chandef(rtwdev);
443df279a26SBjoern A. Zeeb set_bit(RTW89_CHANCTX_0, recalc_map);
4448e93258fSBjoern A. Zeeb fallthrough;
4458e93258fSBjoern A. Zeeb case 1:
446df279a26SBjoern A. Zeeb mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
4478e93258fSBjoern A. Zeeb break;
448df279a26SBjoern A. Zeeb case 2 ... NUM_OF_RTW89_CHANCTX:
449df279a26SBjoern A. Zeeb if (w.active_roles == 1) {
450df279a26SBjoern A. Zeeb mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
451df279a26SBjoern A. Zeeb break;
452df279a26SBjoern A. Zeeb }
453df279a26SBjoern A. Zeeb
4546d67aabdSBjoern A. Zeeb if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) {
4556d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
4566d67aabdSBjoern A. Zeeb "unhandled ent: %d chanctxs %d roles\n",
4576d67aabdSBjoern A. Zeeb w.active_chanctxs, w.active_roles);
4586d67aabdSBjoern A. Zeeb return RTW89_ENTITY_MODE_UNHANDLED;
4598e93258fSBjoern A. Zeeb }
4608e93258fSBjoern A. Zeeb
4616d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
4626d67aabdSBjoern A. Zeeb if (mode == RTW89_ENTITY_MODE_MCC)
4636d67aabdSBjoern A. Zeeb break;
4646d67aabdSBjoern A. Zeeb
4656d67aabdSBjoern A. Zeeb mode = RTW89_ENTITY_MODE_MCC_PREPARE;
4666d67aabdSBjoern A. Zeeb break;
4676d67aabdSBjoern A. Zeeb }
4686d67aabdSBjoern A. Zeeb
469df279a26SBjoern A. Zeeb for_each_set_bit(idx, recalc_map, NUM_OF_RTW89_CHANCTX) {
4706d67aabdSBjoern A. Zeeb chandef = rtw89_chandef_get(rtwdev, idx);
4716d67aabdSBjoern A. Zeeb rtw89_get_channel_params(chandef, &chan);
4726d67aabdSBjoern A. Zeeb if (chan.channel == 0) {
4736d67aabdSBjoern A. Zeeb WARN(1, "Invalid channel on chanctx %d\n", idx);
4746d67aabdSBjoern A. Zeeb return RTW89_ENTITY_MODE_INVALID;
4756d67aabdSBjoern A. Zeeb }
4766d67aabdSBjoern A. Zeeb
4776d67aabdSBjoern A. Zeeb rtw89_assign_entity_chan(rtwdev, idx, &chan);
4786d67aabdSBjoern A. Zeeb }
4796d67aabdSBjoern A. Zeeb
480df279a26SBjoern A. Zeeb rtw89_entity_recalc_mgnt_roles(rtwdev);
481df279a26SBjoern A. Zeeb
4826d67aabdSBjoern A. Zeeb if (hal->entity_pause)
4836d67aabdSBjoern A. Zeeb return rtw89_get_entity_mode(rtwdev);
4846d67aabdSBjoern A. Zeeb
4858e93258fSBjoern A. Zeeb rtw89_set_entity_mode(rtwdev, mode);
4868e93258fSBjoern A. Zeeb return mode;
4878e93258fSBjoern A. Zeeb }
4888e93258fSBjoern A. Zeeb
rtw89_chanctx_notify(struct rtw89_dev * rtwdev,enum rtw89_chanctx_state state)4896d67aabdSBjoern A. Zeeb static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
4906d67aabdSBjoern A. Zeeb enum rtw89_chanctx_state state)
4916d67aabdSBjoern A. Zeeb {
4926d67aabdSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
4936d67aabdSBjoern A. Zeeb const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
4946d67aabdSBjoern A. Zeeb int i;
4956d67aabdSBjoern A. Zeeb
4966d67aabdSBjoern A. Zeeb if (!listener)
4976d67aabdSBjoern A. Zeeb return;
4986d67aabdSBjoern A. Zeeb
4996d67aabdSBjoern A. Zeeb for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
5006d67aabdSBjoern A. Zeeb if (!listener->callbacks[i])
5016d67aabdSBjoern A. Zeeb continue;
5026d67aabdSBjoern A. Zeeb
5036d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
5046d67aabdSBjoern A. Zeeb "chanctx notify listener: cb %d, state %d\n",
5056d67aabdSBjoern A. Zeeb i, state);
5066d67aabdSBjoern A. Zeeb
5076d67aabdSBjoern A. Zeeb listener->callbacks[i](rtwdev, state);
5086d67aabdSBjoern A. Zeeb }
5096d67aabdSBjoern A. Zeeb }
5106d67aabdSBjoern A. Zeeb
rtw89_concurrent_via_mrc(struct rtw89_dev * rtwdev)5116d67aabdSBjoern A. Zeeb static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev)
5126d67aabdSBjoern A. Zeeb {
5136d67aabdSBjoern A. Zeeb enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
5146d67aabdSBjoern A. Zeeb
5156d67aabdSBjoern A. Zeeb return chip_gen == RTW89_CHIP_BE;
5166d67aabdSBjoern A. Zeeb }
5176d67aabdSBjoern A. Zeeb
5186d67aabdSBjoern A. Zeeb /* This function centrally manages how MCC roles are sorted and iterated.
5196d67aabdSBjoern A. Zeeb * And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES.
5206d67aabdSBjoern A. Zeeb * So, if data needs to pass an array for ordered_idx, the array can declare
5216d67aabdSBjoern A. Zeeb * with NUM_OF_RTW89_MCC_ROLES. Besides, the entire iteration will stop
5226d67aabdSBjoern A. Zeeb * immediately as long as iterator returns a non-zero value.
5236d67aabdSBjoern A. Zeeb */
5246d67aabdSBjoern A. Zeeb static
rtw89_iterate_mcc_roles(struct rtw89_dev * rtwdev,int (* iterator)(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data),void * data)5256d67aabdSBjoern A. Zeeb int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev,
5266d67aabdSBjoern A. Zeeb int (*iterator)(struct rtw89_dev *rtwdev,
5276d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
5286d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
5296d67aabdSBjoern A. Zeeb void *data),
5306d67aabdSBjoern A. Zeeb void *data)
5316d67aabdSBjoern A. Zeeb {
5326d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
5336d67aabdSBjoern A. Zeeb struct rtw89_mcc_role * const roles[] = {
5346d67aabdSBjoern A. Zeeb &mcc->role_ref,
5356d67aabdSBjoern A. Zeeb &mcc->role_aux,
5366d67aabdSBjoern A. Zeeb };
5376d67aabdSBjoern A. Zeeb unsigned int idx;
5386d67aabdSBjoern A. Zeeb int ret;
5396d67aabdSBjoern A. Zeeb
5406d67aabdSBjoern A. Zeeb BUILD_BUG_ON(ARRAY_SIZE(roles) != NUM_OF_RTW89_MCC_ROLES);
5416d67aabdSBjoern A. Zeeb
5426d67aabdSBjoern A. Zeeb for (idx = 0; idx < NUM_OF_RTW89_MCC_ROLES; idx++) {
5436d67aabdSBjoern A. Zeeb ret = iterator(rtwdev, roles[idx], idx, data);
5446d67aabdSBjoern A. Zeeb if (ret)
5456d67aabdSBjoern A. Zeeb return ret;
5466d67aabdSBjoern A. Zeeb }
5476d67aabdSBjoern A. Zeeb
5486d67aabdSBjoern A. Zeeb return 0;
5496d67aabdSBjoern A. Zeeb }
5506d67aabdSBjoern A. Zeeb
rtw89_mcc_get_tbtt_ofst(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * role,u64 tsf)5516d67aabdSBjoern A. Zeeb static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
5526d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role, u64 tsf)
5536d67aabdSBjoern A. Zeeb {
554df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link = role->rtwvif_link;
5556d67aabdSBjoern A. Zeeb u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval);
556df279a26SBjoern A. Zeeb u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);
5576d67aabdSBjoern A. Zeeb u32 remainder;
5586d67aabdSBjoern A. Zeeb
5596d67aabdSBjoern A. Zeeb if (tsf < sync_tsf) {
5606d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
5616d67aabdSBjoern A. Zeeb "MCC get tbtt ofst: tsf might not update yet\n");
5626d67aabdSBjoern A. Zeeb sync_tsf = 0;
5636d67aabdSBjoern A. Zeeb }
5646d67aabdSBjoern A. Zeeb
5656d67aabdSBjoern A. Zeeb div_u64_rem(tsf - sync_tsf, bcn_intvl_us, &remainder);
5666d67aabdSBjoern A. Zeeb
5676d67aabdSBjoern A. Zeeb return remainder;
5686d67aabdSBjoern A. Zeeb }
5696d67aabdSBjoern A. Zeeb
__mcc_fw_req_tsf(struct rtw89_dev * rtwdev,u64 * tsf_ref,u64 * tsf_aux)5706d67aabdSBjoern A. Zeeb static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
5716d67aabdSBjoern A. Zeeb {
5726d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
5736d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
5746d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
5756d67aabdSBjoern A. Zeeb struct rtw89_mac_mcc_tsf_rpt rpt = {};
5766d67aabdSBjoern A. Zeeb struct rtw89_fw_mcc_tsf_req req = {};
5776d67aabdSBjoern A. Zeeb int ret;
5786d67aabdSBjoern A. Zeeb
5796d67aabdSBjoern A. Zeeb req.group = mcc->group;
580df279a26SBjoern A. Zeeb req.macid_x = ref->rtwvif_link->mac_id;
581df279a26SBjoern A. Zeeb req.macid_y = aux->rtwvif_link->mac_id;
5826d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt);
5836d67aabdSBjoern A. Zeeb if (ret) {
5846d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
5856d67aabdSBjoern A. Zeeb "MCC h2c failed to request tsf: %d\n", ret);
5866d67aabdSBjoern A. Zeeb return ret;
5876d67aabdSBjoern A. Zeeb }
5886d67aabdSBjoern A. Zeeb
5896d67aabdSBjoern A. Zeeb *tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
5906d67aabdSBjoern A. Zeeb *tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
5916d67aabdSBjoern A. Zeeb
5926d67aabdSBjoern A. Zeeb return 0;
5936d67aabdSBjoern A. Zeeb }
5946d67aabdSBjoern A. Zeeb
__mrc_fw_req_tsf(struct rtw89_dev * rtwdev,u64 * tsf_ref,u64 * tsf_aux)5956d67aabdSBjoern A. Zeeb static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
5966d67aabdSBjoern A. Zeeb {
5976d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
5986d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
5996d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
6006d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_req_tsf_arg arg = {};
6016d67aabdSBjoern A. Zeeb struct rtw89_mac_mrc_tsf_rpt rpt = {};
6026d67aabdSBjoern A. Zeeb int ret;
6036d67aabdSBjoern A. Zeeb
6046d67aabdSBjoern A. Zeeb BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
6056d67aabdSBjoern A. Zeeb
6066d67aabdSBjoern A. Zeeb arg.num = 2;
607df279a26SBjoern A. Zeeb arg.infos[0].band = ref->rtwvif_link->mac_idx;
608df279a26SBjoern A. Zeeb arg.infos[0].port = ref->rtwvif_link->port;
609df279a26SBjoern A. Zeeb arg.infos[1].band = aux->rtwvif_link->mac_idx;
610df279a26SBjoern A. Zeeb arg.infos[1].port = aux->rtwvif_link->port;
6116d67aabdSBjoern A. Zeeb
6126d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt);
6136d67aabdSBjoern A. Zeeb if (ret) {
6146d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
6156d67aabdSBjoern A. Zeeb "MRC h2c failed to request tsf: %d\n", ret);
6166d67aabdSBjoern A. Zeeb return ret;
6176d67aabdSBjoern A. Zeeb }
6186d67aabdSBjoern A. Zeeb
6196d67aabdSBjoern A. Zeeb *tsf_ref = rpt.tsfs[0];
6206d67aabdSBjoern A. Zeeb *tsf_aux = rpt.tsfs[1];
6216d67aabdSBjoern A. Zeeb
6226d67aabdSBjoern A. Zeeb return 0;
6236d67aabdSBjoern A. Zeeb }
6246d67aabdSBjoern A. Zeeb
rtw89_mcc_get_bcn_ofst(struct rtw89_dev * rtwdev)6256d67aabdSBjoern A. Zeeb static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
6266d67aabdSBjoern A. Zeeb {
6276d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
6286d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
6296d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
6306d67aabdSBjoern A. Zeeb u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
6316d67aabdSBjoern A. Zeeb u32 tbtt_ofst_ref, tbtt_ofst_aux;
6326d67aabdSBjoern A. Zeeb u64 tsf_ref, tsf_aux;
6336d67aabdSBjoern A. Zeeb int ret;
6346d67aabdSBjoern A. Zeeb
6356d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev))
6366d67aabdSBjoern A. Zeeb ret = __mrc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
6376d67aabdSBjoern A. Zeeb else
6386d67aabdSBjoern A. Zeeb ret = __mcc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
6396d67aabdSBjoern A. Zeeb
6406d67aabdSBjoern A. Zeeb if (ret)
6416d67aabdSBjoern A. Zeeb return RTW89_MCC_DFLT_BCN_OFST_TIME;
6426d67aabdSBjoern A. Zeeb
6436d67aabdSBjoern A. Zeeb tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf_ref);
6446d67aabdSBjoern A. Zeeb tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, aux, tsf_aux);
6456d67aabdSBjoern A. Zeeb
6466d67aabdSBjoern A. Zeeb while (tbtt_ofst_ref < tbtt_ofst_aux)
6476d67aabdSBjoern A. Zeeb tbtt_ofst_ref += bcn_intvl_ref_us;
6486d67aabdSBjoern A. Zeeb
6496d67aabdSBjoern A. Zeeb return (tbtt_ofst_ref - tbtt_ofst_aux) / 1024;
6506d67aabdSBjoern A. Zeeb }
6516d67aabdSBjoern A. Zeeb
6526d67aabdSBjoern A. Zeeb static
rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role * mcc_role,unsigned int bit)6536d67aabdSBjoern A. Zeeb void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role,
6546d67aabdSBjoern A. Zeeb unsigned int bit)
6556d67aabdSBjoern A. Zeeb {
6566d67aabdSBjoern A. Zeeb unsigned int idx = bit / 8;
6576d67aabdSBjoern A. Zeeb unsigned int pos = bit % 8;
6586d67aabdSBjoern A. Zeeb
6596d67aabdSBjoern A. Zeeb if (idx >= ARRAY_SIZE(mcc_role->macid_bitmap))
6606d67aabdSBjoern A. Zeeb return;
6616d67aabdSBjoern A. Zeeb
6626d67aabdSBjoern A. Zeeb mcc_role->macid_bitmap[idx] |= BIT(pos);
6636d67aabdSBjoern A. Zeeb }
6646d67aabdSBjoern A. Zeeb
6656d67aabdSBjoern A. Zeeb static
rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role * mcc_role)6666d67aabdSBjoern A. Zeeb u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role)
6676d67aabdSBjoern A. Zeeb {
6686d67aabdSBjoern A. Zeeb unsigned int macid;
6696d67aabdSBjoern A. Zeeb unsigned int i, j;
6706d67aabdSBjoern A. Zeeb u32 bitmap = 0;
6716d67aabdSBjoern A. Zeeb
6726d67aabdSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) {
6736d67aabdSBjoern A. Zeeb for (j = 0; j < 8; j++) {
6746d67aabdSBjoern A. Zeeb macid = i * 8 + j;
6756d67aabdSBjoern A. Zeeb if (macid >= 32)
6766d67aabdSBjoern A. Zeeb goto out;
6776d67aabdSBjoern A. Zeeb
6786d67aabdSBjoern A. Zeeb if (mcc_role->macid_bitmap[i] & BIT(j))
6796d67aabdSBjoern A. Zeeb bitmap |= BIT(macid);
6806d67aabdSBjoern A. Zeeb }
6816d67aabdSBjoern A. Zeeb }
6826d67aabdSBjoern A. Zeeb
6836d67aabdSBjoern A. Zeeb out:
6846d67aabdSBjoern A. Zeeb return bitmap;
6856d67aabdSBjoern A. Zeeb }
6866d67aabdSBjoern A. Zeeb
rtw89_mcc_role_macid_sta_iter(void * data,struct ieee80211_sta * sta)6876d67aabdSBjoern A. Zeeb static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
6886d67aabdSBjoern A. Zeeb {
6896d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role = data;
690df279a26SBjoern A. Zeeb struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif;
691df279a26SBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
692df279a26SBjoern A. Zeeb struct rtw89_vif *rtwvif = rtwsta->rtwvif;
693df279a26SBjoern A. Zeeb struct rtw89_dev *rtwdev = rtwsta->rtwdev;
694df279a26SBjoern A. Zeeb struct rtw89_sta_link *rtwsta_link;
6956d67aabdSBjoern A. Zeeb
6966d67aabdSBjoern A. Zeeb if (rtwvif != target)
6976d67aabdSBjoern A. Zeeb return;
6986d67aabdSBjoern A. Zeeb
699df279a26SBjoern A. Zeeb rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
700df279a26SBjoern A. Zeeb if (unlikely(!rtwsta_link)) {
701df279a26SBjoern A. Zeeb rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n");
702df279a26SBjoern A. Zeeb return;
703df279a26SBjoern A. Zeeb }
704df279a26SBjoern A. Zeeb
705df279a26SBjoern A. Zeeb rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id);
7066d67aabdSBjoern A. Zeeb }
7076d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role)7086d67aabdSBjoern A. Zeeb static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
7096d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role)
7106d67aabdSBjoern A. Zeeb {
711df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
7126d67aabdSBjoern A. Zeeb
713df279a26SBjoern A. Zeeb rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif_link->mac_id);
7146d67aabdSBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw,
7156d67aabdSBjoern A. Zeeb rtw89_mcc_role_macid_sta_iter,
7166d67aabdSBjoern A. Zeeb mcc_role);
7176d67aabdSBjoern A. Zeeb }
7186d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_role_policy(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role)7196d67aabdSBjoern A. Zeeb static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev,
7206d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role)
7216d67aabdSBjoern A. Zeeb {
7226d67aabdSBjoern A. Zeeb struct rtw89_mcc_policy *policy = &mcc_role->policy;
7236d67aabdSBjoern A. Zeeb
7246d67aabdSBjoern A. Zeeb policy->c2h_rpt = RTW89_FW_MCC_C2H_RPT_ALL;
7256d67aabdSBjoern A. Zeeb policy->tx_null_early = RTW89_MCC_DFLT_TX_NULL_EARLY;
7266d67aabdSBjoern A. Zeeb policy->in_curr_ch = false;
7276d67aabdSBjoern A. Zeeb policy->dis_sw_retry = true;
7286d67aabdSBjoern A. Zeeb policy->sw_retry_count = false;
7296d67aabdSBjoern A. Zeeb
7306d67aabdSBjoern A. Zeeb if (mcc_role->is_go)
7316d67aabdSBjoern A. Zeeb policy->dis_tx_null = true;
7326d67aabdSBjoern A. Zeeb else
7336d67aabdSBjoern A. Zeeb policy->dis_tx_null = false;
7346d67aabdSBjoern A. Zeeb }
7356d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_role_limit(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role)7366d67aabdSBjoern A. Zeeb static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
7376d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role)
7386d67aabdSBjoern A. Zeeb {
739df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
7406d67aabdSBjoern A. Zeeb struct ieee80211_p2p_noa_desc *noa_desc;
741df279a26SBjoern A. Zeeb struct ieee80211_bss_conf *bss_conf;
7426d67aabdSBjoern A. Zeeb u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval);
7436d67aabdSBjoern A. Zeeb u32 max_toa_us, max_tob_us, max_dur_us;
7446d67aabdSBjoern A. Zeeb u32 start_time, interval, duration;
7456d67aabdSBjoern A. Zeeb u64 tsf, tsf_lmt;
7466d67aabdSBjoern A. Zeeb int ret;
7476d67aabdSBjoern A. Zeeb int i;
7486d67aabdSBjoern A. Zeeb
7496d67aabdSBjoern A. Zeeb if (!mcc_role->is_go && !mcc_role->is_gc)
7506d67aabdSBjoern A. Zeeb return;
7516d67aabdSBjoern A. Zeeb
752df279a26SBjoern A. Zeeb rcu_read_lock();
753df279a26SBjoern A. Zeeb
754df279a26SBjoern A. Zeeb bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
755df279a26SBjoern A. Zeeb
7566d67aabdSBjoern A. Zeeb /* find the first periodic NoA */
7576d67aabdSBjoern A. Zeeb for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
758df279a26SBjoern A. Zeeb noa_desc = &bss_conf->p2p_noa_attr.desc[i];
7596d67aabdSBjoern A. Zeeb if (noa_desc->count == 255)
7606d67aabdSBjoern A. Zeeb goto fill;
7616d67aabdSBjoern A. Zeeb }
7626d67aabdSBjoern A. Zeeb
763df279a26SBjoern A. Zeeb rcu_read_unlock();
7646d67aabdSBjoern A. Zeeb return;
7656d67aabdSBjoern A. Zeeb
7666d67aabdSBjoern A. Zeeb fill:
7676d67aabdSBjoern A. Zeeb start_time = le32_to_cpu(noa_desc->start_time);
7686d67aabdSBjoern A. Zeeb interval = le32_to_cpu(noa_desc->interval);
7696d67aabdSBjoern A. Zeeb duration = le32_to_cpu(noa_desc->duration);
7706d67aabdSBjoern A. Zeeb
771df279a26SBjoern A. Zeeb rcu_read_unlock();
772df279a26SBjoern A. Zeeb
7736d67aabdSBjoern A. Zeeb if (interval != bcn_intvl_us) {
7746d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
7756d67aabdSBjoern A. Zeeb "MCC role limit: mismatch interval: %d vs. %d\n",
7766d67aabdSBjoern A. Zeeb interval, bcn_intvl_us);
7776d67aabdSBjoern A. Zeeb return;
7786d67aabdSBjoern A. Zeeb }
7796d67aabdSBjoern A. Zeeb
780df279a26SBjoern A. Zeeb ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
7816d67aabdSBjoern A. Zeeb if (ret) {
7826d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
7836d67aabdSBjoern A. Zeeb return;
7846d67aabdSBjoern A. Zeeb }
7856d67aabdSBjoern A. Zeeb
7866d67aabdSBjoern A. Zeeb tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time;
7876d67aabdSBjoern A. Zeeb max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, mcc_role, tsf_lmt);
7886d67aabdSBjoern A. Zeeb max_dur_us = interval - duration;
7896d67aabdSBjoern A. Zeeb max_tob_us = max_dur_us - max_toa_us;
7906d67aabdSBjoern A. Zeeb
7916d67aabdSBjoern A. Zeeb if (!max_toa_us || !max_tob_us) {
7926d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
7936d67aabdSBjoern A. Zeeb "MCC role limit: hit boundary\n");
7946d67aabdSBjoern A. Zeeb return;
7956d67aabdSBjoern A. Zeeb }
7966d67aabdSBjoern A. Zeeb
7976d67aabdSBjoern A. Zeeb if (max_dur_us < max_toa_us) {
7986d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
7996d67aabdSBjoern A. Zeeb "MCC role limit: insufficient duration\n");
8006d67aabdSBjoern A. Zeeb return;
8016d67aabdSBjoern A. Zeeb }
8026d67aabdSBjoern A. Zeeb
8036d67aabdSBjoern A. Zeeb mcc_role->limit.max_toa = max_toa_us / 1024;
8046d67aabdSBjoern A. Zeeb mcc_role->limit.max_tob = max_tob_us / 1024;
805df279a26SBjoern A. Zeeb mcc_role->limit.max_dur = mcc_role->limit.max_toa + mcc_role->limit.max_tob;
8066d67aabdSBjoern A. Zeeb mcc_role->limit.enable = true;
8076d67aabdSBjoern A. Zeeb
8086d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
8096d67aabdSBjoern A. Zeeb "MCC role limit: max_toa %d, max_tob %d, max_dur %d\n",
8106d67aabdSBjoern A. Zeeb mcc_role->limit.max_toa, mcc_role->limit.max_tob,
8116d67aabdSBjoern A. Zeeb mcc_role->limit.max_dur);
8126d67aabdSBjoern A. Zeeb }
8136d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_role(struct rtw89_dev * rtwdev,struct rtw89_vif_link * rtwvif_link,struct rtw89_mcc_role * role)8146d67aabdSBjoern A. Zeeb static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
815df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link,
8166d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role)
8176d67aabdSBjoern A. Zeeb {
818df279a26SBjoern A. Zeeb struct ieee80211_bss_conf *bss_conf;
8196d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan;
8206d67aabdSBjoern A. Zeeb
8216d67aabdSBjoern A. Zeeb memset(role, 0, sizeof(*role));
822df279a26SBjoern A. Zeeb role->rtwvif_link = rtwvif_link;
823df279a26SBjoern A. Zeeb
824df279a26SBjoern A. Zeeb rcu_read_lock();
825df279a26SBjoern A. Zeeb
826df279a26SBjoern A. Zeeb bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
827df279a26SBjoern A. Zeeb role->beacon_interval = bss_conf->beacon_int;
828df279a26SBjoern A. Zeeb
829df279a26SBjoern A. Zeeb rcu_read_unlock();
8306d67aabdSBjoern A. Zeeb
8316d67aabdSBjoern A. Zeeb if (!role->beacon_interval) {
8326d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev,
8336d67aabdSBjoern A. Zeeb "cannot handle MCC role without beacon interval\n");
8346d67aabdSBjoern A. Zeeb return -EINVAL;
8356d67aabdSBjoern A. Zeeb }
8366d67aabdSBjoern A. Zeeb
8376d67aabdSBjoern A. Zeeb role->duration = role->beacon_interval / 2;
8386d67aabdSBjoern A. Zeeb
839df279a26SBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
8406d67aabdSBjoern A. Zeeb role->is_2ghz = chan->band_type == RTW89_BAND_2G;
841df279a26SBjoern A. Zeeb role->is_go = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
842df279a26SBjoern A. Zeeb role->is_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
8436d67aabdSBjoern A. Zeeb
8446d67aabdSBjoern A. Zeeb rtw89_mcc_fill_role_macid_bitmap(rtwdev, role);
8456d67aabdSBjoern A. Zeeb rtw89_mcc_fill_role_policy(rtwdev, role);
8466d67aabdSBjoern A. Zeeb rtw89_mcc_fill_role_limit(rtwdev, role);
8476d67aabdSBjoern A. Zeeb
8486d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
8496d67aabdSBjoern A. Zeeb "MCC role: bcn_intvl %d, is_2ghz %d, is_go %d, is_gc %d\n",
8506d67aabdSBjoern A. Zeeb role->beacon_interval, role->is_2ghz, role->is_go, role->is_gc);
8516d67aabdSBjoern A. Zeeb return 0;
8526d67aabdSBjoern A. Zeeb }
8536d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_bt_role(struct rtw89_dev * rtwdev)8546d67aabdSBjoern A. Zeeb static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev)
8556d67aabdSBjoern A. Zeeb {
8566d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
8576d67aabdSBjoern A. Zeeb struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
8586d67aabdSBjoern A. Zeeb
8596d67aabdSBjoern A. Zeeb memset(bt_role, 0, sizeof(*bt_role));
8606d67aabdSBjoern A. Zeeb bt_role->duration = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
8616d67aabdSBjoern A. Zeeb
8626d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC bt role: dur %d\n",
8636d67aabdSBjoern A. Zeeb bt_role->duration);
8646d67aabdSBjoern A. Zeeb }
8656d67aabdSBjoern A. Zeeb
8666d67aabdSBjoern A. Zeeb struct rtw89_mcc_fill_role_selector {
867df279a26SBjoern A. Zeeb struct rtw89_vif_link *bind_vif[NUM_OF_RTW89_CHANCTX];
8686d67aabdSBjoern A. Zeeb };
8696d67aabdSBjoern A. Zeeb
870df279a26SBjoern A. Zeeb static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES);
871df279a26SBjoern A. Zeeb static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES);
8726d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_role_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)8736d67aabdSBjoern A. Zeeb static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
8746d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
8756d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
8766d67aabdSBjoern A. Zeeb void *data)
8776d67aabdSBjoern A. Zeeb {
8786d67aabdSBjoern A. Zeeb struct rtw89_mcc_fill_role_selector *sel = data;
879df279a26SBjoern A. Zeeb struct rtw89_vif_link *role_vif = sel->bind_vif[ordered_idx];
8806d67aabdSBjoern A. Zeeb int ret;
8816d67aabdSBjoern A. Zeeb
8826d67aabdSBjoern A. Zeeb if (!role_vif) {
8836d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "cannot handle MCC without role[%d]\n",
8846d67aabdSBjoern A. Zeeb ordered_idx);
8856d67aabdSBjoern A. Zeeb return -EINVAL;
8866d67aabdSBjoern A. Zeeb }
8876d67aabdSBjoern A. Zeeb
8886d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
8896d67aabdSBjoern A. Zeeb "MCC fill role[%d] with vif <macid %d>\n",
8906d67aabdSBjoern A. Zeeb ordered_idx, role_vif->mac_id);
8916d67aabdSBjoern A. Zeeb
8926d67aabdSBjoern A. Zeeb ret = rtw89_mcc_fill_role(rtwdev, role_vif, mcc_role);
8936d67aabdSBjoern A. Zeeb if (ret)
8946d67aabdSBjoern A. Zeeb return ret;
8956d67aabdSBjoern A. Zeeb
8966d67aabdSBjoern A. Zeeb return 0;
8976d67aabdSBjoern A. Zeeb }
8986d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_all_roles(struct rtw89_dev * rtwdev)8996d67aabdSBjoern A. Zeeb static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
9006d67aabdSBjoern A. Zeeb {
901df279a26SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
902df279a26SBjoern A. Zeeb struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
9036d67aabdSBjoern A. Zeeb struct rtw89_mcc_fill_role_selector sel = {};
904df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link;
9056d67aabdSBjoern A. Zeeb struct rtw89_vif *rtwvif;
9066d67aabdSBjoern A. Zeeb int ret;
907df279a26SBjoern A. Zeeb int i;
9086d67aabdSBjoern A. Zeeb
909df279a26SBjoern A. Zeeb for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) {
910df279a26SBjoern A. Zeeb rtwvif = mgnt->active_roles[i];
911df279a26SBjoern A. Zeeb if (!rtwvif)
912df279a26SBjoern A. Zeeb break;
9136d67aabdSBjoern A. Zeeb
914df279a26SBjoern A. Zeeb rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
915df279a26SBjoern A. Zeeb if (unlikely(!rtwvif_link)) {
916df279a26SBjoern A. Zeeb rtw89_err(rtwdev, "mcc fill roles: find no link on HW-0\n");
9176d67aabdSBjoern A. Zeeb continue;
9186d67aabdSBjoern A. Zeeb }
9196d67aabdSBjoern A. Zeeb
920df279a26SBjoern A. Zeeb sel.bind_vif[i] = rtwvif_link;
9216d67aabdSBjoern A. Zeeb }
9226d67aabdSBjoern A. Zeeb
9236d67aabdSBjoern A. Zeeb ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel);
9246d67aabdSBjoern A. Zeeb if (ret)
9256d67aabdSBjoern A. Zeeb return ret;
9266d67aabdSBjoern A. Zeeb
9276d67aabdSBjoern A. Zeeb rtw89_mcc_fill_bt_role(rtwdev);
9286d67aabdSBjoern A. Zeeb return 0;
9296d67aabdSBjoern A. Zeeb }
9306d67aabdSBjoern A. Zeeb
rtw89_mcc_assign_pattern(struct rtw89_dev * rtwdev,const struct rtw89_mcc_pattern * new)9316d67aabdSBjoern A. Zeeb static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
9326d67aabdSBjoern A. Zeeb const struct rtw89_mcc_pattern *new)
9336d67aabdSBjoern A. Zeeb {
9346d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
9356d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
9366d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
9376d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
9386d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
9396d67aabdSBjoern A. Zeeb
9406d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
9416d67aabdSBjoern A. Zeeb "MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",
9426d67aabdSBjoern A. Zeeb new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux);
9436d67aabdSBjoern A. Zeeb
9446d67aabdSBjoern A. Zeeb *pattern = *new;
9456d67aabdSBjoern A. Zeeb memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
9466d67aabdSBjoern A. Zeeb
9476d67aabdSBjoern A. Zeeb if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) {
948df279a26SBjoern A. Zeeb pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id;
949df279a26SBjoern A. Zeeb pattern->courtesy.macid_src = ref->rtwvif_link->mac_id;
9506d67aabdSBjoern A. Zeeb pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
9516d67aabdSBjoern A. Zeeb pattern->courtesy.enable = true;
9526d67aabdSBjoern A. Zeeb } else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) {
953df279a26SBjoern A. Zeeb pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id;
954df279a26SBjoern A. Zeeb pattern->courtesy.macid_src = aux->rtwvif_link->mac_id;
9556d67aabdSBjoern A. Zeeb pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
9566d67aabdSBjoern A. Zeeb pattern->courtesy.enable = true;
9576d67aabdSBjoern A. Zeeb }
9586d67aabdSBjoern A. Zeeb
9596d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
9606d67aabdSBjoern A. Zeeb "MCC pattern flags: plan %d, courtesy_en %d\n",
9616d67aabdSBjoern A. Zeeb pattern->plan, pattern->courtesy.enable);
9626d67aabdSBjoern A. Zeeb
9636d67aabdSBjoern A. Zeeb if (!pattern->courtesy.enable)
9646d67aabdSBjoern A. Zeeb return;
9656d67aabdSBjoern A. Zeeb
9666d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
9676d67aabdSBjoern A. Zeeb "MCC pattern courtesy: tgt %d, src %d, slot %d\n",
9686d67aabdSBjoern A. Zeeb pattern->courtesy.macid_tgt, pattern->courtesy.macid_src,
9696d67aabdSBjoern A. Zeeb pattern->courtesy.slot_num);
9706d67aabdSBjoern A. Zeeb }
9716d67aabdSBjoern A. Zeeb
9726d67aabdSBjoern A. Zeeb /* The follow-up roughly shows the relationship between the parameters
9736d67aabdSBjoern A. Zeeb * for pattern calculation.
9746d67aabdSBjoern A. Zeeb *
9756d67aabdSBjoern A. Zeeb * |< duration ref >| (if mid bt) |< duration aux >|
9766d67aabdSBjoern A. Zeeb * |< tob ref >|< toa ref >| ... |< tob aux >|< toa aux >|
9776d67aabdSBjoern A. Zeeb * V V
9786d67aabdSBjoern A. Zeeb * tbtt ref tbtt aux
9796d67aabdSBjoern A. Zeeb * |< beacon offset >|
9806d67aabdSBjoern A. Zeeb *
9816d67aabdSBjoern A. Zeeb * In loose pattern calculation, we only ensure at least tob_ref and
9826d67aabdSBjoern A. Zeeb * toa_ref have positive results. If tob_aux or toa_aux is negative
9836d67aabdSBjoern A. Zeeb * unfortunately, FW will be notified to handle it with courtesy
9846d67aabdSBjoern A. Zeeb * mechanism.
9856d67aabdSBjoern A. Zeeb */
__rtw89_mcc_calc_pattern_loose(struct rtw89_dev * rtwdev,struct rtw89_mcc_pattern * ptrn,bool hdl_bt)9866d67aabdSBjoern A. Zeeb static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
9876d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *ptrn,
9886d67aabdSBjoern A. Zeeb bool hdl_bt)
9896d67aabdSBjoern A. Zeeb {
9906d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
9916d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
9926d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
9936d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
9946d67aabdSBjoern A. Zeeb u16 bcn_ofst = config->beacon_offset;
9956d67aabdSBjoern A. Zeeb u16 bt_dur_in_mid = 0;
9966d67aabdSBjoern A. Zeeb u16 max_bcn_ofst;
9976d67aabdSBjoern A. Zeeb s16 upper, lower;
9986d67aabdSBjoern A. Zeeb u16 res;
9996d67aabdSBjoern A. Zeeb
10006d67aabdSBjoern A. Zeeb *ptrn = (typeof(*ptrn)){
10016d67aabdSBjoern A. Zeeb .plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
10026d67aabdSBjoern A. Zeeb };
10036d67aabdSBjoern A. Zeeb
10046d67aabdSBjoern A. Zeeb if (!hdl_bt)
10056d67aabdSBjoern A. Zeeb goto calc;
10066d67aabdSBjoern A. Zeeb
10076d67aabdSBjoern A. Zeeb max_bcn_ofst = ref->duration + aux->duration;
10086d67aabdSBjoern A. Zeeb if (ref->limit.enable)
10096d67aabdSBjoern A. Zeeb max_bcn_ofst = min_t(u16, max_bcn_ofst,
10106d67aabdSBjoern A. Zeeb ref->limit.max_toa + aux->duration);
10116d67aabdSBjoern A. Zeeb else if (aux->limit.enable)
10126d67aabdSBjoern A. Zeeb max_bcn_ofst = min_t(u16, max_bcn_ofst,
10136d67aabdSBjoern A. Zeeb ref->duration + aux->limit.max_tob);
10146d67aabdSBjoern A. Zeeb
10156d67aabdSBjoern A. Zeeb if (bcn_ofst > max_bcn_ofst && bcn_ofst >= mcc->bt_role.duration) {
10166d67aabdSBjoern A. Zeeb bt_dur_in_mid = mcc->bt_role.duration;
10176d67aabdSBjoern A. Zeeb ptrn->plan = RTW89_MCC_PLAN_MID_BT;
10186d67aabdSBjoern A. Zeeb }
10196d67aabdSBjoern A. Zeeb
10206d67aabdSBjoern A. Zeeb calc:
10216d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
10226d67aabdSBjoern A. Zeeb "MCC calc ptrn_ls: plan %d, bcn_ofst %d\n",
10236d67aabdSBjoern A. Zeeb ptrn->plan, bcn_ofst);
10246d67aabdSBjoern A. Zeeb
10256d67aabdSBjoern A. Zeeb res = bcn_ofst - bt_dur_in_mid;
10266d67aabdSBjoern A. Zeeb upper = min_t(s16, ref->duration, res);
10276d67aabdSBjoern A. Zeeb lower = 0;
10286d67aabdSBjoern A. Zeeb
10296d67aabdSBjoern A. Zeeb if (ref->limit.enable) {
10306d67aabdSBjoern A. Zeeb upper = min_t(s16, upper, ref->limit.max_toa);
10316d67aabdSBjoern A. Zeeb lower = max_t(s16, lower, ref->duration - ref->limit.max_tob);
10326d67aabdSBjoern A. Zeeb } else if (aux->limit.enable) {
10336d67aabdSBjoern A. Zeeb upper = min_t(s16, upper,
10346d67aabdSBjoern A. Zeeb res - (aux->duration - aux->limit.max_toa));
10356d67aabdSBjoern A. Zeeb lower = max_t(s16, lower, res - aux->limit.max_tob);
10366d67aabdSBjoern A. Zeeb }
10376d67aabdSBjoern A. Zeeb
10386d67aabdSBjoern A. Zeeb if (lower < upper)
10396d67aabdSBjoern A. Zeeb ptrn->toa_ref = (upper + lower) / 2;
10406d67aabdSBjoern A. Zeeb else
10416d67aabdSBjoern A. Zeeb ptrn->toa_ref = lower;
10426d67aabdSBjoern A. Zeeb
10436d67aabdSBjoern A. Zeeb ptrn->tob_ref = ref->duration - ptrn->toa_ref;
10446d67aabdSBjoern A. Zeeb ptrn->tob_aux = res - ptrn->toa_ref;
10456d67aabdSBjoern A. Zeeb ptrn->toa_aux = aux->duration - ptrn->tob_aux;
10466d67aabdSBjoern A. Zeeb }
10476d67aabdSBjoern A. Zeeb
10486d67aabdSBjoern A. Zeeb /* In strict pattern calculation, we consider timing that might need
10496d67aabdSBjoern A. Zeeb * for HW stuffs, i.e. min_tob and min_toa.
10506d67aabdSBjoern A. Zeeb */
__rtw89_mcc_calc_pattern_strict(struct rtw89_dev * rtwdev,struct rtw89_mcc_pattern * ptrn)10516d67aabdSBjoern A. Zeeb static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,
10526d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *ptrn)
10536d67aabdSBjoern A. Zeeb {
10546d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
10556d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
10566d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
10576d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
10586d67aabdSBjoern A. Zeeb u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME;
10596d67aabdSBjoern A. Zeeb u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME;
10606d67aabdSBjoern A. Zeeb u16 bcn_ofst = config->beacon_offset;
10616d67aabdSBjoern A. Zeeb s16 upper_toa_ref, lower_toa_ref;
10626d67aabdSBjoern A. Zeeb s16 upper_tob_aux, lower_tob_aux;
10636d67aabdSBjoern A. Zeeb u16 bt_dur_in_mid;
10646d67aabdSBjoern A. Zeeb s16 res;
10656d67aabdSBjoern A. Zeeb
10666d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
10676d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: plan %d, bcn_ofst %d\n",
10686d67aabdSBjoern A. Zeeb ptrn->plan, bcn_ofst);
10696d67aabdSBjoern A. Zeeb
10706d67aabdSBjoern A. Zeeb if (ptrn->plan == RTW89_MCC_PLAN_MID_BT)
10716d67aabdSBjoern A. Zeeb bt_dur_in_mid = mcc->bt_role.duration;
10726d67aabdSBjoern A. Zeeb else
10736d67aabdSBjoern A. Zeeb bt_dur_in_mid = 0;
10746d67aabdSBjoern A. Zeeb
10756d67aabdSBjoern A. Zeeb if (ref->duration < min_tob + min_toa) {
10766d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
10776d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: not meet ref dur cond\n");
10786d67aabdSBjoern A. Zeeb return -EINVAL;
10796d67aabdSBjoern A. Zeeb }
10806d67aabdSBjoern A. Zeeb
10816d67aabdSBjoern A. Zeeb if (aux->duration < min_tob + min_toa) {
10826d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
10836d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: not meet aux dur cond\n");
10846d67aabdSBjoern A. Zeeb return -EINVAL;
10856d67aabdSBjoern A. Zeeb }
10866d67aabdSBjoern A. Zeeb
10876d67aabdSBjoern A. Zeeb res = bcn_ofst - min_toa - min_tob - bt_dur_in_mid;
10886d67aabdSBjoern A. Zeeb if (res < 0) {
10896d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
10906d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: not meet bcn_ofst cond\n");
10916d67aabdSBjoern A. Zeeb return -EINVAL;
10926d67aabdSBjoern A. Zeeb }
10936d67aabdSBjoern A. Zeeb
10946d67aabdSBjoern A. Zeeb upper_toa_ref = min_t(s16, min_toa + res, ref->duration - min_tob);
10956d67aabdSBjoern A. Zeeb lower_toa_ref = min_toa;
10966d67aabdSBjoern A. Zeeb upper_tob_aux = min_t(s16, min_tob + res, aux->duration - min_toa);
10976d67aabdSBjoern A. Zeeb lower_tob_aux = min_tob;
10986d67aabdSBjoern A. Zeeb
10996d67aabdSBjoern A. Zeeb if (ref->limit.enable) {
11006d67aabdSBjoern A. Zeeb if (min_tob > ref->limit.max_tob || min_toa > ref->limit.max_toa) {
11016d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11026d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: conflict ref limit\n");
11036d67aabdSBjoern A. Zeeb return -EINVAL;
11046d67aabdSBjoern A. Zeeb }
11056d67aabdSBjoern A. Zeeb
11066d67aabdSBjoern A. Zeeb upper_toa_ref = min_t(s16, upper_toa_ref, ref->limit.max_toa);
11076d67aabdSBjoern A. Zeeb lower_toa_ref = max_t(s16, lower_toa_ref,
11086d67aabdSBjoern A. Zeeb ref->duration - ref->limit.max_tob);
11096d67aabdSBjoern A. Zeeb } else if (aux->limit.enable) {
11106d67aabdSBjoern A. Zeeb if (min_tob > aux->limit.max_tob || min_toa > aux->limit.max_toa) {
11116d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11126d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: conflict aux limit\n");
11136d67aabdSBjoern A. Zeeb return -EINVAL;
11146d67aabdSBjoern A. Zeeb }
11156d67aabdSBjoern A. Zeeb
11166d67aabdSBjoern A. Zeeb upper_tob_aux = min_t(s16, upper_tob_aux, aux->limit.max_tob);
11176d67aabdSBjoern A. Zeeb lower_tob_aux = max_t(s16, lower_tob_aux,
11186d67aabdSBjoern A. Zeeb aux->duration - aux->limit.max_toa);
11196d67aabdSBjoern A. Zeeb }
11206d67aabdSBjoern A. Zeeb
11216d67aabdSBjoern A. Zeeb upper_toa_ref = min_t(s16, upper_toa_ref,
11226d67aabdSBjoern A. Zeeb bcn_ofst - bt_dur_in_mid - lower_tob_aux);
11236d67aabdSBjoern A. Zeeb lower_toa_ref = max_t(s16, lower_toa_ref,
11246d67aabdSBjoern A. Zeeb bcn_ofst - bt_dur_in_mid - upper_tob_aux);
11256d67aabdSBjoern A. Zeeb if (lower_toa_ref > upper_toa_ref) {
11266d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11276d67aabdSBjoern A. Zeeb "MCC calc ptrn_st: conflict boundary\n");
11286d67aabdSBjoern A. Zeeb return -EINVAL;
11296d67aabdSBjoern A. Zeeb }
11306d67aabdSBjoern A. Zeeb
11316d67aabdSBjoern A. Zeeb ptrn->toa_ref = (upper_toa_ref + lower_toa_ref) / 2;
11326d67aabdSBjoern A. Zeeb ptrn->tob_ref = ref->duration - ptrn->toa_ref;
11336d67aabdSBjoern A. Zeeb ptrn->tob_aux = bcn_ofst - ptrn->toa_ref - bt_dur_in_mid;
11346d67aabdSBjoern A. Zeeb ptrn->toa_aux = aux->duration - ptrn->tob_aux;
11356d67aabdSBjoern A. Zeeb return 0;
11366d67aabdSBjoern A. Zeeb }
11376d67aabdSBjoern A. Zeeb
rtw89_mcc_calc_pattern(struct rtw89_dev * rtwdev,bool hdl_bt)11386d67aabdSBjoern A. Zeeb static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
11396d67aabdSBjoern A. Zeeb {
11406d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
11416d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
11426d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
11436d67aabdSBjoern A. Zeeb bool sel_plan[NUM_OF_RTW89_MCC_PLAN] = {};
11446d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern ptrn;
11456d67aabdSBjoern A. Zeeb int ret;
11466d67aabdSBjoern A. Zeeb int i;
11476d67aabdSBjoern A. Zeeb
11486d67aabdSBjoern A. Zeeb if (ref->limit.enable && aux->limit.enable) {
11496d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11506d67aabdSBjoern A. Zeeb "MCC calc ptrn: not support dual limited roles\n");
11516d67aabdSBjoern A. Zeeb return -EINVAL;
11526d67aabdSBjoern A. Zeeb }
11536d67aabdSBjoern A. Zeeb
11546d67aabdSBjoern A. Zeeb if (ref->limit.enable &&
11556d67aabdSBjoern A. Zeeb ref->duration > ref->limit.max_tob + ref->limit.max_toa) {
11566d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11576d67aabdSBjoern A. Zeeb "MCC calc ptrn: not fit ref limit\n");
11586d67aabdSBjoern A. Zeeb return -EINVAL;
11596d67aabdSBjoern A. Zeeb }
11606d67aabdSBjoern A. Zeeb
11616d67aabdSBjoern A. Zeeb if (aux->limit.enable &&
11626d67aabdSBjoern A. Zeeb aux->duration > aux->limit.max_tob + aux->limit.max_toa) {
11636d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11646d67aabdSBjoern A. Zeeb "MCC calc ptrn: not fit aux limit\n");
11656d67aabdSBjoern A. Zeeb return -EINVAL;
11666d67aabdSBjoern A. Zeeb }
11676d67aabdSBjoern A. Zeeb
11686d67aabdSBjoern A. Zeeb if (hdl_bt) {
11696d67aabdSBjoern A. Zeeb sel_plan[RTW89_MCC_PLAN_TAIL_BT] = true;
11706d67aabdSBjoern A. Zeeb sel_plan[RTW89_MCC_PLAN_MID_BT] = true;
11716d67aabdSBjoern A. Zeeb } else {
11726d67aabdSBjoern A. Zeeb sel_plan[RTW89_MCC_PLAN_NO_BT] = true;
11736d67aabdSBjoern A. Zeeb }
11746d67aabdSBjoern A. Zeeb
11756d67aabdSBjoern A. Zeeb for (i = 0; i < NUM_OF_RTW89_MCC_PLAN; i++) {
11766d67aabdSBjoern A. Zeeb if (!sel_plan[i])
11776d67aabdSBjoern A. Zeeb continue;
11786d67aabdSBjoern A. Zeeb
11796d67aabdSBjoern A. Zeeb ptrn = (typeof(ptrn)){
11806d67aabdSBjoern A. Zeeb .plan = i,
11816d67aabdSBjoern A. Zeeb };
11826d67aabdSBjoern A. Zeeb
11836d67aabdSBjoern A. Zeeb ret = __rtw89_mcc_calc_pattern_strict(rtwdev, &ptrn);
11846d67aabdSBjoern A. Zeeb if (ret)
11856d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
11866d67aabdSBjoern A. Zeeb "MCC calc ptrn_st with plan %d: fail\n", i);
11876d67aabdSBjoern A. Zeeb else
11886d67aabdSBjoern A. Zeeb goto done;
11896d67aabdSBjoern A. Zeeb }
11906d67aabdSBjoern A. Zeeb
11916d67aabdSBjoern A. Zeeb __rtw89_mcc_calc_pattern_loose(rtwdev, &ptrn, hdl_bt);
11926d67aabdSBjoern A. Zeeb
11936d67aabdSBjoern A. Zeeb done:
11946d67aabdSBjoern A. Zeeb rtw89_mcc_assign_pattern(rtwdev, &ptrn);
11956d67aabdSBjoern A. Zeeb return 0;
11966d67aabdSBjoern A. Zeeb }
11976d67aabdSBjoern A. Zeeb
rtw89_mcc_set_default_pattern(struct rtw89_dev * rtwdev)11986d67aabdSBjoern A. Zeeb static void rtw89_mcc_set_default_pattern(struct rtw89_dev *rtwdev)
11996d67aabdSBjoern A. Zeeb {
12006d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
12016d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
12026d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
12036d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern tmp = {};
12046d67aabdSBjoern A. Zeeb
12056d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
12066d67aabdSBjoern A. Zeeb "MCC use default pattern unexpectedly\n");
12076d67aabdSBjoern A. Zeeb
12086d67aabdSBjoern A. Zeeb tmp.plan = RTW89_MCC_PLAN_NO_BT;
12096d67aabdSBjoern A. Zeeb tmp.tob_ref = ref->duration / 2;
12106d67aabdSBjoern A. Zeeb tmp.toa_ref = ref->duration - tmp.tob_ref;
12116d67aabdSBjoern A. Zeeb tmp.tob_aux = aux->duration / 2;
12126d67aabdSBjoern A. Zeeb tmp.toa_aux = aux->duration - tmp.tob_aux;
12136d67aabdSBjoern A. Zeeb
12146d67aabdSBjoern A. Zeeb rtw89_mcc_assign_pattern(rtwdev, &tmp);
12156d67aabdSBjoern A. Zeeb }
12166d67aabdSBjoern A. Zeeb
rtw89_mcc_set_duration_go_sta(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * role_go,struct rtw89_mcc_role * role_sta)12176d67aabdSBjoern A. Zeeb static void rtw89_mcc_set_duration_go_sta(struct rtw89_dev *rtwdev,
12186d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role_go,
12196d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role_sta)
12206d67aabdSBjoern A. Zeeb {
12216d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
12226d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
12236d67aabdSBjoern A. Zeeb u16 mcc_intvl = config->mcc_interval;
12246d67aabdSBjoern A. Zeeb u16 dur_go, dur_sta;
12256d67aabdSBjoern A. Zeeb
12266d67aabdSBjoern A. Zeeb dur_go = clamp_t(u16, role_go->duration, RTW89_MCC_MIN_GO_DURATION,
12276d67aabdSBjoern A. Zeeb mcc_intvl - RTW89_MCC_MIN_STA_DURATION);
12286d67aabdSBjoern A. Zeeb if (role_go->limit.enable)
12296d67aabdSBjoern A. Zeeb dur_go = min(dur_go, role_go->limit.max_dur);
12306d67aabdSBjoern A. Zeeb dur_sta = mcc_intvl - dur_go;
12316d67aabdSBjoern A. Zeeb
12326d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
12336d67aabdSBjoern A. Zeeb "MCC set dur: (go, sta) {%d, %d} -> {%d, %d}\n",
12346d67aabdSBjoern A. Zeeb role_go->duration, role_sta->duration, dur_go, dur_sta);
12356d67aabdSBjoern A. Zeeb
12366d67aabdSBjoern A. Zeeb role_go->duration = dur_go;
12376d67aabdSBjoern A. Zeeb role_sta->duration = dur_sta;
12386d67aabdSBjoern A. Zeeb }
12396d67aabdSBjoern A. Zeeb
rtw89_mcc_set_duration_gc_sta(struct rtw89_dev * rtwdev)12406d67aabdSBjoern A. Zeeb static void rtw89_mcc_set_duration_gc_sta(struct rtw89_dev *rtwdev)
12416d67aabdSBjoern A. Zeeb {
12426d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
12436d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
12446d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
12456d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
12466d67aabdSBjoern A. Zeeb u16 mcc_intvl = config->mcc_interval;
12476d67aabdSBjoern A. Zeeb u16 dur_ref, dur_aux;
12486d67aabdSBjoern A. Zeeb
12496d67aabdSBjoern A. Zeeb if (ref->duration < RTW89_MCC_MIN_STA_DURATION) {
12506d67aabdSBjoern A. Zeeb dur_ref = RTW89_MCC_MIN_STA_DURATION;
12516d67aabdSBjoern A. Zeeb dur_aux = mcc_intvl - dur_ref;
12526d67aabdSBjoern A. Zeeb } else if (aux->duration < RTW89_MCC_MIN_STA_DURATION) {
12536d67aabdSBjoern A. Zeeb dur_aux = RTW89_MCC_MIN_STA_DURATION;
12546d67aabdSBjoern A. Zeeb dur_ref = mcc_intvl - dur_aux;
12556d67aabdSBjoern A. Zeeb } else {
12566d67aabdSBjoern A. Zeeb dur_ref = ref->duration;
12576d67aabdSBjoern A. Zeeb dur_aux = mcc_intvl - dur_ref;
12586d67aabdSBjoern A. Zeeb }
12596d67aabdSBjoern A. Zeeb
12606d67aabdSBjoern A. Zeeb if (ref->limit.enable) {
12616d67aabdSBjoern A. Zeeb dur_ref = min(dur_ref, ref->limit.max_dur);
12626d67aabdSBjoern A. Zeeb dur_aux = mcc_intvl - dur_ref;
12636d67aabdSBjoern A. Zeeb } else if (aux->limit.enable) {
12646d67aabdSBjoern A. Zeeb dur_aux = min(dur_aux, aux->limit.max_dur);
12656d67aabdSBjoern A. Zeeb dur_ref = mcc_intvl - dur_aux;
12666d67aabdSBjoern A. Zeeb }
12676d67aabdSBjoern A. Zeeb
12686d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
12696d67aabdSBjoern A. Zeeb "MCC set dur: (ref, aux) {%d ~ %d} -> {%d ~ %d}\n",
12706d67aabdSBjoern A. Zeeb ref->duration, aux->duration, dur_ref, dur_aux);
12716d67aabdSBjoern A. Zeeb
12726d67aabdSBjoern A. Zeeb ref->duration = dur_ref;
12736d67aabdSBjoern A. Zeeb aux->duration = dur_aux;
12746d67aabdSBjoern A. Zeeb }
12756d67aabdSBjoern A. Zeeb
12766d67aabdSBjoern A. Zeeb struct rtw89_mcc_mod_dur_data {
12776d67aabdSBjoern A. Zeeb u16 available;
12786d67aabdSBjoern A. Zeeb struct {
12796d67aabdSBjoern A. Zeeb u16 dur;
12806d67aabdSBjoern A. Zeeb u16 room;
12816d67aabdSBjoern A. Zeeb } parm[NUM_OF_RTW89_MCC_ROLES];
12826d67aabdSBjoern A. Zeeb };
12836d67aabdSBjoern A. Zeeb
rtw89_mcc_mod_dur_get_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)12846d67aabdSBjoern A. Zeeb static int rtw89_mcc_mod_dur_get_iterator(struct rtw89_dev *rtwdev,
12856d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
12866d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
12876d67aabdSBjoern A. Zeeb void *data)
12886d67aabdSBjoern A. Zeeb {
12896d67aabdSBjoern A. Zeeb struct rtw89_mcc_mod_dur_data *p = data;
12906d67aabdSBjoern A. Zeeb u16 min;
12916d67aabdSBjoern A. Zeeb
12926d67aabdSBjoern A. Zeeb p->parm[ordered_idx].dur = mcc_role->duration;
12936d67aabdSBjoern A. Zeeb
12946d67aabdSBjoern A. Zeeb if (mcc_role->is_go)
12956d67aabdSBjoern A. Zeeb min = RTW89_MCC_MIN_GO_DURATION;
12966d67aabdSBjoern A. Zeeb else
12976d67aabdSBjoern A. Zeeb min = RTW89_MCC_MIN_STA_DURATION;
12986d67aabdSBjoern A. Zeeb
12996d67aabdSBjoern A. Zeeb p->parm[ordered_idx].room = max_t(s32, p->parm[ordered_idx].dur - min, 0);
13006d67aabdSBjoern A. Zeeb
13016d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13026d67aabdSBjoern A. Zeeb "MCC mod dur: chk role[%u]: dur %u, min %u, room %u\n",
13036d67aabdSBjoern A. Zeeb ordered_idx, p->parm[ordered_idx].dur, min,
13046d67aabdSBjoern A. Zeeb p->parm[ordered_idx].room);
13056d67aabdSBjoern A. Zeeb
13066d67aabdSBjoern A. Zeeb p->available += p->parm[ordered_idx].room;
13076d67aabdSBjoern A. Zeeb return 0;
13086d67aabdSBjoern A. Zeeb }
13096d67aabdSBjoern A. Zeeb
rtw89_mcc_mod_dur_put_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)13106d67aabdSBjoern A. Zeeb static int rtw89_mcc_mod_dur_put_iterator(struct rtw89_dev *rtwdev,
13116d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
13126d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
13136d67aabdSBjoern A. Zeeb void *data)
13146d67aabdSBjoern A. Zeeb {
13156d67aabdSBjoern A. Zeeb struct rtw89_mcc_mod_dur_data *p = data;
13166d67aabdSBjoern A. Zeeb
13176d67aabdSBjoern A. Zeeb mcc_role->duration = p->parm[ordered_idx].dur;
13186d67aabdSBjoern A. Zeeb
13196d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13206d67aabdSBjoern A. Zeeb "MCC mod dur: set role[%u]: dur %u\n",
13216d67aabdSBjoern A. Zeeb ordered_idx, p->parm[ordered_idx].dur);
13226d67aabdSBjoern A. Zeeb return 0;
13236d67aabdSBjoern A. Zeeb }
13246d67aabdSBjoern A. Zeeb
rtw89_mcc_mod_duration_dual_2ghz_with_bt(struct rtw89_dev * rtwdev)13256d67aabdSBjoern A. Zeeb static void rtw89_mcc_mod_duration_dual_2ghz_with_bt(struct rtw89_dev *rtwdev)
13266d67aabdSBjoern A. Zeeb {
13276d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
13286d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
13296d67aabdSBjoern A. Zeeb struct rtw89_mcc_mod_dur_data data = {};
13306d67aabdSBjoern A. Zeeb u16 mcc_intvl = config->mcc_interval;
13316d67aabdSBjoern A. Zeeb u16 bt_dur = mcc->bt_role.duration;
13326d67aabdSBjoern A. Zeeb u16 wifi_dur;
13336d67aabdSBjoern A. Zeeb
13346d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13356d67aabdSBjoern A. Zeeb "MCC mod dur (dual 2ghz): mcc_intvl %u, raw bt_dur %u\n",
13366d67aabdSBjoern A. Zeeb mcc_intvl, bt_dur);
13376d67aabdSBjoern A. Zeeb
13386d67aabdSBjoern A. Zeeb rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_get_iterator, &data);
13396d67aabdSBjoern A. Zeeb
13406d67aabdSBjoern A. Zeeb bt_dur = clamp_t(u16, bt_dur, 1, data.available / 3);
13416d67aabdSBjoern A. Zeeb wifi_dur = mcc_intvl - bt_dur;
13426d67aabdSBjoern A. Zeeb
13436d67aabdSBjoern A. Zeeb if (data.parm[0].room <= data.parm[1].room) {
13446d67aabdSBjoern A. Zeeb data.parm[0].dur -= min_t(u16, bt_dur / 2, data.parm[0].room);
13456d67aabdSBjoern A. Zeeb data.parm[1].dur = wifi_dur - data.parm[0].dur;
13466d67aabdSBjoern A. Zeeb } else {
13476d67aabdSBjoern A. Zeeb data.parm[1].dur -= min_t(u16, bt_dur / 2, data.parm[1].room);
13486d67aabdSBjoern A. Zeeb data.parm[0].dur = wifi_dur - data.parm[1].dur;
13496d67aabdSBjoern A. Zeeb }
13506d67aabdSBjoern A. Zeeb
13516d67aabdSBjoern A. Zeeb rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_put_iterator, &data);
13526d67aabdSBjoern A. Zeeb
13536d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC mod dur: set bt: dur %u\n", bt_dur);
13546d67aabdSBjoern A. Zeeb mcc->bt_role.duration = bt_dur;
13556d67aabdSBjoern A. Zeeb }
13566d67aabdSBjoern A. Zeeb
13576d67aabdSBjoern A. Zeeb static
rtw89_mcc_mod_duration_diff_band_with_bt(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * role_2ghz,struct rtw89_mcc_role * role_non_2ghz)13586d67aabdSBjoern A. Zeeb void rtw89_mcc_mod_duration_diff_band_with_bt(struct rtw89_dev *rtwdev,
13596d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role_2ghz,
13606d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *role_non_2ghz)
13616d67aabdSBjoern A. Zeeb {
13626d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
13636d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
13646d67aabdSBjoern A. Zeeb u16 dur_2ghz, dur_non_2ghz;
13656d67aabdSBjoern A. Zeeb u16 bt_dur, mcc_intvl;
13666d67aabdSBjoern A. Zeeb
13676d67aabdSBjoern A. Zeeb dur_2ghz = role_2ghz->duration;
13686d67aabdSBjoern A. Zeeb dur_non_2ghz = role_non_2ghz->duration;
13696d67aabdSBjoern A. Zeeb mcc_intvl = config->mcc_interval;
13706d67aabdSBjoern A. Zeeb bt_dur = mcc->bt_role.duration;
13716d67aabdSBjoern A. Zeeb
13726d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13736d67aabdSBjoern A. Zeeb "MCC mod dur (diff band): mcc_intvl %u, bt_dur %u\n",
13746d67aabdSBjoern A. Zeeb mcc_intvl, bt_dur);
13756d67aabdSBjoern A. Zeeb
13766d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13776d67aabdSBjoern A. Zeeb "MCC mod dur: check dur_2ghz %u, dur_non_2ghz %u\n",
13786d67aabdSBjoern A. Zeeb dur_2ghz, dur_non_2ghz);
13796d67aabdSBjoern A. Zeeb
13806d67aabdSBjoern A. Zeeb if (dur_non_2ghz >= bt_dur) {
13816d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13826d67aabdSBjoern A. Zeeb "MCC mod dur: dur_non_2ghz is enough for bt\n");
13836d67aabdSBjoern A. Zeeb return;
13846d67aabdSBjoern A. Zeeb }
13856d67aabdSBjoern A. Zeeb
13866d67aabdSBjoern A. Zeeb dur_non_2ghz = bt_dur;
13876d67aabdSBjoern A. Zeeb dur_2ghz = mcc_intvl - dur_non_2ghz;
13886d67aabdSBjoern A. Zeeb
13896d67aabdSBjoern A. Zeeb if (role_non_2ghz->limit.enable) {
13906d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13916d67aabdSBjoern A. Zeeb "MCC mod dur: dur_non_2ghz is limited with max %u\n",
13926d67aabdSBjoern A. Zeeb role_non_2ghz->limit.max_dur);
13936d67aabdSBjoern A. Zeeb
13946d67aabdSBjoern A. Zeeb dur_non_2ghz = min(dur_non_2ghz, role_non_2ghz->limit.max_dur);
13956d67aabdSBjoern A. Zeeb dur_2ghz = mcc_intvl - dur_non_2ghz;
13966d67aabdSBjoern A. Zeeb }
13976d67aabdSBjoern A. Zeeb
13986d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
13996d67aabdSBjoern A. Zeeb "MCC mod dur: set dur_2ghz %u, dur_non_2ghz %u\n",
14006d67aabdSBjoern A. Zeeb dur_2ghz, dur_non_2ghz);
14016d67aabdSBjoern A. Zeeb
14026d67aabdSBjoern A. Zeeb role_2ghz->duration = dur_2ghz;
14036d67aabdSBjoern A. Zeeb role_non_2ghz->duration = dur_non_2ghz;
14046d67aabdSBjoern A. Zeeb }
14056d67aabdSBjoern A. Zeeb
rtw89_mcc_duration_decision_on_bt(struct rtw89_dev * rtwdev)14066d67aabdSBjoern A. Zeeb static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)
14076d67aabdSBjoern A. Zeeb {
14086d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
14096d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
14106d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
14116d67aabdSBjoern A. Zeeb struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
14126d67aabdSBjoern A. Zeeb
14136d67aabdSBjoern A. Zeeb if (!bt_role->duration)
14146d67aabdSBjoern A. Zeeb return false;
14156d67aabdSBjoern A. Zeeb
14166d67aabdSBjoern A. Zeeb if (ref->is_2ghz && aux->is_2ghz) {
14176d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
14186d67aabdSBjoern A. Zeeb "MCC dual roles are on 2GHz; consider BT duration\n");
14196d67aabdSBjoern A. Zeeb
14206d67aabdSBjoern A. Zeeb rtw89_mcc_mod_duration_dual_2ghz_with_bt(rtwdev);
14216d67aabdSBjoern A. Zeeb return true;
14226d67aabdSBjoern A. Zeeb }
14236d67aabdSBjoern A. Zeeb
14246d67aabdSBjoern A. Zeeb if (!ref->is_2ghz && !aux->is_2ghz) {
14256d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
14266d67aabdSBjoern A. Zeeb "MCC dual roles are not on 2GHz; ignore BT duration\n");
14276d67aabdSBjoern A. Zeeb return false;
14286d67aabdSBjoern A. Zeeb }
14296d67aabdSBjoern A. Zeeb
14306d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
14316d67aabdSBjoern A. Zeeb "MCC one role is on 2GHz; modify another for BT duration\n");
14326d67aabdSBjoern A. Zeeb
14336d67aabdSBjoern A. Zeeb if (ref->is_2ghz)
14346d67aabdSBjoern A. Zeeb rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, ref, aux);
14356d67aabdSBjoern A. Zeeb else
14366d67aabdSBjoern A. Zeeb rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, aux, ref);
14376d67aabdSBjoern A. Zeeb
14386d67aabdSBjoern A. Zeeb return false;
14396d67aabdSBjoern A. Zeeb }
14406d67aabdSBjoern A. Zeeb
rtw89_mcc_sync_tbtt(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * tgt,struct rtw89_mcc_role * src,bool ref_is_src)14416d67aabdSBjoern A. Zeeb static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
14426d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *tgt,
14436d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *src,
14446d67aabdSBjoern A. Zeeb bool ref_is_src)
14456d67aabdSBjoern A. Zeeb {
14466d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
14476d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
14486d67aabdSBjoern A. Zeeb u16 beacon_offset_us = ieee80211_tu_to_usec(config->beacon_offset);
14496d67aabdSBjoern A. Zeeb u32 bcn_intvl_src_us = ieee80211_tu_to_usec(src->beacon_interval);
14506d67aabdSBjoern A. Zeeb u32 cur_tbtt_ofst_src;
14516d67aabdSBjoern A. Zeeb u32 tsf_ofst_tgt;
14526d67aabdSBjoern A. Zeeb u32 remainder;
14536d67aabdSBjoern A. Zeeb u64 tbtt_tgt;
14546d67aabdSBjoern A. Zeeb u64 tsf_src;
14556d67aabdSBjoern A. Zeeb int ret;
14566d67aabdSBjoern A. Zeeb
1457df279a26SBjoern A. Zeeb ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src);
14586d67aabdSBjoern A. Zeeb if (ret) {
14596d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
14606d67aabdSBjoern A. Zeeb return;
14616d67aabdSBjoern A. Zeeb }
14626d67aabdSBjoern A. Zeeb
14636d67aabdSBjoern A. Zeeb cur_tbtt_ofst_src = rtw89_mcc_get_tbtt_ofst(rtwdev, src, tsf_src);
14646d67aabdSBjoern A. Zeeb
14656d67aabdSBjoern A. Zeeb if (ref_is_src)
14666d67aabdSBjoern A. Zeeb tbtt_tgt = tsf_src - cur_tbtt_ofst_src + beacon_offset_us;
14676d67aabdSBjoern A. Zeeb else
14686d67aabdSBjoern A. Zeeb tbtt_tgt = tsf_src - cur_tbtt_ofst_src +
14696d67aabdSBjoern A. Zeeb (bcn_intvl_src_us - beacon_offset_us);
14706d67aabdSBjoern A. Zeeb
14716d67aabdSBjoern A. Zeeb div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder);
14726d67aabdSBjoern A. Zeeb tsf_ofst_tgt = bcn_intvl_src_us - remainder;
14736d67aabdSBjoern A. Zeeb
1474df279a26SBjoern A. Zeeb config->sync.macid_tgt = tgt->rtwvif_link->mac_id;
1475df279a26SBjoern A. Zeeb config->sync.band_tgt = tgt->rtwvif_link->mac_idx;
1476df279a26SBjoern A. Zeeb config->sync.port_tgt = tgt->rtwvif_link->port;
1477df279a26SBjoern A. Zeeb config->sync.macid_src = src->rtwvif_link->mac_id;
1478df279a26SBjoern A. Zeeb config->sync.band_src = src->rtwvif_link->mac_idx;
1479df279a26SBjoern A. Zeeb config->sync.port_src = src->rtwvif_link->port;
14806d67aabdSBjoern A. Zeeb config->sync.offset = tsf_ofst_tgt / 1024;
14816d67aabdSBjoern A. Zeeb config->sync.enable = true;
14826d67aabdSBjoern A. Zeeb
14836d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
14846d67aabdSBjoern A. Zeeb "MCC sync tbtt: tgt %d, src %d, offset %d\n",
14856d67aabdSBjoern A. Zeeb config->sync.macid_tgt, config->sync.macid_src,
14866d67aabdSBjoern A. Zeeb config->sync.offset);
14876d67aabdSBjoern A. Zeeb
1488df279a26SBjoern A. Zeeb rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link,
14896d67aabdSBjoern A. Zeeb config->sync.offset);
14906d67aabdSBjoern A. Zeeb }
14916d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_start_tsf(struct rtw89_dev * rtwdev)14926d67aabdSBjoern A. Zeeb static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
14936d67aabdSBjoern A. Zeeb {
14946d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
14956d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
14966d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
14976d67aabdSBjoern A. Zeeb u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
14986d67aabdSBjoern A. Zeeb u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
1499df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link;
15006d67aabdSBjoern A. Zeeb u64 tsf, start_tsf;
15016d67aabdSBjoern A. Zeeb u32 cur_tbtt_ofst;
15026d67aabdSBjoern A. Zeeb u64 min_time;
15036d67aabdSBjoern A. Zeeb int ret;
15046d67aabdSBjoern A. Zeeb
1505df279a26SBjoern A. Zeeb ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
15066d67aabdSBjoern A. Zeeb if (ret) {
15076d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
15086d67aabdSBjoern A. Zeeb return ret;
15096d67aabdSBjoern A. Zeeb }
15106d67aabdSBjoern A. Zeeb
15116d67aabdSBjoern A. Zeeb min_time = tsf;
15126d67aabdSBjoern A. Zeeb if (ref->is_go)
15136d67aabdSBjoern A. Zeeb min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);
15146d67aabdSBjoern A. Zeeb else
15156d67aabdSBjoern A. Zeeb min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);
15166d67aabdSBjoern A. Zeeb
15176d67aabdSBjoern A. Zeeb cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf);
15186d67aabdSBjoern A. Zeeb start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us;
15196d67aabdSBjoern A. Zeeb while (start_tsf < min_time)
15206d67aabdSBjoern A. Zeeb start_tsf += bcn_intvl_ref_us;
15216d67aabdSBjoern A. Zeeb
15226d67aabdSBjoern A. Zeeb config->start_tsf = start_tsf;
15236d67aabdSBjoern A. Zeeb return 0;
15246d67aabdSBjoern A. Zeeb }
15256d67aabdSBjoern A. Zeeb
rtw89_mcc_fill_config(struct rtw89_dev * rtwdev)15266d67aabdSBjoern A. Zeeb static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
15276d67aabdSBjoern A. Zeeb {
15286d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
15296d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
15306d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
15316d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
15326d67aabdSBjoern A. Zeeb bool hdl_bt;
15336d67aabdSBjoern A. Zeeb int ret;
15346d67aabdSBjoern A. Zeeb
15356d67aabdSBjoern A. Zeeb memset(config, 0, sizeof(*config));
15366d67aabdSBjoern A. Zeeb
15376d67aabdSBjoern A. Zeeb switch (mcc->mode) {
15386d67aabdSBjoern A. Zeeb case RTW89_MCC_MODE_GO_STA:
15396d67aabdSBjoern A. Zeeb config->beacon_offset = RTW89_MCC_DFLT_BCN_OFST_TIME;
15406d67aabdSBjoern A. Zeeb if (ref->is_go) {
15416d67aabdSBjoern A. Zeeb rtw89_mcc_sync_tbtt(rtwdev, ref, aux, false);
15426d67aabdSBjoern A. Zeeb config->mcc_interval = ref->beacon_interval;
15436d67aabdSBjoern A. Zeeb rtw89_mcc_set_duration_go_sta(rtwdev, ref, aux);
15446d67aabdSBjoern A. Zeeb } else {
15456d67aabdSBjoern A. Zeeb rtw89_mcc_sync_tbtt(rtwdev, aux, ref, true);
15466d67aabdSBjoern A. Zeeb config->mcc_interval = aux->beacon_interval;
15476d67aabdSBjoern A. Zeeb rtw89_mcc_set_duration_go_sta(rtwdev, aux, ref);
15486d67aabdSBjoern A. Zeeb }
15496d67aabdSBjoern A. Zeeb break;
15506d67aabdSBjoern A. Zeeb case RTW89_MCC_MODE_GC_STA:
15516d67aabdSBjoern A. Zeeb config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
15526d67aabdSBjoern A. Zeeb config->mcc_interval = ref->beacon_interval;
15536d67aabdSBjoern A. Zeeb rtw89_mcc_set_duration_gc_sta(rtwdev);
15546d67aabdSBjoern A. Zeeb break;
15556d67aabdSBjoern A. Zeeb default:
15566d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC unknown mode: %d\n", mcc->mode);
15576d67aabdSBjoern A. Zeeb return -EFAULT;
15586d67aabdSBjoern A. Zeeb }
15596d67aabdSBjoern A. Zeeb
15606d67aabdSBjoern A. Zeeb hdl_bt = rtw89_mcc_duration_decision_on_bt(rtwdev);
15616d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC handle bt: %d\n", hdl_bt);
15626d67aabdSBjoern A. Zeeb
15636d67aabdSBjoern A. Zeeb ret = rtw89_mcc_calc_pattern(rtwdev, hdl_bt);
15646d67aabdSBjoern A. Zeeb if (!ret)
15656d67aabdSBjoern A. Zeeb goto bottom;
15666d67aabdSBjoern A. Zeeb
15676d67aabdSBjoern A. Zeeb rtw89_mcc_set_default_pattern(rtwdev);
15686d67aabdSBjoern A. Zeeb
15696d67aabdSBjoern A. Zeeb bottom:
15706d67aabdSBjoern A. Zeeb return rtw89_mcc_fill_start_tsf(rtwdev);
15716d67aabdSBjoern A. Zeeb }
15726d67aabdSBjoern A. Zeeb
__mcc_fw_add_role(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * role)15736d67aabdSBjoern A. Zeeb static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
15746d67aabdSBjoern A. Zeeb {
15756d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
15766d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
15776d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
15786d67aabdSBjoern A. Zeeb struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
15796d67aabdSBjoern A. Zeeb struct rtw89_mcc_policy *policy = &role->policy;
15806d67aabdSBjoern A. Zeeb struct rtw89_fw_mcc_add_req req = {};
15816d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan;
15826d67aabdSBjoern A. Zeeb int ret;
15836d67aabdSBjoern A. Zeeb
1584df279a26SBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
15856d67aabdSBjoern A. Zeeb req.central_ch_seg0 = chan->channel;
15866d67aabdSBjoern A. Zeeb req.primary_ch = chan->primary_channel;
15876d67aabdSBjoern A. Zeeb req.bandwidth = chan->band_width;
15886d67aabdSBjoern A. Zeeb req.ch_band_type = chan->band_type;
15896d67aabdSBjoern A. Zeeb
1590df279a26SBjoern A. Zeeb req.macid = role->rtwvif_link->mac_id;
15916d67aabdSBjoern A. Zeeb req.group = mcc->group;
15926d67aabdSBjoern A. Zeeb req.c2h_rpt = policy->c2h_rpt;
15936d67aabdSBjoern A. Zeeb req.tx_null_early = policy->tx_null_early;
15946d67aabdSBjoern A. Zeeb req.dis_tx_null = policy->dis_tx_null;
15956d67aabdSBjoern A. Zeeb req.in_curr_ch = policy->in_curr_ch;
15966d67aabdSBjoern A. Zeeb req.sw_retry_count = policy->sw_retry_count;
15976d67aabdSBjoern A. Zeeb req.dis_sw_retry = policy->dis_sw_retry;
15986d67aabdSBjoern A. Zeeb req.duration = role->duration;
15996d67aabdSBjoern A. Zeeb req.btc_in_2g = false;
16006d67aabdSBjoern A. Zeeb
16016d67aabdSBjoern A. Zeeb if (courtesy->enable && courtesy->macid_src == req.macid) {
16026d67aabdSBjoern A. Zeeb req.courtesy_target = courtesy->macid_tgt;
16036d67aabdSBjoern A. Zeeb req.courtesy_num = courtesy->slot_num;
16046d67aabdSBjoern A. Zeeb req.courtesy_en = true;
16056d67aabdSBjoern A. Zeeb }
16066d67aabdSBjoern A. Zeeb
16076d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
16086d67aabdSBjoern A. Zeeb if (ret) {
16096d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
16106d67aabdSBjoern A. Zeeb "MCC h2c failed to add wifi role: %d\n", ret);
16116d67aabdSBjoern A. Zeeb return ret;
16126d67aabdSBjoern A. Zeeb }
16136d67aabdSBjoern A. Zeeb
16146d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
1615df279a26SBjoern A. Zeeb role->rtwvif_link->mac_id,
16166d67aabdSBjoern A. Zeeb role->macid_bitmap);
16176d67aabdSBjoern A. Zeeb if (ret) {
16186d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
16196d67aabdSBjoern A. Zeeb "MCC h2c failed to set macid bitmap: %d\n", ret);
16206d67aabdSBjoern A. Zeeb return ret;
16216d67aabdSBjoern A. Zeeb }
16226d67aabdSBjoern A. Zeeb
16236d67aabdSBjoern A. Zeeb return 0;
16246d67aabdSBjoern A. Zeeb }
16256d67aabdSBjoern A. Zeeb
16266d67aabdSBjoern A. Zeeb static
__mrc_fw_add_role(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * role,struct rtw89_fw_mrc_add_arg * arg,u8 slot_idx)16276d67aabdSBjoern A. Zeeb void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
16286d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
16296d67aabdSBjoern A. Zeeb {
16306d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
16316d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
16326d67aabdSBjoern A. Zeeb struct rtw89_mcc_policy *policy = &role->policy;
16336d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_slot_arg *slot_arg;
16346d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan;
16356d67aabdSBjoern A. Zeeb
16366d67aabdSBjoern A. Zeeb slot_arg = &arg->slots[slot_idx];
16376d67aabdSBjoern A. Zeeb role->slot_idx = slot_idx;
16386d67aabdSBjoern A. Zeeb
16396d67aabdSBjoern A. Zeeb slot_arg->duration = role->duration;
16406d67aabdSBjoern A. Zeeb slot_arg->role_num = 1;
16416d67aabdSBjoern A. Zeeb
1642df279a26SBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
16436d67aabdSBjoern A. Zeeb
16446d67aabdSBjoern A. Zeeb slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
16456d67aabdSBjoern A. Zeeb slot_arg->roles[0].is_master = role == ref;
16466d67aabdSBjoern A. Zeeb slot_arg->roles[0].band = chan->band_type;
16476d67aabdSBjoern A. Zeeb slot_arg->roles[0].bw = chan->band_width;
16486d67aabdSBjoern A. Zeeb slot_arg->roles[0].central_ch = chan->channel;
16496d67aabdSBjoern A. Zeeb slot_arg->roles[0].primary_ch = chan->primary_channel;
16506d67aabdSBjoern A. Zeeb slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
16516d67aabdSBjoern A. Zeeb slot_arg->roles[0].null_early = policy->tx_null_early;
1652df279a26SBjoern A. Zeeb slot_arg->roles[0].macid = role->rtwvif_link->mac_id;
16536d67aabdSBjoern A. Zeeb slot_arg->roles[0].macid_main_bitmap =
16546d67aabdSBjoern A. Zeeb rtw89_mcc_role_fw_macid_bitmap_to_u32(role);
16556d67aabdSBjoern A. Zeeb }
16566d67aabdSBjoern A. Zeeb
__mcc_fw_add_bt_role(struct rtw89_dev * rtwdev)16576d67aabdSBjoern A. Zeeb static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
16586d67aabdSBjoern A. Zeeb {
16596d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
16606d67aabdSBjoern A. Zeeb struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
16616d67aabdSBjoern A. Zeeb struct rtw89_fw_mcc_add_req req = {};
16626d67aabdSBjoern A. Zeeb int ret;
16636d67aabdSBjoern A. Zeeb
16646d67aabdSBjoern A. Zeeb req.group = mcc->group;
16656d67aabdSBjoern A. Zeeb req.duration = bt_role->duration;
16666d67aabdSBjoern A. Zeeb req.btc_in_2g = true;
16676d67aabdSBjoern A. Zeeb
16686d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
16696d67aabdSBjoern A. Zeeb if (ret) {
16706d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
16716d67aabdSBjoern A. Zeeb "MCC h2c failed to add bt role: %d\n", ret);
16726d67aabdSBjoern A. Zeeb return ret;
16736d67aabdSBjoern A. Zeeb }
16746d67aabdSBjoern A. Zeeb
16756d67aabdSBjoern A. Zeeb return 0;
16766d67aabdSBjoern A. Zeeb }
16776d67aabdSBjoern A. Zeeb
16786d67aabdSBjoern A. Zeeb static
__mrc_fw_add_bt_role(struct rtw89_dev * rtwdev,struct rtw89_fw_mrc_add_arg * arg,u8 slot_idx)16796d67aabdSBjoern A. Zeeb void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev,
16806d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
16816d67aabdSBjoern A. Zeeb {
16826d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
16836d67aabdSBjoern A. Zeeb struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
16846d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx];
16856d67aabdSBjoern A. Zeeb
16866d67aabdSBjoern A. Zeeb slot_arg->duration = bt_role->duration;
16876d67aabdSBjoern A. Zeeb slot_arg->role_num = 1;
16886d67aabdSBjoern A. Zeeb
16896d67aabdSBjoern A. Zeeb slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT;
16906d67aabdSBjoern A. Zeeb }
16916d67aabdSBjoern A. Zeeb
__mcc_fw_start(struct rtw89_dev * rtwdev,bool replace)16926d67aabdSBjoern A. Zeeb static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
16936d67aabdSBjoern A. Zeeb {
16946d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
16956d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
16966d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
16976d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
16986d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
16996d67aabdSBjoern A. Zeeb struct rtw89_mcc_sync *sync = &config->sync;
17006d67aabdSBjoern A. Zeeb struct rtw89_fw_mcc_start_req req = {};
17016d67aabdSBjoern A. Zeeb int ret;
17026d67aabdSBjoern A. Zeeb
17036d67aabdSBjoern A. Zeeb if (replace) {
17046d67aabdSBjoern A. Zeeb req.old_group = mcc->group;
17056d67aabdSBjoern A. Zeeb req.old_group_action = RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE;
17066d67aabdSBjoern A. Zeeb mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
17076d67aabdSBjoern A. Zeeb }
17086d67aabdSBjoern A. Zeeb
17096d67aabdSBjoern A. Zeeb req.group = mcc->group;
17106d67aabdSBjoern A. Zeeb
17116d67aabdSBjoern A. Zeeb switch (pattern->plan) {
17126d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_TAIL_BT:
17136d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, ref);
17146d67aabdSBjoern A. Zeeb if (ret)
17156d67aabdSBjoern A. Zeeb return ret;
17166d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, aux);
17176d67aabdSBjoern A. Zeeb if (ret)
17186d67aabdSBjoern A. Zeeb return ret;
17196d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_bt_role(rtwdev);
17206d67aabdSBjoern A. Zeeb if (ret)
17216d67aabdSBjoern A. Zeeb return ret;
17226d67aabdSBjoern A. Zeeb
17236d67aabdSBjoern A. Zeeb req.btc_in_group = true;
17246d67aabdSBjoern A. Zeeb break;
17256d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_MID_BT:
17266d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, ref);
17276d67aabdSBjoern A. Zeeb if (ret)
17286d67aabdSBjoern A. Zeeb return ret;
17296d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_bt_role(rtwdev);
17306d67aabdSBjoern A. Zeeb if (ret)
17316d67aabdSBjoern A. Zeeb return ret;
17326d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, aux);
17336d67aabdSBjoern A. Zeeb if (ret)
17346d67aabdSBjoern A. Zeeb return ret;
17356d67aabdSBjoern A. Zeeb
17366d67aabdSBjoern A. Zeeb req.btc_in_group = true;
17376d67aabdSBjoern A. Zeeb break;
17386d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_NO_BT:
17396d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, ref);
17406d67aabdSBjoern A. Zeeb if (ret)
17416d67aabdSBjoern A. Zeeb return ret;
17426d67aabdSBjoern A. Zeeb ret = __mcc_fw_add_role(rtwdev, aux);
17436d67aabdSBjoern A. Zeeb if (ret)
17446d67aabdSBjoern A. Zeeb return ret;
17456d67aabdSBjoern A. Zeeb
17466d67aabdSBjoern A. Zeeb req.btc_in_group = false;
17476d67aabdSBjoern A. Zeeb break;
17486d67aabdSBjoern A. Zeeb default:
17496d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
17506d67aabdSBjoern A. Zeeb return -EFAULT;
17516d67aabdSBjoern A. Zeeb }
17526d67aabdSBjoern A. Zeeb
17536d67aabdSBjoern A. Zeeb if (sync->enable) {
17546d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_sync(rtwdev, req.group, sync->macid_src,
17556d67aabdSBjoern A. Zeeb sync->macid_tgt, sync->offset);
17566d67aabdSBjoern A. Zeeb if (ret) {
17576d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
17586d67aabdSBjoern A. Zeeb "MCC h2c failed to trigger sync: %d\n", ret);
17596d67aabdSBjoern A. Zeeb return ret;
17606d67aabdSBjoern A. Zeeb }
17616d67aabdSBjoern A. Zeeb }
17626d67aabdSBjoern A. Zeeb
1763df279a26SBjoern A. Zeeb req.macid = ref->rtwvif_link->mac_id;
17646d67aabdSBjoern A. Zeeb req.tsf_high = config->start_tsf >> 32;
17656d67aabdSBjoern A. Zeeb req.tsf_low = config->start_tsf;
17666d67aabdSBjoern A. Zeeb
17676d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_start_mcc(rtwdev, &req);
17686d67aabdSBjoern A. Zeeb if (ret) {
17696d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
17706d67aabdSBjoern A. Zeeb "MCC h2c failed to trigger start: %d\n", ret);
17716d67aabdSBjoern A. Zeeb return ret;
17726d67aabdSBjoern A. Zeeb }
17736d67aabdSBjoern A. Zeeb
17746d67aabdSBjoern A. Zeeb return 0;
17756d67aabdSBjoern A. Zeeb }
17766d67aabdSBjoern A. Zeeb
__mrc_fw_add_courtesy(struct rtw89_dev * rtwdev,struct rtw89_fw_mrc_add_arg * arg)17776d67aabdSBjoern A. Zeeb static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
17786d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_arg *arg)
17796d67aabdSBjoern A. Zeeb {
17806d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
17816d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
17826d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
17836d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
17846d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
17856d67aabdSBjoern A. Zeeb struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
17866d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
17876d67aabdSBjoern A. Zeeb u8 slot_idx_tgt;
17886d67aabdSBjoern A. Zeeb
17896d67aabdSBjoern A. Zeeb if (!courtesy->enable)
17906d67aabdSBjoern A. Zeeb return;
17916d67aabdSBjoern A. Zeeb
1792df279a26SBjoern A. Zeeb if (courtesy->macid_src == ref->rtwvif_link->mac_id) {
17936d67aabdSBjoern A. Zeeb slot_arg_src = &arg->slots[ref->slot_idx];
17946d67aabdSBjoern A. Zeeb slot_idx_tgt = aux->slot_idx;
17956d67aabdSBjoern A. Zeeb } else {
17966d67aabdSBjoern A. Zeeb slot_arg_src = &arg->slots[aux->slot_idx];
17976d67aabdSBjoern A. Zeeb slot_idx_tgt = ref->slot_idx;
17986d67aabdSBjoern A. Zeeb }
17996d67aabdSBjoern A. Zeeb
18006d67aabdSBjoern A. Zeeb slot_arg_src->courtesy_target = slot_idx_tgt;
18016d67aabdSBjoern A. Zeeb slot_arg_src->courtesy_period = courtesy->slot_num;
18026d67aabdSBjoern A. Zeeb slot_arg_src->courtesy_en = true;
18036d67aabdSBjoern A. Zeeb }
18046d67aabdSBjoern A. Zeeb
__mrc_fw_start(struct rtw89_dev * rtwdev,bool replace)18056d67aabdSBjoern A. Zeeb static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
18066d67aabdSBjoern A. Zeeb {
18076d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
18086d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
18096d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
18106d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
18116d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
18126d67aabdSBjoern A. Zeeb struct rtw89_mcc_sync *sync = &config->sync;
18136d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_start_arg start_arg = {};
18146d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_add_arg add_arg = {};
18156d67aabdSBjoern A. Zeeb int ret;
18166d67aabdSBjoern A. Zeeb
18176d67aabdSBjoern A. Zeeb BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM <
18186d67aabdSBjoern A. Zeeb NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */);
18196d67aabdSBjoern A. Zeeb
18206d67aabdSBjoern A. Zeeb if (replace) {
18216d67aabdSBjoern A. Zeeb start_arg.old_sch_idx = mcc->group;
18226d67aabdSBjoern A. Zeeb start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD;
18236d67aabdSBjoern A. Zeeb mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
18246d67aabdSBjoern A. Zeeb }
18256d67aabdSBjoern A. Zeeb
18266d67aabdSBjoern A. Zeeb add_arg.sch_idx = mcc->group;
18276d67aabdSBjoern A. Zeeb add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY;
18286d67aabdSBjoern A. Zeeb
18296d67aabdSBjoern A. Zeeb switch (pattern->plan) {
18306d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_TAIL_BT:
18316d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
18326d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
18336d67aabdSBjoern A. Zeeb __mrc_fw_add_bt_role(rtwdev, &add_arg, 2);
18346d67aabdSBjoern A. Zeeb
18356d67aabdSBjoern A. Zeeb add_arg.slot_num = 3;
18366d67aabdSBjoern A. Zeeb add_arg.btc_in_sch = true;
18376d67aabdSBjoern A. Zeeb break;
18386d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_MID_BT:
18396d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
18406d67aabdSBjoern A. Zeeb __mrc_fw_add_bt_role(rtwdev, &add_arg, 1);
18416d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, aux, &add_arg, 2);
18426d67aabdSBjoern A. Zeeb
18436d67aabdSBjoern A. Zeeb add_arg.slot_num = 3;
18446d67aabdSBjoern A. Zeeb add_arg.btc_in_sch = true;
18456d67aabdSBjoern A. Zeeb break;
18466d67aabdSBjoern A. Zeeb case RTW89_MCC_PLAN_NO_BT:
18476d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
18486d67aabdSBjoern A. Zeeb __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
18496d67aabdSBjoern A. Zeeb
18506d67aabdSBjoern A. Zeeb add_arg.slot_num = 2;
18516d67aabdSBjoern A. Zeeb add_arg.btc_in_sch = false;
18526d67aabdSBjoern A. Zeeb break;
18536d67aabdSBjoern A. Zeeb default:
18546d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
18556d67aabdSBjoern A. Zeeb return -EFAULT;
18566d67aabdSBjoern A. Zeeb }
18576d67aabdSBjoern A. Zeeb
18586d67aabdSBjoern A. Zeeb __mrc_fw_add_courtesy(rtwdev, &add_arg);
18596d67aabdSBjoern A. Zeeb
18606d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_add(rtwdev, &add_arg);
18616d67aabdSBjoern A. Zeeb if (ret) {
18626d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
18636d67aabdSBjoern A. Zeeb "MRC h2c failed to trigger add: %d\n", ret);
18646d67aabdSBjoern A. Zeeb return ret;
18656d67aabdSBjoern A. Zeeb }
18666d67aabdSBjoern A. Zeeb
18676d67aabdSBjoern A. Zeeb if (sync->enable) {
18686d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_sync_arg sync_arg = {
18696d67aabdSBjoern A. Zeeb .offset = sync->offset,
18706d67aabdSBjoern A. Zeeb .src = {
18716d67aabdSBjoern A. Zeeb .band = sync->band_src,
18726d67aabdSBjoern A. Zeeb .port = sync->port_src,
18736d67aabdSBjoern A. Zeeb },
18746d67aabdSBjoern A. Zeeb .dest = {
18756d67aabdSBjoern A. Zeeb .band = sync->band_tgt,
18766d67aabdSBjoern A. Zeeb .port = sync->port_tgt,
18776d67aabdSBjoern A. Zeeb },
18786d67aabdSBjoern A. Zeeb };
18796d67aabdSBjoern A. Zeeb
18806d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
18816d67aabdSBjoern A. Zeeb if (ret) {
18826d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
18836d67aabdSBjoern A. Zeeb "MRC h2c failed to trigger sync: %d\n", ret);
18846d67aabdSBjoern A. Zeeb return ret;
18856d67aabdSBjoern A. Zeeb }
18866d67aabdSBjoern A. Zeeb }
18876d67aabdSBjoern A. Zeeb
18886d67aabdSBjoern A. Zeeb start_arg.sch_idx = mcc->group;
18896d67aabdSBjoern A. Zeeb start_arg.start_tsf = config->start_tsf;
18906d67aabdSBjoern A. Zeeb
18916d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_start(rtwdev, &start_arg);
18926d67aabdSBjoern A. Zeeb if (ret) {
18936d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
18946d67aabdSBjoern A. Zeeb "MRC h2c failed to trigger start: %d\n", ret);
18956d67aabdSBjoern A. Zeeb return ret;
18966d67aabdSBjoern A. Zeeb }
18976d67aabdSBjoern A. Zeeb
18986d67aabdSBjoern A. Zeeb return 0;
18996d67aabdSBjoern A. Zeeb }
19006d67aabdSBjoern A. Zeeb
__mcc_fw_set_duration_no_bt(struct rtw89_dev * rtwdev,bool sync_changed)19016d67aabdSBjoern A. Zeeb static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
19026d67aabdSBjoern A. Zeeb {
19036d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
19046d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
19056d67aabdSBjoern A. Zeeb struct rtw89_mcc_sync *sync = &config->sync;
19066d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
19076d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
19086d67aabdSBjoern A. Zeeb struct rtw89_fw_mcc_duration req = {
19096d67aabdSBjoern A. Zeeb .group = mcc->group,
19106d67aabdSBjoern A. Zeeb .btc_in_group = false,
1911df279a26SBjoern A. Zeeb .start_macid = ref->rtwvif_link->mac_id,
1912df279a26SBjoern A. Zeeb .macid_x = ref->rtwvif_link->mac_id,
1913df279a26SBjoern A. Zeeb .macid_y = aux->rtwvif_link->mac_id,
19146d67aabdSBjoern A. Zeeb .duration_x = ref->duration,
19156d67aabdSBjoern A. Zeeb .duration_y = aux->duration,
19166d67aabdSBjoern A. Zeeb .start_tsf_high = config->start_tsf >> 32,
19176d67aabdSBjoern A. Zeeb .start_tsf_low = config->start_tsf,
19186d67aabdSBjoern A. Zeeb };
19196d67aabdSBjoern A. Zeeb int ret;
19206d67aabdSBjoern A. Zeeb
19216d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_set_duration(rtwdev, &req);
19226d67aabdSBjoern A. Zeeb if (ret) {
19236d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
19246d67aabdSBjoern A. Zeeb "MCC h2c failed to set duration: %d\n", ret);
19256d67aabdSBjoern A. Zeeb return ret;
19266d67aabdSBjoern A. Zeeb }
19276d67aabdSBjoern A. Zeeb
19286d67aabdSBjoern A. Zeeb if (!sync->enable || !sync_changed)
19296d67aabdSBjoern A. Zeeb return 0;
19306d67aabdSBjoern A. Zeeb
19316d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_sync(rtwdev, mcc->group, sync->macid_src,
19326d67aabdSBjoern A. Zeeb sync->macid_tgt, sync->offset);
19336d67aabdSBjoern A. Zeeb if (ret) {
19346d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
19356d67aabdSBjoern A. Zeeb "MCC h2c failed to trigger sync: %d\n", ret);
19366d67aabdSBjoern A. Zeeb return ret;
19376d67aabdSBjoern A. Zeeb }
19386d67aabdSBjoern A. Zeeb
19396d67aabdSBjoern A. Zeeb return 0;
19406d67aabdSBjoern A. Zeeb }
19416d67aabdSBjoern A. Zeeb
__mrc_fw_set_duration_no_bt(struct rtw89_dev * rtwdev,bool sync_changed)19426d67aabdSBjoern A. Zeeb static int __mrc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
19436d67aabdSBjoern A. Zeeb {
19446d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
19456d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
19466d67aabdSBjoern A. Zeeb struct rtw89_mcc_sync *sync = &config->sync;
19476d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
19486d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
19496d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_upd_duration_arg dur_arg = {
19506d67aabdSBjoern A. Zeeb .sch_idx = mcc->group,
19516d67aabdSBjoern A. Zeeb .start_tsf = config->start_tsf,
19526d67aabdSBjoern A. Zeeb .slot_num = 2,
19536d67aabdSBjoern A. Zeeb .slots[0] = {
19546d67aabdSBjoern A. Zeeb .slot_idx = ref->slot_idx,
19556d67aabdSBjoern A. Zeeb .duration = ref->duration,
19566d67aabdSBjoern A. Zeeb },
19576d67aabdSBjoern A. Zeeb .slots[1] = {
19586d67aabdSBjoern A. Zeeb .slot_idx = aux->slot_idx,
19596d67aabdSBjoern A. Zeeb .duration = aux->duration,
19606d67aabdSBjoern A. Zeeb },
19616d67aabdSBjoern A. Zeeb };
19626d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_sync_arg sync_arg = {
19636d67aabdSBjoern A. Zeeb .offset = sync->offset,
19646d67aabdSBjoern A. Zeeb .src = {
19656d67aabdSBjoern A. Zeeb .band = sync->band_src,
19666d67aabdSBjoern A. Zeeb .port = sync->port_src,
19676d67aabdSBjoern A. Zeeb },
19686d67aabdSBjoern A. Zeeb .dest = {
19696d67aabdSBjoern A. Zeeb .band = sync->band_tgt,
19706d67aabdSBjoern A. Zeeb .port = sync->port_tgt,
19716d67aabdSBjoern A. Zeeb },
19726d67aabdSBjoern A. Zeeb
19736d67aabdSBjoern A. Zeeb };
19746d67aabdSBjoern A. Zeeb int ret;
19756d67aabdSBjoern A. Zeeb
19766d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, &dur_arg);
19776d67aabdSBjoern A. Zeeb if (ret) {
19786d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
19796d67aabdSBjoern A. Zeeb "MRC h2c failed to update duration: %d\n", ret);
19806d67aabdSBjoern A. Zeeb return ret;
19816d67aabdSBjoern A. Zeeb }
19826d67aabdSBjoern A. Zeeb
19836d67aabdSBjoern A. Zeeb if (!sync->enable || !sync_changed)
19846d67aabdSBjoern A. Zeeb return 0;
19856d67aabdSBjoern A. Zeeb
19866d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
19876d67aabdSBjoern A. Zeeb if (ret) {
19886d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
19896d67aabdSBjoern A. Zeeb "MRC h2c failed to trigger sync: %d\n", ret);
19906d67aabdSBjoern A. Zeeb return ret;
19916d67aabdSBjoern A. Zeeb }
19926d67aabdSBjoern A. Zeeb
19936d67aabdSBjoern A. Zeeb return 0;
19946d67aabdSBjoern A. Zeeb }
19956d67aabdSBjoern A. Zeeb
rtw89_mcc_handle_beacon_noa(struct rtw89_dev * rtwdev,bool enable)19966d67aabdSBjoern A. Zeeb static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
19976d67aabdSBjoern A. Zeeb {
19986d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
19996d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
20006d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
20016d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
20026d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
20036d67aabdSBjoern A. Zeeb struct rtw89_mcc_sync *sync = &config->sync;
20046d67aabdSBjoern A. Zeeb struct ieee80211_p2p_noa_desc noa_desc = {};
20056d67aabdSBjoern A. Zeeb u64 start_time = config->start_tsf;
20066d67aabdSBjoern A. Zeeb u32 interval = config->mcc_interval;
2007df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_go;
20086d67aabdSBjoern A. Zeeb u32 duration;
20096d67aabdSBjoern A. Zeeb
20106d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GO_STA)
20116d67aabdSBjoern A. Zeeb return;
20126d67aabdSBjoern A. Zeeb
20136d67aabdSBjoern A. Zeeb if (ref->is_go) {
2014df279a26SBjoern A. Zeeb rtwvif_go = ref->rtwvif_link;
20156d67aabdSBjoern A. Zeeb start_time += ieee80211_tu_to_usec(ref->duration);
20166d67aabdSBjoern A. Zeeb duration = config->mcc_interval - ref->duration;
20176d67aabdSBjoern A. Zeeb } else if (aux->is_go) {
2018df279a26SBjoern A. Zeeb rtwvif_go = aux->rtwvif_link;
20196d67aabdSBjoern A. Zeeb start_time += ieee80211_tu_to_usec(pattern->tob_ref) +
20206d67aabdSBjoern A. Zeeb ieee80211_tu_to_usec(config->beacon_offset) +
20216d67aabdSBjoern A. Zeeb ieee80211_tu_to_usec(pattern->toa_aux);
20226d67aabdSBjoern A. Zeeb duration = config->mcc_interval - aux->duration;
20236d67aabdSBjoern A. Zeeb
20246d67aabdSBjoern A. Zeeb /* convert time domain from sta(ref) to GO(aux) */
20256d67aabdSBjoern A. Zeeb start_time += ieee80211_tu_to_usec(sync->offset);
20266d67aabdSBjoern A. Zeeb } else {
20276d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
20286d67aabdSBjoern A. Zeeb "MCC find no GO: skip updating beacon NoA\n");
20296d67aabdSBjoern A. Zeeb return;
20306d67aabdSBjoern A. Zeeb }
20316d67aabdSBjoern A. Zeeb
20326d67aabdSBjoern A. Zeeb rtw89_p2p_noa_renew(rtwvif_go);
20336d67aabdSBjoern A. Zeeb
20346d67aabdSBjoern A. Zeeb if (enable) {
20356d67aabdSBjoern A. Zeeb noa_desc.start_time = cpu_to_le32(start_time);
20366d67aabdSBjoern A. Zeeb noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval));
20376d67aabdSBjoern A. Zeeb noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration));
20386d67aabdSBjoern A. Zeeb noa_desc.count = 255;
20396d67aabdSBjoern A. Zeeb rtw89_p2p_noa_append(rtwvif_go, &noa_desc);
20406d67aabdSBjoern A. Zeeb }
20416d67aabdSBjoern A. Zeeb
20426d67aabdSBjoern A. Zeeb /* without chanctx, we cannot get beacon from mac80211 stack */
20436d67aabdSBjoern A. Zeeb if (!rtwvif_go->chanctx_assigned)
20446d67aabdSBjoern A. Zeeb return;
20456d67aabdSBjoern A. Zeeb
20466d67aabdSBjoern A. Zeeb rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_go);
20476d67aabdSBjoern A. Zeeb }
20486d67aabdSBjoern A. Zeeb
rtw89_mcc_start_beacon_noa(struct rtw89_dev * rtwdev)20496d67aabdSBjoern A. Zeeb static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev)
20506d67aabdSBjoern A. Zeeb {
20516d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
20526d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
20536d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
20546d67aabdSBjoern A. Zeeb
20556d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GO_STA)
20566d67aabdSBjoern A. Zeeb return;
20576d67aabdSBjoern A. Zeeb
20586d67aabdSBjoern A. Zeeb if (ref->is_go)
2059df279a26SBjoern A. Zeeb rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, true);
20606d67aabdSBjoern A. Zeeb else if (aux->is_go)
2061df279a26SBjoern A. Zeeb rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, true);
20626d67aabdSBjoern A. Zeeb
20636d67aabdSBjoern A. Zeeb rtw89_mcc_handle_beacon_noa(rtwdev, true);
20646d67aabdSBjoern A. Zeeb }
20656d67aabdSBjoern A. Zeeb
rtw89_mcc_stop_beacon_noa(struct rtw89_dev * rtwdev)20666d67aabdSBjoern A. Zeeb static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)
20676d67aabdSBjoern A. Zeeb {
20686d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
20696d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
20706d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
20716d67aabdSBjoern A. Zeeb
20726d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GO_STA)
20736d67aabdSBjoern A. Zeeb return;
20746d67aabdSBjoern A. Zeeb
20756d67aabdSBjoern A. Zeeb if (ref->is_go)
2076df279a26SBjoern A. Zeeb rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, false);
20776d67aabdSBjoern A. Zeeb else if (aux->is_go)
2078df279a26SBjoern A. Zeeb rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, false);
20796d67aabdSBjoern A. Zeeb
20806d67aabdSBjoern A. Zeeb rtw89_mcc_handle_beacon_noa(rtwdev, false);
20816d67aabdSBjoern A. Zeeb }
20826d67aabdSBjoern A. Zeeb
rtw89_mcc_start(struct rtw89_dev * rtwdev)20836d67aabdSBjoern A. Zeeb static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
20846d67aabdSBjoern A. Zeeb {
20856d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
20866d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
20876d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *aux = &mcc->role_aux;
20886d67aabdSBjoern A. Zeeb int ret;
20896d67aabdSBjoern A. Zeeb
20906d67aabdSBjoern A. Zeeb if (rtwdev->scanning)
20916d67aabdSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
20926d67aabdSBjoern A. Zeeb
20936d67aabdSBjoern A. Zeeb rtw89_leave_lps(rtwdev);
20946d67aabdSBjoern A. Zeeb
20956d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n");
20966d67aabdSBjoern A. Zeeb
20976d67aabdSBjoern A. Zeeb ret = rtw89_mcc_fill_all_roles(rtwdev);
20986d67aabdSBjoern A. Zeeb if (ret)
20996d67aabdSBjoern A. Zeeb return ret;
21006d67aabdSBjoern A. Zeeb
21016d67aabdSBjoern A. Zeeb if (ref->is_go || aux->is_go)
21026d67aabdSBjoern A. Zeeb mcc->mode = RTW89_MCC_MODE_GO_STA;
21036d67aabdSBjoern A. Zeeb else
21046d67aabdSBjoern A. Zeeb mcc->mode = RTW89_MCC_MODE_GC_STA;
21056d67aabdSBjoern A. Zeeb
21066d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode);
21076d67aabdSBjoern A. Zeeb
21086d67aabdSBjoern A. Zeeb mcc->group = RTW89_MCC_DFLT_GROUP;
21096d67aabdSBjoern A. Zeeb
21106d67aabdSBjoern A. Zeeb ret = rtw89_mcc_fill_config(rtwdev);
21116d67aabdSBjoern A. Zeeb if (ret)
21126d67aabdSBjoern A. Zeeb return ret;
21136d67aabdSBjoern A. Zeeb
21146d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev))
21156d67aabdSBjoern A. Zeeb ret = __mrc_fw_start(rtwdev, false);
21166d67aabdSBjoern A. Zeeb else
21176d67aabdSBjoern A. Zeeb ret = __mcc_fw_start(rtwdev, false);
21186d67aabdSBjoern A. Zeeb
21196d67aabdSBjoern A. Zeeb if (ret)
21206d67aabdSBjoern A. Zeeb return ret;
21216d67aabdSBjoern A. Zeeb
21226d67aabdSBjoern A. Zeeb rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);
21236d67aabdSBjoern A. Zeeb
21246d67aabdSBjoern A. Zeeb rtw89_mcc_start_beacon_noa(rtwdev);
21256d67aabdSBjoern A. Zeeb return 0;
21266d67aabdSBjoern A. Zeeb }
21276d67aabdSBjoern A. Zeeb
2128df279a26SBjoern A. Zeeb struct rtw89_mcc_stop_sel {
2129df279a26SBjoern A. Zeeb u8 mac_id;
2130df279a26SBjoern A. Zeeb u8 slot_idx;
2131df279a26SBjoern A. Zeeb };
2132df279a26SBjoern A. Zeeb
rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel * sel,const struct rtw89_mcc_role * mcc_role)2133df279a26SBjoern A. Zeeb static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel,
2134df279a26SBjoern A. Zeeb const struct rtw89_mcc_role *mcc_role)
2135df279a26SBjoern A. Zeeb {
2136df279a26SBjoern A. Zeeb sel->mac_id = mcc_role->rtwvif_link->mac_id;
2137df279a26SBjoern A. Zeeb sel->slot_idx = mcc_role->slot_idx;
2138df279a26SBjoern A. Zeeb }
2139df279a26SBjoern A. Zeeb
rtw89_mcc_stop_sel_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)2140df279a26SBjoern A. Zeeb static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,
2141df279a26SBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
2142df279a26SBjoern A. Zeeb unsigned int ordered_idx,
2143df279a26SBjoern A. Zeeb void *data)
2144df279a26SBjoern A. Zeeb {
2145df279a26SBjoern A. Zeeb struct rtw89_mcc_stop_sel *sel = data;
2146df279a26SBjoern A. Zeeb
2147df279a26SBjoern A. Zeeb if (!mcc_role->rtwvif_link->chanctx_assigned)
2148df279a26SBjoern A. Zeeb return 0;
2149df279a26SBjoern A. Zeeb
2150df279a26SBjoern A. Zeeb rtw89_mcc_stop_sel_fill(sel, mcc_role);
2151df279a26SBjoern A. Zeeb return 1; /* break iteration */
2152df279a26SBjoern A. Zeeb }
2153df279a26SBjoern A. Zeeb
rtw89_mcc_stop(struct rtw89_dev * rtwdev)21546d67aabdSBjoern A. Zeeb static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
21556d67aabdSBjoern A. Zeeb {
21566d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
21576d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *ref = &mcc->role_ref;
2158df279a26SBjoern A. Zeeb struct rtw89_mcc_stop_sel sel;
21596d67aabdSBjoern A. Zeeb int ret;
21606d67aabdSBjoern A. Zeeb
2161df279a26SBjoern A. Zeeb /* by default, stop at ref */
2162df279a26SBjoern A. Zeeb rtw89_mcc_stop_sel_fill(&sel, ref);
2163df279a26SBjoern A. Zeeb rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel);
2164df279a26SBjoern A. Zeeb
2165df279a26SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop at <macid %d>\n", sel.mac_id);
21666d67aabdSBjoern A. Zeeb
21676d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev)) {
2168df279a26SBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_del(rtwdev, mcc->group, sel.slot_idx);
21696d67aabdSBjoern A. Zeeb if (ret)
21706d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
21716d67aabdSBjoern A. Zeeb "MRC h2c failed to trigger del: %d\n", ret);
21726d67aabdSBjoern A. Zeeb } else {
21736d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group,
2174df279a26SBjoern A. Zeeb sel.mac_id, true);
21756d67aabdSBjoern A. Zeeb if (ret)
21766d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
21776d67aabdSBjoern A. Zeeb "MCC h2c failed to trigger stop: %d\n", ret);
21786d67aabdSBjoern A. Zeeb
21796d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true);
21806d67aabdSBjoern A. Zeeb if (ret)
21816d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
21826d67aabdSBjoern A. Zeeb "MCC h2c failed to delete group: %d\n", ret);
21836d67aabdSBjoern A. Zeeb }
21846d67aabdSBjoern A. Zeeb
21856d67aabdSBjoern A. Zeeb rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
21866d67aabdSBjoern A. Zeeb
21876d67aabdSBjoern A. Zeeb rtw89_mcc_stop_beacon_noa(rtwdev);
21886d67aabdSBjoern A. Zeeb }
21896d67aabdSBjoern A. Zeeb
rtw89_mcc_update(struct rtw89_dev * rtwdev)21906d67aabdSBjoern A. Zeeb static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
21916d67aabdSBjoern A. Zeeb {
21926d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
21936d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
21946d67aabdSBjoern A. Zeeb struct rtw89_mcc_config old_cfg = *config;
21956d67aabdSBjoern A. Zeeb bool sync_changed;
21966d67aabdSBjoern A. Zeeb int ret;
21976d67aabdSBjoern A. Zeeb
21986d67aabdSBjoern A. Zeeb if (rtwdev->scanning)
21996d67aabdSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
22006d67aabdSBjoern A. Zeeb
22016d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC update\n");
22026d67aabdSBjoern A. Zeeb
22036d67aabdSBjoern A. Zeeb ret = rtw89_mcc_fill_config(rtwdev);
22046d67aabdSBjoern A. Zeeb if (ret)
22056d67aabdSBjoern A. Zeeb return ret;
22066d67aabdSBjoern A. Zeeb
22076d67aabdSBjoern A. Zeeb if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
22086d67aabdSBjoern A. Zeeb config->pattern.plan != RTW89_MCC_PLAN_NO_BT) {
22096d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev))
22106d67aabdSBjoern A. Zeeb ret = __mrc_fw_start(rtwdev, true);
22116d67aabdSBjoern A. Zeeb else
22126d67aabdSBjoern A. Zeeb ret = __mcc_fw_start(rtwdev, true);
22136d67aabdSBjoern A. Zeeb
22146d67aabdSBjoern A. Zeeb if (ret)
22156d67aabdSBjoern A. Zeeb return ret;
22166d67aabdSBjoern A. Zeeb } else {
22176d67aabdSBjoern A. Zeeb if (memcmp(&old_cfg.sync, &config->sync, sizeof(old_cfg.sync)) == 0)
22186d67aabdSBjoern A. Zeeb sync_changed = false;
22196d67aabdSBjoern A. Zeeb else
22206d67aabdSBjoern A. Zeeb sync_changed = true;
22216d67aabdSBjoern A. Zeeb
22226d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev))
22236d67aabdSBjoern A. Zeeb ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed);
22246d67aabdSBjoern A. Zeeb else
22256d67aabdSBjoern A. Zeeb ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
22266d67aabdSBjoern A. Zeeb
22276d67aabdSBjoern A. Zeeb if (ret)
22286d67aabdSBjoern A. Zeeb return ret;
22296d67aabdSBjoern A. Zeeb }
22306d67aabdSBjoern A. Zeeb
22316d67aabdSBjoern A. Zeeb rtw89_mcc_handle_beacon_noa(rtwdev, true);
22326d67aabdSBjoern A. Zeeb return 0;
22336d67aabdSBjoern A. Zeeb }
22346d67aabdSBjoern A. Zeeb
rtw89_mcc_track(struct rtw89_dev * rtwdev)22356d67aabdSBjoern A. Zeeb static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
22366d67aabdSBjoern A. Zeeb {
22376d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
22386d67aabdSBjoern A. Zeeb struct rtw89_mcc_config *config = &mcc->config;
22396d67aabdSBjoern A. Zeeb struct rtw89_mcc_pattern *pattern = &config->pattern;
22406d67aabdSBjoern A. Zeeb s16 tolerance;
22416d67aabdSBjoern A. Zeeb u16 bcn_ofst;
22426d67aabdSBjoern A. Zeeb u16 diff;
22436d67aabdSBjoern A. Zeeb
22446d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GC_STA)
22456d67aabdSBjoern A. Zeeb return;
22466d67aabdSBjoern A. Zeeb
22476d67aabdSBjoern A. Zeeb bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
22486d67aabdSBjoern A. Zeeb if (bcn_ofst > config->beacon_offset) {
22496d67aabdSBjoern A. Zeeb diff = bcn_ofst - config->beacon_offset;
22506d67aabdSBjoern A. Zeeb if (pattern->tob_aux < 0)
22516d67aabdSBjoern A. Zeeb tolerance = -pattern->tob_aux;
22526d67aabdSBjoern A. Zeeb else
22536d67aabdSBjoern A. Zeeb tolerance = pattern->toa_aux;
22546d67aabdSBjoern A. Zeeb } else {
22556d67aabdSBjoern A. Zeeb diff = config->beacon_offset - bcn_ofst;
22566d67aabdSBjoern A. Zeeb if (pattern->toa_aux < 0)
22576d67aabdSBjoern A. Zeeb tolerance = -pattern->toa_aux;
22586d67aabdSBjoern A. Zeeb else
22596d67aabdSBjoern A. Zeeb tolerance = pattern->tob_aux;
22606d67aabdSBjoern A. Zeeb }
22616d67aabdSBjoern A. Zeeb
22626d67aabdSBjoern A. Zeeb if (diff <= tolerance)
22636d67aabdSBjoern A. Zeeb return;
22646d67aabdSBjoern A. Zeeb
22656d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE);
22666d67aabdSBjoern A. Zeeb }
22676d67aabdSBjoern A. Zeeb
__mcc_fw_upd_macid_bitmap(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * upd)22686d67aabdSBjoern A. Zeeb static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
22696d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *upd)
22706d67aabdSBjoern A. Zeeb {
22716d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
22726d67aabdSBjoern A. Zeeb int ret;
22736d67aabdSBjoern A. Zeeb
22746d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
2275df279a26SBjoern A. Zeeb upd->rtwvif_link->mac_id,
22766d67aabdSBjoern A. Zeeb upd->macid_bitmap);
22776d67aabdSBjoern A. Zeeb if (ret) {
22786d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
22796d67aabdSBjoern A. Zeeb "MCC h2c failed to update macid bitmap: %d\n", ret);
22806d67aabdSBjoern A. Zeeb return ret;
22816d67aabdSBjoern A. Zeeb }
22826d67aabdSBjoern A. Zeeb
22836d67aabdSBjoern A. Zeeb return 0;
22846d67aabdSBjoern A. Zeeb }
22856d67aabdSBjoern A. Zeeb
__mrc_fw_upd_macid_bitmap(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * cur,struct rtw89_mcc_role * upd)22866d67aabdSBjoern A. Zeeb static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
22876d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *cur,
22886d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *upd)
22896d67aabdSBjoern A. Zeeb {
22906d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
22916d67aabdSBjoern A. Zeeb struct rtw89_fw_mrc_upd_bitmap_arg arg = {};
22926d67aabdSBjoern A. Zeeb u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(cur);
22936d67aabdSBjoern A. Zeeb u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(upd);
22946d67aabdSBjoern A. Zeeb u32 add = new & ~old;
22956d67aabdSBjoern A. Zeeb u32 del = old & ~new;
22966d67aabdSBjoern A. Zeeb int ret;
22976d67aabdSBjoern A. Zeeb int i;
22986d67aabdSBjoern A. Zeeb
22996d67aabdSBjoern A. Zeeb arg.sch_idx = mcc->group;
2300df279a26SBjoern A. Zeeb arg.macid = upd->rtwvif_link->mac_id;
23016d67aabdSBjoern A. Zeeb
23026d67aabdSBjoern A. Zeeb for (i = 0; i < 32; i++) {
23036d67aabdSBjoern A. Zeeb if (add & BIT(i)) {
23046d67aabdSBjoern A. Zeeb arg.client_macid = i;
23056d67aabdSBjoern A. Zeeb arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD;
23066d67aabdSBjoern A. Zeeb
23076d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
23086d67aabdSBjoern A. Zeeb if (ret)
23096d67aabdSBjoern A. Zeeb goto err;
23106d67aabdSBjoern A. Zeeb }
23116d67aabdSBjoern A. Zeeb }
23126d67aabdSBjoern A. Zeeb
23136d67aabdSBjoern A. Zeeb for (i = 0; i < 32; i++) {
23146d67aabdSBjoern A. Zeeb if (del & BIT(i)) {
23156d67aabdSBjoern A. Zeeb arg.client_macid = i;
23166d67aabdSBjoern A. Zeeb arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL;
23176d67aabdSBjoern A. Zeeb
23186d67aabdSBjoern A. Zeeb ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
23196d67aabdSBjoern A. Zeeb if (ret)
23206d67aabdSBjoern A. Zeeb goto err;
23216d67aabdSBjoern A. Zeeb }
23226d67aabdSBjoern A. Zeeb }
23236d67aabdSBjoern A. Zeeb
23246d67aabdSBjoern A. Zeeb return 0;
23256d67aabdSBjoern A. Zeeb
23266d67aabdSBjoern A. Zeeb err:
23276d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
23286d67aabdSBjoern A. Zeeb "MRC h2c failed to update bitmap: %d\n", ret);
23296d67aabdSBjoern A. Zeeb return ret;
23306d67aabdSBjoern A. Zeeb }
23316d67aabdSBjoern A. Zeeb
rtw89_mcc_upd_map_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)23326d67aabdSBjoern A. Zeeb static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
23336d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
23346d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
23356d67aabdSBjoern A. Zeeb void *data)
23366d67aabdSBjoern A. Zeeb {
23376d67aabdSBjoern A. Zeeb struct rtw89_mcc_role upd = {
2338df279a26SBjoern A. Zeeb .rtwvif_link = mcc_role->rtwvif_link,
23396d67aabdSBjoern A. Zeeb };
23406d67aabdSBjoern A. Zeeb int ret;
23416d67aabdSBjoern A. Zeeb
23426d67aabdSBjoern A. Zeeb if (!mcc_role->is_go)
23436d67aabdSBjoern A. Zeeb return 0;
23446d67aabdSBjoern A. Zeeb
23456d67aabdSBjoern A. Zeeb rtw89_mcc_fill_role_macid_bitmap(rtwdev, &upd);
23466d67aabdSBjoern A. Zeeb if (memcmp(mcc_role->macid_bitmap, upd.macid_bitmap,
23476d67aabdSBjoern A. Zeeb sizeof(mcc_role->macid_bitmap)) == 0)
23486d67aabdSBjoern A. Zeeb return 0;
23496d67aabdSBjoern A. Zeeb
23506d67aabdSBjoern A. Zeeb if (rtw89_concurrent_via_mrc(rtwdev))
23516d67aabdSBjoern A. Zeeb ret = __mrc_fw_upd_macid_bitmap(rtwdev, mcc_role, &upd);
23526d67aabdSBjoern A. Zeeb else
23536d67aabdSBjoern A. Zeeb ret = __mcc_fw_upd_macid_bitmap(rtwdev, &upd);
23546d67aabdSBjoern A. Zeeb
23556d67aabdSBjoern A. Zeeb if (ret)
23566d67aabdSBjoern A. Zeeb return ret;
23576d67aabdSBjoern A. Zeeb
23586d67aabdSBjoern A. Zeeb memcpy(mcc_role->macid_bitmap, upd.macid_bitmap,
23596d67aabdSBjoern A. Zeeb sizeof(mcc_role->macid_bitmap));
23606d67aabdSBjoern A. Zeeb return 0;
23616d67aabdSBjoern A. Zeeb }
23626d67aabdSBjoern A. Zeeb
rtw89_mcc_update_macid_bitmap(struct rtw89_dev * rtwdev)23636d67aabdSBjoern A. Zeeb static void rtw89_mcc_update_macid_bitmap(struct rtw89_dev *rtwdev)
23646d67aabdSBjoern A. Zeeb {
23656d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
23666d67aabdSBjoern A. Zeeb
23676d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GO_STA)
23686d67aabdSBjoern A. Zeeb return;
23696d67aabdSBjoern A. Zeeb
23706d67aabdSBjoern A. Zeeb rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_map_iterator, NULL);
23716d67aabdSBjoern A. Zeeb }
23726d67aabdSBjoern A. Zeeb
rtw89_mcc_upd_lmt_iterator(struct rtw89_dev * rtwdev,struct rtw89_mcc_role * mcc_role,unsigned int ordered_idx,void * data)23736d67aabdSBjoern A. Zeeb static int rtw89_mcc_upd_lmt_iterator(struct rtw89_dev *rtwdev,
23746d67aabdSBjoern A. Zeeb struct rtw89_mcc_role *mcc_role,
23756d67aabdSBjoern A. Zeeb unsigned int ordered_idx,
23766d67aabdSBjoern A. Zeeb void *data)
23776d67aabdSBjoern A. Zeeb {
23786d67aabdSBjoern A. Zeeb memset(&mcc_role->limit, 0, sizeof(mcc_role->limit));
23796d67aabdSBjoern A. Zeeb rtw89_mcc_fill_role_limit(rtwdev, mcc_role);
23806d67aabdSBjoern A. Zeeb return 0;
23816d67aabdSBjoern A. Zeeb }
23826d67aabdSBjoern A. Zeeb
rtw89_mcc_update_limit(struct rtw89_dev * rtwdev)23836d67aabdSBjoern A. Zeeb static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev)
23846d67aabdSBjoern A. Zeeb {
23856d67aabdSBjoern A. Zeeb struct rtw89_mcc_info *mcc = &rtwdev->mcc;
23866d67aabdSBjoern A. Zeeb
23876d67aabdSBjoern A. Zeeb if (mcc->mode != RTW89_MCC_MODE_GC_STA)
23886d67aabdSBjoern A. Zeeb return;
23896d67aabdSBjoern A. Zeeb
23906d67aabdSBjoern A. Zeeb rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL);
23916d67aabdSBjoern A. Zeeb }
23926d67aabdSBjoern A. Zeeb
rtw89_chanctx_work(struct work_struct * work)23936d67aabdSBjoern A. Zeeb void rtw89_chanctx_work(struct work_struct *work)
23946d67aabdSBjoern A. Zeeb {
23956d67aabdSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
23966d67aabdSBjoern A. Zeeb chanctx_work.work);
23976d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
23986d67aabdSBjoern A. Zeeb bool update_mcc_pattern = false;
23996d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
24006d67aabdSBjoern A. Zeeb u32 changed = 0;
24016d67aabdSBjoern A. Zeeb int ret;
24026d67aabdSBjoern A. Zeeb int i;
24036d67aabdSBjoern A. Zeeb
24046d67aabdSBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
24056d67aabdSBjoern A. Zeeb
24066d67aabdSBjoern A. Zeeb if (hal->entity_pause) {
24076d67aabdSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
24086d67aabdSBjoern A. Zeeb return;
24096d67aabdSBjoern A. Zeeb }
24106d67aabdSBjoern A. Zeeb
24116d67aabdSBjoern A. Zeeb for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) {
24126d67aabdSBjoern A. Zeeb if (test_and_clear_bit(i, hal->changes))
24136d67aabdSBjoern A. Zeeb changed |= BIT(i);
24146d67aabdSBjoern A. Zeeb }
24156d67aabdSBjoern A. Zeeb
24166d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
24176d67aabdSBjoern A. Zeeb switch (mode) {
24186d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC_PREPARE:
24196d67aabdSBjoern A. Zeeb rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC);
24206d67aabdSBjoern A. Zeeb rtw89_set_channel(rtwdev);
24216d67aabdSBjoern A. Zeeb
24226d67aabdSBjoern A. Zeeb ret = rtw89_mcc_start(rtwdev);
24236d67aabdSBjoern A. Zeeb if (ret)
24246d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
24256d67aabdSBjoern A. Zeeb break;
24266d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
24276d67aabdSBjoern A. Zeeb if (changed & BIT(RTW89_CHANCTX_BCN_OFFSET_CHANGE) ||
24286d67aabdSBjoern A. Zeeb changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE) ||
24296d67aabdSBjoern A. Zeeb changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE) ||
24306d67aabdSBjoern A. Zeeb changed & BIT(RTW89_CHANCTX_TSF32_TOGGLE_CHANGE))
24316d67aabdSBjoern A. Zeeb update_mcc_pattern = true;
24326d67aabdSBjoern A. Zeeb if (changed & BIT(RTW89_CHANCTX_REMOTE_STA_CHANGE))
24336d67aabdSBjoern A. Zeeb rtw89_mcc_update_macid_bitmap(rtwdev);
24346d67aabdSBjoern A. Zeeb if (changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE))
24356d67aabdSBjoern A. Zeeb rtw89_mcc_update_limit(rtwdev);
24366d67aabdSBjoern A. Zeeb if (changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE))
24376d67aabdSBjoern A. Zeeb rtw89_mcc_fill_bt_role(rtwdev);
24386d67aabdSBjoern A. Zeeb if (update_mcc_pattern) {
24396d67aabdSBjoern A. Zeeb ret = rtw89_mcc_update(rtwdev);
24406d67aabdSBjoern A. Zeeb if (ret)
24416d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to update MCC: %d\n",
24426d67aabdSBjoern A. Zeeb ret);
24436d67aabdSBjoern A. Zeeb }
24446d67aabdSBjoern A. Zeeb break;
24456d67aabdSBjoern A. Zeeb default:
24466d67aabdSBjoern A. Zeeb break;
24476d67aabdSBjoern A. Zeeb }
24486d67aabdSBjoern A. Zeeb
24496d67aabdSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
24506d67aabdSBjoern A. Zeeb }
24516d67aabdSBjoern A. Zeeb
rtw89_queue_chanctx_change(struct rtw89_dev * rtwdev,enum rtw89_chanctx_changes change)24526d67aabdSBjoern A. Zeeb void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
24536d67aabdSBjoern A. Zeeb enum rtw89_chanctx_changes change)
24546d67aabdSBjoern A. Zeeb {
24556d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
24566d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
24576d67aabdSBjoern A. Zeeb u32 delay;
24586d67aabdSBjoern A. Zeeb
24596d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
24606d67aabdSBjoern A. Zeeb switch (mode) {
24616d67aabdSBjoern A. Zeeb default:
24626d67aabdSBjoern A. Zeeb return;
24636d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC_PREPARE:
24646d67aabdSBjoern A. Zeeb delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
24656d67aabdSBjoern A. Zeeb break;
24666d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
24676d67aabdSBjoern A. Zeeb delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC);
24686d67aabdSBjoern A. Zeeb break;
24696d67aabdSBjoern A. Zeeb }
24706d67aabdSBjoern A. Zeeb
24716d67aabdSBjoern A. Zeeb if (change != RTW89_CHANCTX_CHANGE_DFLT) {
24726d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "set chanctx change %d\n",
24736d67aabdSBjoern A. Zeeb change);
24746d67aabdSBjoern A. Zeeb set_bit(change, hal->changes);
24756d67aabdSBjoern A. Zeeb }
24766d67aabdSBjoern A. Zeeb
24776d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
24786d67aabdSBjoern A. Zeeb "queue chanctx work for mode %d with delay %d us\n",
24796d67aabdSBjoern A. Zeeb mode, delay);
24806d67aabdSBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work,
24816d67aabdSBjoern A. Zeeb usecs_to_jiffies(delay));
24826d67aabdSBjoern A. Zeeb }
24836d67aabdSBjoern A. Zeeb
rtw89_queue_chanctx_work(struct rtw89_dev * rtwdev)24846d67aabdSBjoern A. Zeeb void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
24856d67aabdSBjoern A. Zeeb {
24866d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT);
24876d67aabdSBjoern A. Zeeb }
24886d67aabdSBjoern A. Zeeb
rtw89_chanctx_track(struct rtw89_dev * rtwdev)24896d67aabdSBjoern A. Zeeb void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
24906d67aabdSBjoern A. Zeeb {
24916d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
24926d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
24936d67aabdSBjoern A. Zeeb
24946d67aabdSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
24956d67aabdSBjoern A. Zeeb
24966d67aabdSBjoern A. Zeeb if (hal->entity_pause)
24976d67aabdSBjoern A. Zeeb return;
24986d67aabdSBjoern A. Zeeb
24996d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
25006d67aabdSBjoern A. Zeeb switch (mode) {
25016d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
25026d67aabdSBjoern A. Zeeb rtw89_mcc_track(rtwdev);
25036d67aabdSBjoern A. Zeeb break;
25046d67aabdSBjoern A. Zeeb default:
25056d67aabdSBjoern A. Zeeb break;
25066d67aabdSBjoern A. Zeeb }
25076d67aabdSBjoern A. Zeeb }
25086d67aabdSBjoern A. Zeeb
rtw89_chanctx_pause(struct rtw89_dev * rtwdev,enum rtw89_chanctx_pause_reasons rsn)25096d67aabdSBjoern A. Zeeb void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
25106d67aabdSBjoern A. Zeeb enum rtw89_chanctx_pause_reasons rsn)
25116d67aabdSBjoern A. Zeeb {
25126d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
25136d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
25146d67aabdSBjoern A. Zeeb
25156d67aabdSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
25166d67aabdSBjoern A. Zeeb
25176d67aabdSBjoern A. Zeeb if (hal->entity_pause)
25186d67aabdSBjoern A. Zeeb return;
25196d67aabdSBjoern A. Zeeb
25206d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", rsn);
25216d67aabdSBjoern A. Zeeb
25226d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
25236d67aabdSBjoern A. Zeeb switch (mode) {
25246d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
25256d67aabdSBjoern A. Zeeb rtw89_mcc_stop(rtwdev);
25266d67aabdSBjoern A. Zeeb break;
25276d67aabdSBjoern A. Zeeb default:
25286d67aabdSBjoern A. Zeeb break;
25296d67aabdSBjoern A. Zeeb }
25306d67aabdSBjoern A. Zeeb
25316d67aabdSBjoern A. Zeeb hal->entity_pause = true;
25326d67aabdSBjoern A. Zeeb }
25336d67aabdSBjoern A. Zeeb
rtw89_chanctx_proceed_cb(struct rtw89_dev * rtwdev,const struct rtw89_chanctx_cb_parm * parm)2534df279a26SBjoern A. Zeeb static void rtw89_chanctx_proceed_cb(struct rtw89_dev *rtwdev,
2535df279a26SBjoern A. Zeeb const struct rtw89_chanctx_cb_parm *parm)
2536df279a26SBjoern A. Zeeb {
2537df279a26SBjoern A. Zeeb int ret;
2538df279a26SBjoern A. Zeeb
2539df279a26SBjoern A. Zeeb if (!parm || !parm->cb)
2540df279a26SBjoern A. Zeeb return;
2541df279a26SBjoern A. Zeeb
2542df279a26SBjoern A. Zeeb ret = parm->cb(rtwdev, parm->data);
2543df279a26SBjoern A. Zeeb if (ret)
2544df279a26SBjoern A. Zeeb rtw89_warn(rtwdev, "%s (%s): cb failed: %d\n", __func__,
2545df279a26SBjoern A. Zeeb parm->caller ?: "unknown", ret);
2546df279a26SBjoern A. Zeeb }
2547df279a26SBjoern A. Zeeb
2548df279a26SBjoern A. Zeeb /* pass @cb_parm if there is a @cb_parm->cb which needs to invoke right after
2549df279a26SBjoern A. Zeeb * call rtw89_set_channel() and right before proceed entity according to mode.
2550df279a26SBjoern A. Zeeb */
rtw89_chanctx_proceed(struct rtw89_dev * rtwdev,const struct rtw89_chanctx_cb_parm * cb_parm)2551df279a26SBjoern A. Zeeb void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev,
2552df279a26SBjoern A. Zeeb const struct rtw89_chanctx_cb_parm *cb_parm)
25536d67aabdSBjoern A. Zeeb {
25546d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
25556d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
25566d67aabdSBjoern A. Zeeb int ret;
25576d67aabdSBjoern A. Zeeb
25586d67aabdSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
25596d67aabdSBjoern A. Zeeb
2560df279a26SBjoern A. Zeeb if (unlikely(!hal->entity_pause)) {
2561df279a26SBjoern A. Zeeb rtw89_chanctx_proceed_cb(rtwdev, cb_parm);
25626d67aabdSBjoern A. Zeeb return;
2563df279a26SBjoern A. Zeeb }
25646d67aabdSBjoern A. Zeeb
25656d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx proceed\n");
25666d67aabdSBjoern A. Zeeb
25676d67aabdSBjoern A. Zeeb hal->entity_pause = false;
25686d67aabdSBjoern A. Zeeb rtw89_set_channel(rtwdev);
25696d67aabdSBjoern A. Zeeb
2570df279a26SBjoern A. Zeeb rtw89_chanctx_proceed_cb(rtwdev, cb_parm);
2571df279a26SBjoern A. Zeeb
25726d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
25736d67aabdSBjoern A. Zeeb switch (mode) {
25746d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
25756d67aabdSBjoern A. Zeeb ret = rtw89_mcc_start(rtwdev);
25766d67aabdSBjoern A. Zeeb if (ret)
25776d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
25786d67aabdSBjoern A. Zeeb break;
25796d67aabdSBjoern A. Zeeb default:
25806d67aabdSBjoern A. Zeeb break;
25816d67aabdSBjoern A. Zeeb }
25826d67aabdSBjoern A. Zeeb
25836d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_work(rtwdev);
25846d67aabdSBjoern A. Zeeb }
25856d67aabdSBjoern A. Zeeb
__rtw89_swap_chanctx(struct rtw89_vif * rtwvif,enum rtw89_chanctx_idx idx1,enum rtw89_chanctx_idx idx2)2586df279a26SBjoern A. Zeeb static void __rtw89_swap_chanctx(struct rtw89_vif *rtwvif,
2587df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx1,
2588df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx2)
2589df279a26SBjoern A. Zeeb {
2590df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link;
2591df279a26SBjoern A. Zeeb unsigned int link_id;
2592df279a26SBjoern A. Zeeb
2593df279a26SBjoern A. Zeeb rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
2594df279a26SBjoern A. Zeeb if (!rtwvif_link->chanctx_assigned)
2595df279a26SBjoern A. Zeeb continue;
2596df279a26SBjoern A. Zeeb
2597df279a26SBjoern A. Zeeb if (rtwvif_link->chanctx_idx == idx1)
2598df279a26SBjoern A. Zeeb rtwvif_link->chanctx_idx = idx2;
2599df279a26SBjoern A. Zeeb else if (rtwvif_link->chanctx_idx == idx2)
2600df279a26SBjoern A. Zeeb rtwvif_link->chanctx_idx = idx1;
2601df279a26SBjoern A. Zeeb }
2602df279a26SBjoern A. Zeeb }
2603df279a26SBjoern A. Zeeb
rtw89_swap_chanctx(struct rtw89_dev * rtwdev,enum rtw89_chanctx_idx idx1,enum rtw89_chanctx_idx idx2)2604df279a26SBjoern A. Zeeb static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
2605df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx1,
2606df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx idx2)
26076d67aabdSBjoern A. Zeeb {
26086d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
26096d67aabdSBjoern A. Zeeb struct rtw89_vif *rtwvif;
26106d67aabdSBjoern A. Zeeb u8 cur;
26116d67aabdSBjoern A. Zeeb
26126d67aabdSBjoern A. Zeeb if (idx1 == idx2)
26136d67aabdSBjoern A. Zeeb return;
26146d67aabdSBjoern A. Zeeb
2615*3a427b83SBjoern A. Zeeb #if defined(__FreeBSD__)
2616*3a427b83SBjoern A. Zeeb /*
2617*3a427b83SBjoern A. Zeeb * __rtw89_config_entity_chandef() might set RTW89_CHANCTX_0 but no
2618*3a427b83SBjoern A. Zeeb * cfg assigned.
2619*3a427b83SBjoern A. Zeeb * A mac80211 (*config)() with IEEE80211_CONF_CHANGE_CHANNEL could do
2620*3a427b83SBjoern A. Zeeb * that if rtw89_config_default_chandef() from rtw89_entity_init() does
2621*3a427b83SBjoern A. Zeeb * not already.
2622*3a427b83SBjoern A. Zeeb * A mac80211: (*assign_vif_chanctx)() following will find idx 0 filled
2623*3a427b83SBjoern A. Zeeb * and rtw89_chanctx_ops_add() will call here. Trying to swap results
2624*3a427b83SBjoern A. Zeeb * in a NULL pointer deref as hal->chanctx[idx1].cfg is NULL.
2625*3a427b83SBjoern A. Zeeb * Catch this for now until fully understood or a proper solution is
2626*3a427b83SBjoern A. Zeeb * found.
2627*3a427b83SBjoern A. Zeeb */
2628*3a427b83SBjoern A. Zeeb if (hal->chanctx[idx1].cfg == NULL || hal->chanctx[idx2].cfg == NULL) {
2629*3a427b83SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_CHAN,
2630*3a427b83SBjoern A. Zeeb "%s: !swapping idx1 %d cfg %p, idx2 %d cfg %p\n", __func__,
2631*3a427b83SBjoern A. Zeeb idx1, hal->chanctx[idx1].cfg, idx2, hal->chanctx[idx2].cfg);
2632*3a427b83SBjoern A. Zeeb return;
2633*3a427b83SBjoern A. Zeeb }
2634*3a427b83SBjoern A. Zeeb #endif
2635*3a427b83SBjoern A. Zeeb
2636df279a26SBjoern A. Zeeb hal->chanctx[idx1].cfg->idx = idx2;
2637df279a26SBjoern A. Zeeb hal->chanctx[idx2].cfg->idx = idx1;
26386d67aabdSBjoern A. Zeeb
2639df279a26SBjoern A. Zeeb swap(hal->chanctx[idx1], hal->chanctx[idx2]);
26406d67aabdSBjoern A. Zeeb
2641df279a26SBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, rtwvif)
2642df279a26SBjoern A. Zeeb __rtw89_swap_chanctx(rtwvif, idx1, idx2);
26436d67aabdSBjoern A. Zeeb
2644df279a26SBjoern A. Zeeb cur = atomic_read(&hal->roc_chanctx_idx);
26456d67aabdSBjoern A. Zeeb if (cur == idx1)
2646df279a26SBjoern A. Zeeb atomic_set(&hal->roc_chanctx_idx, idx2);
26476d67aabdSBjoern A. Zeeb else if (cur == idx2)
2648df279a26SBjoern A. Zeeb atomic_set(&hal->roc_chanctx_idx, idx1);
26496d67aabdSBjoern A. Zeeb }
26506d67aabdSBjoern A. Zeeb
rtw89_chanctx_ops_add(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx)26518e93258fSBjoern A. Zeeb int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
26528e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx)
26538e93258fSBjoern A. Zeeb {
26548e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
26558e93258fSBjoern A. Zeeb struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
26568e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
26578e93258fSBjoern A. Zeeb u8 idx;
26588e93258fSBjoern A. Zeeb
2659df279a26SBjoern A. Zeeb idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_CHANCTX);
26608e93258fSBjoern A. Zeeb if (idx >= chip->support_chanctx_num)
26618e93258fSBjoern A. Zeeb return -ENOENT;
26628e93258fSBjoern A. Zeeb
26638e93258fSBjoern A. Zeeb rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
26648e93258fSBjoern A. Zeeb cfg->idx = idx;
26656d67aabdSBjoern A. Zeeb cfg->ref_count = 0;
2666df279a26SBjoern A. Zeeb hal->chanctx[idx].cfg = cfg;
26678e93258fSBjoern A. Zeeb return 0;
26688e93258fSBjoern A. Zeeb }
26698e93258fSBjoern A. Zeeb
rtw89_chanctx_ops_remove(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx)26708e93258fSBjoern A. Zeeb void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
26718e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx)
26728e93258fSBjoern A. Zeeb {
26738e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
26748e93258fSBjoern A. Zeeb struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
26758e93258fSBjoern A. Zeeb
26766d67aabdSBjoern A. Zeeb clear_bit(cfg->idx, hal->entity_map);
26778e93258fSBjoern A. Zeeb }
26788e93258fSBjoern A. Zeeb
rtw89_chanctx_ops_change(struct rtw89_dev * rtwdev,struct ieee80211_chanctx_conf * ctx,u32 changed)26798e93258fSBjoern A. Zeeb void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
26808e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx,
26818e93258fSBjoern A. Zeeb u32 changed)
26828e93258fSBjoern A. Zeeb {
26838e93258fSBjoern A. Zeeb struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
26848e93258fSBjoern A. Zeeb u8 idx = cfg->idx;
26858e93258fSBjoern A. Zeeb
26868e93258fSBjoern A. Zeeb if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
26878e93258fSBjoern A. Zeeb rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
26888e93258fSBjoern A. Zeeb rtw89_set_channel(rtwdev);
26898e93258fSBjoern A. Zeeb }
26908e93258fSBjoern A. Zeeb }
26918e93258fSBjoern A. Zeeb
rtw89_chanctx_ops_assign_vif(struct rtw89_dev * rtwdev,struct rtw89_vif_link * rtwvif_link,struct ieee80211_chanctx_conf * ctx)26928e93258fSBjoern A. Zeeb int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
2693df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link,
26948e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx)
26958e93258fSBjoern A. Zeeb {
2696e2340276SBjoern A. Zeeb struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2697df279a26SBjoern A. Zeeb struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
2698df279a26SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
2699df279a26SBjoern A. Zeeb struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
27006d67aabdSBjoern A. Zeeb struct rtw89_entity_weight w = {};
2701e2340276SBjoern A. Zeeb
2702df279a26SBjoern A. Zeeb rtwvif_link->chanctx_idx = cfg->idx;
2703df279a26SBjoern A. Zeeb rtwvif_link->chanctx_assigned = true;
27046d67aabdSBjoern A. Zeeb cfg->ref_count++;
27056d67aabdSBjoern A. Zeeb
2706df279a26SBjoern A. Zeeb if (list_empty(&rtwvif->mgnt_entry))
2707df279a26SBjoern A. Zeeb list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list);
2708df279a26SBjoern A. Zeeb
2709df279a26SBjoern A. Zeeb if (cfg->idx == RTW89_CHANCTX_0)
27106d67aabdSBjoern A. Zeeb goto out;
27116d67aabdSBjoern A. Zeeb
27126d67aabdSBjoern A. Zeeb rtw89_entity_calculate_weight(rtwdev, &w);
27136d67aabdSBjoern A. Zeeb if (w.active_chanctxs != 1)
27146d67aabdSBjoern A. Zeeb goto out;
27156d67aabdSBjoern A. Zeeb
2716df279a26SBjoern A. Zeeb /* put the first active chanctx at RTW89_CHANCTX_0 */
2717df279a26SBjoern A. Zeeb rtw89_swap_chanctx(rtwdev, cfg->idx, RTW89_CHANCTX_0);
27186d67aabdSBjoern A. Zeeb
27196d67aabdSBjoern A. Zeeb out:
27206d67aabdSBjoern A. Zeeb return rtw89_set_channel(rtwdev);
27218e93258fSBjoern A. Zeeb }
27228e93258fSBjoern A. Zeeb
rtw89_chanctx_ops_unassign_vif(struct rtw89_dev * rtwdev,struct rtw89_vif_link * rtwvif_link,struct ieee80211_chanctx_conf * ctx)27238e93258fSBjoern A. Zeeb void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
2724df279a26SBjoern A. Zeeb struct rtw89_vif_link *rtwvif_link,
27258e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx)
27268e93258fSBjoern A. Zeeb {
27276d67aabdSBjoern A. Zeeb struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
2728df279a26SBjoern A. Zeeb struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
27296d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
2730df279a26SBjoern A. Zeeb enum rtw89_chanctx_idx roll;
27316d67aabdSBjoern A. Zeeb enum rtw89_entity_mode cur;
2732df279a26SBjoern A. Zeeb enum rtw89_entity_mode new;
2733df279a26SBjoern A. Zeeb int ret;
27346d67aabdSBjoern A. Zeeb
2735df279a26SBjoern A. Zeeb rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;
2736df279a26SBjoern A. Zeeb rtwvif_link->chanctx_assigned = false;
27376d67aabdSBjoern A. Zeeb cfg->ref_count--;
27386d67aabdSBjoern A. Zeeb
2739df279a26SBjoern A. Zeeb if (!rtw89_vif_is_active_role(rtwvif))
2740df279a26SBjoern A. Zeeb list_del_init(&rtwvif->mgnt_entry);
2741df279a26SBjoern A. Zeeb
27426d67aabdSBjoern A. Zeeb if (cfg->ref_count != 0)
27436d67aabdSBjoern A. Zeeb goto out;
27446d67aabdSBjoern A. Zeeb
2745df279a26SBjoern A. Zeeb if (cfg->idx != RTW89_CHANCTX_0)
27466d67aabdSBjoern A. Zeeb goto out;
27476d67aabdSBjoern A. Zeeb
2748df279a26SBjoern A. Zeeb roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_CHANCTX,
27496d67aabdSBjoern A. Zeeb cfg->idx + 1);
27506d67aabdSBjoern A. Zeeb /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
2751df279a26SBjoern A. Zeeb if (roll == NUM_OF_RTW89_CHANCTX)
27526d67aabdSBjoern A. Zeeb goto out;
27536d67aabdSBjoern A. Zeeb
2754df279a26SBjoern A. Zeeb /* RTW89_CHANCTX_0 is going to release, and another exists.
2755df279a26SBjoern A. Zeeb * Make another roll down to RTW89_CHANCTX_0 to replace.
27566d67aabdSBjoern A. Zeeb */
2757df279a26SBjoern A. Zeeb rtw89_swap_chanctx(rtwdev, cfg->idx, roll);
27586d67aabdSBjoern A. Zeeb
27596d67aabdSBjoern A. Zeeb out:
2760df279a26SBjoern A. Zeeb if (!hal->entity_pause) {
27616d67aabdSBjoern A. Zeeb cur = rtw89_get_entity_mode(rtwdev);
27626d67aabdSBjoern A. Zeeb switch (cur) {
27636d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
27646d67aabdSBjoern A. Zeeb rtw89_mcc_stop(rtwdev);
27656d67aabdSBjoern A. Zeeb break;
27666d67aabdSBjoern A. Zeeb default:
27676d67aabdSBjoern A. Zeeb break;
27686d67aabdSBjoern A. Zeeb }
2769df279a26SBjoern A. Zeeb }
27706d67aabdSBjoern A. Zeeb
2771df279a26SBjoern A. Zeeb ret = rtw89_set_channel(rtwdev);
2772df279a26SBjoern A. Zeeb if (ret)
2773df279a26SBjoern A. Zeeb return;
2774df279a26SBjoern A. Zeeb
2775df279a26SBjoern A. Zeeb if (hal->entity_pause)
2776df279a26SBjoern A. Zeeb return;
2777df279a26SBjoern A. Zeeb
2778df279a26SBjoern A. Zeeb new = rtw89_get_entity_mode(rtwdev);
2779df279a26SBjoern A. Zeeb switch (new) {
2780df279a26SBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
2781df279a26SBjoern A. Zeeb /* re-plan MCC for chanctx changes. */
2782df279a26SBjoern A. Zeeb ret = rtw89_mcc_start(rtwdev);
2783df279a26SBjoern A. Zeeb if (ret)
2784df279a26SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
2785df279a26SBjoern A. Zeeb break;
2786df279a26SBjoern A. Zeeb default:
2787df279a26SBjoern A. Zeeb break;
2788df279a26SBjoern A. Zeeb }
27898e93258fSBjoern A. Zeeb }
2790