diff options
Diffstat (limited to 'sys/contrib/dev/rtw89/chan.c')
| -rw-r--r-- | sys/contrib/dev/rtw89/chan.c | 993 | 
1 files changed, 832 insertions, 161 deletions
| diff --git a/sys/contrib/dev/rtw89/chan.c b/sys/contrib/dev/rtw89/chan.c index 257331c2de2e..bbdae184a0df 100644 --- a/sys/contrib/dev/rtw89/chan.c +++ b/sys/contrib/dev/rtw89/chan.c @@ -7,7 +7,9 @@  #include "debug.h"  #include "fw.h"  #include "mac.h" +#include "phy.h"  #include "ps.h" +#include "sar.h"  #include "util.h"  static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, @@ -127,6 +129,48 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,  						    bandwidth);  } +static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, +					 struct rtw89_vif_link *rtwvif_link, +					 const struct cfg80211_chan_def *chandef) +{ +	struct ieee80211_bss_conf *bss_conf; + +	if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && +	    rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) +		return; + +	rcu_read_lock(); + +	bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); +	if (!bss_conf->eht_support) { +		rcu_read_unlock(); +		return; +	} + +	rcu_read_unlock(); + +	rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured); +} + +static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, +					enum rtw89_chanctx_idx idx, +					const struct cfg80211_chan_def *chandef) +{ +	struct rtw89_vif_link *rtwvif_link; +	struct rtw89_vif *rtwvif; +	unsigned int link_id; + +	rtw89_for_each_rtwvif(rtwdev, rtwvif) { +		rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { +			if (!rtwvif_link->chanctx_assigned || +			    rtwvif_link->chanctx_idx != idx) +				continue; + +			_rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef); +		} +	} +} +  bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,  			      enum rtw89_chanctx_idx idx,  			      const struct rtw89_chan *new) @@ -155,7 +199,7 @@ int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,  	int ret;  	u8 idx; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	for_each_set_bit(idx,  hal->entity_map, NUM_OF_RTW89_CHANCTX) {  		chan = rtw89_chan_get(rtwdev, idx); @@ -169,28 +213,33 @@ int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,  static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,  					  enum rtw89_chanctx_idx idx, -					  const struct cfg80211_chan_def *chandef, -					  bool from_stack) +					  const struct cfg80211_chan_def *chandef)  {  	struct rtw89_hal *hal = &rtwdev->hal;  	hal->chanctx[idx].chandef = *chandef; - -	if (from_stack) -		set_bit(idx, hal->entity_map);  }  void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,  				 enum rtw89_chanctx_idx idx,  				 const struct cfg80211_chan_def *chandef)  { -	__rtw89_config_entity_chandef(rtwdev, idx, chandef, true); +	struct rtw89_hal *hal = &rtwdev->hal; + +	if (!chandef) { +		clear_bit(idx, hal->entity_map); +		return; +	} + +	__rtw89_config_entity_chandef(rtwdev, idx, chandef); +	set_bit(idx, hal->entity_map);  }  void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, -			      enum rtw89_chanctx_idx idx, +			      struct rtw89_vif_link *rtwvif_link,  			      const struct cfg80211_chan_def *chandef)  { +	enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx;  	struct rtw89_hal *hal = &rtwdev->hal;  	enum rtw89_chanctx_idx cur; @@ -204,6 +253,7 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,  		}  		hal->roc_chandef = *chandef; +		hal->roc_link_index = rtw89_vif_link_inst_get_index(rtwvif_link);  	} else {  		cur = atomic_cmpxchg(&hal->roc_chanctx_idx, idx,  				     RTW89_CHANCTX_IDLE); @@ -224,7 +274,7 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)  	struct cfg80211_chan_def chandef = {0};  	rtw89_get_default_chandef(&chandef); -	__rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef, false); +	__rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef);  }  void rtw89_entity_init(struct rtw89_dev *rtwdev) @@ -262,6 +312,8 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,  	struct rtw89_vif *rtwvif;  	int idx; +	w->registered_chanctxs = bitmap_weight(hal->entity_map, NUM_OF_RTW89_CHANCTX); +  	for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) {  		cfg = hal->chanctx[idx].cfg;  		if (!cfg) { @@ -310,7 +362,7 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,  	enum rtw89_entity_mode mode;  	u8 role_index; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) {  		WARN(1, "link index %u is invalid (max link inst num: %d)\n", @@ -338,11 +390,10 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,  	roc_idx = atomic_read(&hal->roc_chanctx_idx);  	if (roc_idx != RTW89_CHANCTX_IDLE) { -		/* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX). -		 * If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get -		 * the ongoing ROC chanctx. +		/* ROC is ongoing (given ROC runs on @hal->roc_link_index). +		 * If @link_index is the same, get the ongoing ROC chanctx.  		 */ -		if (link_index == RTW89_ROC_BY_LINK_INDEX) +		if (link_index == hal->roc_link_index)  			chanctx_idx = roc_idx;  	} @@ -357,16 +408,45 @@ dflt:  }  EXPORT_SYMBOL(__rtw89_mgnt_chan_get); +static enum rtw89_mlo_dbcc_mode +rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws) +{ +	if (rtwdev->chip->chip_gen != RTW89_CHIP_BE) +		return MLO_DBCC_NOT_SUPPORT; + +	switch (active_hws) { +	case BIT(0): +		return MLO_2_PLUS_0_1RF; +	case BIT(1): +		return MLO_0_PLUS_2_1RF; +	case BIT(0) | BIT(1): +	default: +		return MLO_1_PLUS_1_1RF; +	} +} + +static +void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws) +{ +	enum rtw89_mlo_dbcc_mode mode; + +	mode = rtw89_entity_sel_mlo_dbcc_mode(rtwdev, active_hws); +	rtwdev->mlo_dbcc_mode = mode; + +	rtw89_debug(rtwdev, RTW89_DBG_STATE, "recalc mlo dbcc mode to %d\n", mode); +} +  static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)  {  	struct rtw89_hal *hal = &rtwdev->hal;  	struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;  	struct rtw89_vif_link *link;  	struct rtw89_vif *role; +	u8 active_hws = 0;  	u8 pos = 0;  	int i, j; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++)  		mgnt->active_roles[i] = NULL; @@ -411,10 +491,13 @@ fill:  				continue;  			mgnt->chanctx_tbl[pos][i] = link->chanctx_idx; +			active_hws |= BIT(i);  		}  		mgnt->active_roles[pos++] = role;  	} + +	rtw89_entity_recalc_mlo_dbcc_mode(rtwdev, active_hws);  }  enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) @@ -427,7 +510,7 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)  	struct rtw89_chan chan;  	u8 idx; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_CHANCTX); @@ -439,7 +522,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)  		bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX);  		fallthrough;  	case 0: -		rtw89_config_default_chandef(rtwdev); +		if (!w.registered_chanctxs) +			rtw89_config_default_chandef(rtwdev);  		set_bit(RTW89_CHANCTX_0, recalc_map);  		fallthrough;  	case 1: @@ -556,7 +640,9 @@ static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,  	u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);  	u32 remainder; -	if (tsf < sync_tsf) { +	if (role->is_go) { +		sync_tsf = 0; +	} else if (tsf < sync_tsf) {  		rtw89_debug(rtwdev, RTW89_DBG_CHAN,  			    "MCC get tbtt ofst: tsf might not update yet\n");  		sync_tsf = 0; @@ -690,19 +776,13 @@ static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)  	struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif;  	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);  	struct rtw89_vif *rtwvif = rtwsta->rtwvif; -	struct rtw89_dev *rtwdev = rtwsta->rtwdev; -	struct rtw89_sta_link *rtwsta_link; +	u8 macid;  	if (rtwvif != target)  		return; -	rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); -	if (unlikely(!rtwsta_link)) { -		rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n"); -		return; -	} - -	rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id); +	macid = rtw89_sta_get_main_macid(rtwsta); +	rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, macid);  }  static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev, @@ -746,9 +826,11 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,  	int ret;  	int i; -	if (!mcc_role->is_go && !mcc_role->is_gc) +	if (!mcc_role->is_gc)  		return; +	rtw89_p2p_noa_once_recalc(rtwvif_link); +  	rcu_read_lock();  	bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); @@ -784,6 +866,9 @@ fill:  	}  	tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time; +	if (tsf_lmt < tsf) +		tsf_lmt += roundup_u64(tsf - tsf_lmt, interval); +  	max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, mcc_role, tsf_lmt);  	max_dur_us = interval - duration;  	max_tob_us = max_dur_us - max_toa_us; @@ -918,6 +1003,7 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)  		}  		sel.bind_vif[i] = rtwvif_link; +		rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, NULL);  	}  	ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -928,6 +1014,15 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)  	return 0;  } +static bool rtw89_mcc_can_courtesy(const struct rtw89_mcc_role *provider, +				   const struct rtw89_mcc_role *receiver) +{ +	if (provider->is_go || receiver->is_gc) +		return false; + +	return true; +} +  static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,  				     const struct rtw89_mcc_pattern *new)  { @@ -936,37 +1031,54 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,  	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config *config = &mcc->config;  	struct rtw89_mcc_pattern *pattern = &config->pattern; +	struct rtw89_mcc_courtesy_cfg *crtz;  	rtw89_debug(rtwdev, RTW89_DBG_CHAN,  		    "MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",  		    new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux); +	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC pattern plan: %d\n", new->plan); +  	*pattern = *new;  	memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); -	if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) { -		pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id; -		pattern->courtesy.macid_src = ref->rtwvif_link->mac_id; -		pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; -		pattern->courtesy.enable = true; -	} else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) { -		pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id; -		pattern->courtesy.macid_src = aux->rtwvif_link->mac_id; -		pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; -		pattern->courtesy.enable = true; +	if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc) +		aux->ignore_bcn = true; +	else +		aux->ignore_bcn = false; + +	if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) { +		crtz = &pattern->courtesy.ref; +		ref->crtz = crtz; + +		crtz->macid_tgt = aux->rtwvif_link->mac_id; +		crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; + +		rtw89_debug(rtwdev, RTW89_DBG_CHAN, +			    "MCC courtesy ref: tgt %d, slot %d\n", +			    crtz->macid_tgt, crtz->slot_num); +	} else { +		ref->crtz = NULL;  	} -	rtw89_debug(rtwdev, RTW89_DBG_CHAN, -		    "MCC pattern flags: plan %d, courtesy_en %d\n", -		    pattern->plan, pattern->courtesy.enable); +	if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc) +		ref->ignore_bcn = true; +	else +		ref->ignore_bcn = false; -	if (!pattern->courtesy.enable) -		return; +	if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) { +		crtz = &pattern->courtesy.aux; +		aux->crtz = crtz; -	rtw89_debug(rtwdev, RTW89_DBG_CHAN, -		    "MCC pattern courtesy: tgt %d, src %d, slot %d\n", -		    pattern->courtesy.macid_tgt, pattern->courtesy.macid_src, -		    pattern->courtesy.slot_num); +		crtz->macid_tgt = ref->rtwvif_link->mac_id; +		crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; + +		rtw89_debug(rtwdev, RTW89_DBG_CHAN, +			    "MCC courtesy aux: tgt %d, slot %d\n", +			    crtz->macid_tgt, crtz->slot_num); +	} else { +		aux->crtz = NULL; +	}  }  /* The follow-up roughly shows the relationship between the parameters @@ -991,6 +1103,7 @@ static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,  	struct rtw89_mcc_role *ref = &mcc->role_ref;  	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config *config = &mcc->config; +	u16 mcc_intvl = config->mcc_interval;  	u16 bcn_ofst = config->beacon_offset;  	u16 bt_dur_in_mid = 0;  	u16 max_bcn_ofst; @@ -1024,7 +1137,7 @@ calc:  	res = bcn_ofst - bt_dur_in_mid;  	upper = min_t(s16, ref->duration, res); -	lower = 0; +	lower = max_t(s16, 0, ref->duration - (mcc_intvl - bcn_ofst));  	if (ref->limit.enable) {  		upper = min_t(s16, upper, ref->limit.max_toa); @@ -1055,7 +1168,7 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,  	struct rtw89_mcc_role *ref = &mcc->role_ref;  	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config *config = &mcc->config; -	u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME; +	u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME;  	u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME;  	u16 bcn_ofst = config->beacon_offset;  	s16 upper_toa_ref, lower_toa_ref; @@ -1135,6 +1248,109 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,  	return 0;  } +static void __rtw89_mcc_fill_ptrn_anchor_ref(struct rtw89_dev *rtwdev, +					     struct rtw89_mcc_pattern *ptrn, +					     bool small_bcn_ofst) +{ +	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux; +	struct rtw89_mcc_config *config = &mcc->config; +	u16 bcn_ofst = config->beacon_offset; +	u16 ref_tob; +	u16 ref_toa; + +	if (ref->limit.enable) { +		ref_tob = ref->limit.max_tob; +		ref_toa = ref->limit.max_toa; +	} else { +		ref_tob = ref->duration / 2; +		ref_toa = ref->duration / 2; +	} + +	if (small_bcn_ofst) { +		ptrn->toa_ref = ref_toa; +		ptrn->tob_ref = ref->duration - ptrn->toa_ref; +	} else { +		ptrn->tob_ref = ref_tob; +		ptrn->toa_ref = ref->duration - ptrn->tob_ref; +	} + +	ptrn->tob_aux = bcn_ofst - ptrn->toa_ref; +	ptrn->toa_aux = aux->duration - ptrn->tob_aux; +} + +static void __rtw89_mcc_fill_ptrn_anchor_aux(struct rtw89_dev *rtwdev, +					     struct rtw89_mcc_pattern *ptrn, +					     bool small_bcn_ofst) +{ +	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux; +	struct rtw89_mcc_config *config = &mcc->config; +	u16 bcn_ofst = config->beacon_offset; +	u16 aux_tob; +	u16 aux_toa; + +	if (aux->limit.enable) { +		aux_tob = aux->limit.max_tob; +		aux_toa = aux->limit.max_toa; +	} else { +		aux_tob = aux->duration / 2; +		aux_toa = aux->duration / 2; +	} + +	if (small_bcn_ofst) { +		ptrn->tob_aux = aux_tob; +		ptrn->toa_aux = aux->duration - ptrn->tob_aux; +	} else { +		ptrn->toa_aux = aux_toa; +		ptrn->tob_aux = aux->duration - ptrn->toa_aux; +	} + +	ptrn->toa_ref = bcn_ofst - ptrn->tob_aux; +	ptrn->tob_ref = ref->duration - ptrn->toa_ref; +} + +static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, +					   struct rtw89_mcc_pattern *ptrn, +					   bool hdl_bt) +{ +	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux; +	struct rtw89_mcc_config *config = &mcc->config; +	u16 mcc_intvl = config->mcc_interval; +	u16 bcn_ofst = config->beacon_offset; +	bool small_bcn_ofst; + +	if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) +		small_bcn_ofst = true; +	else if (bcn_ofst < aux->duration - aux->limit.max_toa) +		small_bcn_ofst = true; +	else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) +		small_bcn_ofst = false; +	else +		return -EPERM; + +	*ptrn = (typeof(*ptrn)){ +		.plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT, +	}; + +	rtw89_debug(rtwdev, RTW89_DBG_CHAN, +		    "MCC calc ptrn_ac: plan %d, bcn_ofst %d\n", +		    ptrn->plan, bcn_ofst); + +	if (ref->is_go || ref->is_gc) +		__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst); +	else if (aux->is_go || aux->is_gc) +		__rtw89_mcc_fill_ptrn_anchor_aux(rtwdev, ptrn, small_bcn_ofst); +	else +		__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst); + +	return 0; +} +  static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)  {  	struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1188,6 +1404,10 @@ static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)  			goto done;  	} +	ret = __rtw89_mcc_calc_pattern_anchor(rtwdev, &ptrn, hdl_bt); +	if (!ret) +		goto done; +  	__rtw89_mcc_calc_pattern_loose(rtwdev, &ptrn, hdl_bt);  done: @@ -1438,88 +1658,72 @@ static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)  	return false;  } -static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, -				struct rtw89_mcc_role *tgt, -				struct rtw89_mcc_role *src, -				bool ref_is_src) +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work)  { -	struct rtw89_mcc_info *mcc = &rtwdev->mcc; -	struct rtw89_mcc_config *config = &mcc->config; -	u16 beacon_offset_us = ieee80211_tu_to_usec(config->beacon_offset); -	u32 bcn_intvl_src_us = ieee80211_tu_to_usec(src->beacon_interval); -	u32 cur_tbtt_ofst_src; -	u32 tsf_ofst_tgt; -	u32 remainder; -	u64 tbtt_tgt; -	u64 tsf_src; -	int ret; - -	ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src); -	if (ret) { -		rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); -		return; -	} - -	cur_tbtt_ofst_src = rtw89_mcc_get_tbtt_ofst(rtwdev, src, tsf_src); +	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, +						mcc_prepare_done_work.work); -	if (ref_is_src) -		tbtt_tgt = tsf_src - cur_tbtt_ofst_src + beacon_offset_us; -	else -		tbtt_tgt = tsf_src - cur_tbtt_ofst_src + -			   (bcn_intvl_src_us - beacon_offset_us); +	lockdep_assert_wiphy(wiphy); -	div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder); -	tsf_ofst_tgt = bcn_intvl_src_us - remainder; +	ieee80211_wake_queues(rtwdev->hw); +} -	config->sync.macid_tgt = tgt->rtwvif_link->mac_id; -	config->sync.band_tgt = tgt->rtwvif_link->mac_idx; -	config->sync.port_tgt = tgt->rtwvif_link->port; -	config->sync.macid_src = src->rtwvif_link->mac_id; -	config->sync.band_src = src->rtwvif_link->mac_idx; -	config->sync.port_src = src->rtwvif_link->port; -	config->sync.offset = tsf_ofst_tgt / 1024; -	config->sync.enable = true; +static void rtw89_mcc_prepare(struct rtw89_dev *rtwdev, bool start) +{ +	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	struct rtw89_mcc_config *config = &mcc->config; -	rtw89_debug(rtwdev, RTW89_DBG_CHAN, -		    "MCC sync tbtt: tgt %d, src %d, offset %d\n", -		    config->sync.macid_tgt, config->sync.macid_src, -		    config->sync.offset); +	if (start) { +		ieee80211_stop_queues(rtwdev->hw); -	rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link, -				config->sync.offset); +		wiphy_delayed_work_queue(rtwdev->hw->wiphy, +					 &rtwdev->mcc_prepare_done_work, +					 usecs_to_jiffies(config->prepare_delay)); +	} else { +		wiphy_delayed_work_queue(rtwdev->hw->wiphy, +					 &rtwdev->mcc_prepare_done_work, 0); +		wiphy_delayed_work_flush(rtwdev->hw->wiphy, +					 &rtwdev->mcc_prepare_done_work); +	}  }  static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)  {  	struct rtw89_mcc_info *mcc = &rtwdev->mcc;  	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config *config = &mcc->config;  	u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval); -	u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref); -	struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link; +	s32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);  	u64 tsf, start_tsf;  	u32 cur_tbtt_ofst;  	u64 min_time; +	u64 tsf_aux;  	int ret; -	ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); -	if (ret) { -		rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); +	if (rtw89_concurrent_via_mrc(rtwdev)) +		ret = __mrc_fw_req_tsf(rtwdev, &tsf, &tsf_aux); +	else +		ret = __mcc_fw_req_tsf(rtwdev, &tsf, &tsf_aux); + +	if (ret)  		return ret; -	}  	min_time = tsf; -	if (ref->is_go) +	if (ref->is_go || aux->is_go)  		min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);  	else  		min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);  	cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf);  	start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us; -	while (start_tsf < min_time) -		start_tsf += bcn_intvl_ref_us; +	if (start_tsf < min_time) +		start_tsf += roundup_u64(min_time - start_tsf, bcn_intvl_ref_us);  	config->start_tsf = start_tsf; +	config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf; +	config->prepare_delay = start_tsf - tsf; +  	return 0;  } @@ -1536,13 +1740,11 @@ static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)  	switch (mcc->mode) {  	case RTW89_MCC_MODE_GO_STA: -		config->beacon_offset = RTW89_MCC_DFLT_BCN_OFST_TIME; +		config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);  		if (ref->is_go) { -			rtw89_mcc_sync_tbtt(rtwdev, ref, aux, false);  			config->mcc_interval = ref->beacon_interval;  			rtw89_mcc_set_duration_go_sta(rtwdev, ref, aux);  		} else { -			rtw89_mcc_sync_tbtt(rtwdev, aux, ref, true);  			config->mcc_interval = aux->beacon_interval;  			rtw89_mcc_set_duration_go_sta(rtwdev, aux, ref);  		} @@ -1572,10 +1774,8 @@ bottom:  static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)  { +	const struct rtw89_mcc_courtesy_cfg *crtz = role->crtz;  	struct rtw89_mcc_info *mcc = &rtwdev->mcc; -	struct rtw89_mcc_config *config = &mcc->config; -	struct rtw89_mcc_pattern *pattern = &config->pattern; -	struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;  	struct rtw89_mcc_policy *policy = &role->policy;  	struct rtw89_fw_mcc_add_req req = {};  	const struct rtw89_chan *chan; @@ -1598,9 +1798,9 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro  	req.duration = role->duration;  	req.btc_in_2g = false; -	if (courtesy->enable && courtesy->macid_src == req.macid) { -		req.courtesy_target = courtesy->macid_tgt; -		req.courtesy_num = courtesy->slot_num; +	if (crtz) { +		req.courtesy_target = crtz->macid_tgt; +		req.courtesy_num = crtz->slot_num;  		req.courtesy_en = true;  	} @@ -1780,26 +1980,23 @@ static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,  	struct rtw89_mcc_info *mcc = &rtwdev->mcc;  	struct rtw89_mcc_role *ref = &mcc->role_ref;  	struct rtw89_mcc_role *aux = &mcc->role_aux; -	struct rtw89_mcc_config *config = &mcc->config; -	struct rtw89_mcc_pattern *pattern = &config->pattern; -	struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;  	struct rtw89_fw_mrc_add_slot_arg *slot_arg_src; -	u8 slot_idx_tgt; - -	if (!courtesy->enable) -		return; -	if (courtesy->macid_src == ref->rtwvif_link->mac_id) { +	if (ref->crtz) {  		slot_arg_src = &arg->slots[ref->slot_idx]; -		slot_idx_tgt = aux->slot_idx; -	} else { -		slot_arg_src = &arg->slots[aux->slot_idx]; -		slot_idx_tgt = ref->slot_idx; + +		slot_arg_src->courtesy_target = aux->slot_idx; +		slot_arg_src->courtesy_period = ref->crtz->slot_num; +		slot_arg_src->courtesy_en = true;  	} -	slot_arg_src->courtesy_target = slot_idx_tgt; -	slot_arg_src->courtesy_period = courtesy->slot_num; -	slot_arg_src->courtesy_en = true; +	if (aux->crtz) { +		slot_arg_src = &arg->slots[aux->slot_idx]; + +		slot_arg_src->courtesy_target = ref->slot_idx; +		slot_arg_src->courtesy_period = aux->crtz->slot_num; +		slot_arg_src->courtesy_en = true; +	}  }  static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace) @@ -1999,30 +2196,24 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)  	struct rtw89_mcc_role *ref = &mcc->role_ref;  	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config *config = &mcc->config; -	struct rtw89_mcc_pattern *pattern = &config->pattern; -	struct rtw89_mcc_sync *sync = &config->sync;  	struct ieee80211_p2p_noa_desc noa_desc = {}; -	u64 start_time = config->start_tsf;  	u32 interval = config->mcc_interval;  	struct rtw89_vif_link *rtwvif_go; +	u64 start_time;  	u32 duration;  	if (mcc->mode != RTW89_MCC_MODE_GO_STA)  		return;  	if (ref->is_go) { +		start_time = config->start_tsf;  		rtwvif_go = ref->rtwvif_link;  		start_time += ieee80211_tu_to_usec(ref->duration);  		duration = config->mcc_interval - ref->duration;  	} else if (aux->is_go) { +		start_time = config->start_tsf_in_aux_domain;  		rtwvif_go = aux->rtwvif_link; -		start_time += ieee80211_tu_to_usec(pattern->tob_ref) + -			      ieee80211_tu_to_usec(config->beacon_offset) + -			      ieee80211_tu_to_usec(pattern->toa_aux);  		duration = config->mcc_interval - aux->duration; - -		/* convert time domain from sta(ref) to GO(aux) */ -		start_time += ieee80211_tu_to_usec(sync->offset);  	} else {  		rtw89_debug(rtwdev, RTW89_DBG_CHAN,  			    "MCC find no GO: skip updating beacon NoA\n"); @@ -2032,6 +2223,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)  	rtw89_p2p_noa_renew(rtwvif_go);  	if (enable) { +		duration += RTW89_MCC_SWITCH_CH_TIME;  		noa_desc.start_time = cpu_to_le32(start_time);  		noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval));  		noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration)); @@ -2080,6 +2272,18 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)  	rtw89_mcc_handle_beacon_noa(rtwdev, false);  } +static bool rtw89_mcc_ignore_bcn(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) +{ +	enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + +	if (role->is_go) +		return true; +	else if (chip_gen == RTW89_CHIP_BE && role->is_gc) +		return true; +	else +		return false; +} +  static int rtw89_mcc_start(struct rtw89_dev *rtwdev)  {  	struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -2111,6 +2315,15 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev)  	if (ret)  		return ret; +	if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) { +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); +	} else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) { +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); +	} else { +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); +	} +  	if (rtw89_concurrent_via_mrc(rtwdev))  		ret = __mrc_fw_start(rtwdev, false);  	else @@ -2122,10 +2335,19 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev)  	rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);  	rtw89_mcc_start_beacon_noa(rtwdev); +	rtw89_phy_dig_suspend(rtwdev); + +	rtw89_mcc_prepare(rtwdev, true);  	return 0;  }  struct rtw89_mcc_stop_sel { +	struct { +		const struct rtw89_vif_link *target; +	} hint; + +	/* selection content */ +	bool filled;  	u8 mac_id;  	u8 slot_idx;  }; @@ -2135,6 +2357,7 @@ static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel,  {  	sel->mac_id = mcc_role->rtwvif_link->mac_id;  	sel->slot_idx = mcc_role->slot_idx; +	sel->filled = true;  }  static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev, @@ -2144,23 +2367,49 @@ static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,  {  	struct rtw89_mcc_stop_sel *sel = data; +	if (mcc_role->rtwvif_link == sel->hint.target) { +		rtw89_mcc_stop_sel_fill(sel, mcc_role); +		return 1; /* break iteration */ +	} + +	if (sel->filled) +		return 0; +  	if (!mcc_role->rtwvif_link->chanctx_assigned)  		return 0;  	rtw89_mcc_stop_sel_fill(sel, mcc_role); -	return 1; /* break iteration */ +	return 0;  } -static void rtw89_mcc_stop(struct rtw89_dev *rtwdev) +static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, +			   const struct rtw89_chanctx_pause_parm *pause)  { +	struct rtw89_hal *hal = &rtwdev->hal;  	struct rtw89_mcc_info *mcc = &rtwdev->mcc;  	struct rtw89_mcc_role *ref = &mcc->role_ref; -	struct rtw89_mcc_stop_sel sel; +	struct rtw89_mcc_role *aux = &mcc->role_aux; +	struct rtw89_mcc_stop_sel sel = { +		.hint.target = pause ? pause->trigger : NULL, +	}; +	bool rsn_scan;  	int ret; +	if (!pause) { +		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->chanctx_work); +		bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); +	} + +	rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN; +	if (rsn_scan && ref->is_go) +		sel.hint.target = ref->rtwvif_link; +	else if (rsn_scan && aux->is_go) +		sel.hint.target = aux->rtwvif_link; +  	/* by default, stop at ref */ -	rtw89_mcc_stop_sel_fill(&sel, ref);  	rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel); +	if (!sel.filled) +		rtw89_mcc_stop_sel_fill(&sel, ref);  	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop at <macid %d>\n", sel.mac_id); @@ -2185,13 +2434,22 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)  	rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);  	rtw89_mcc_stop_beacon_noa(rtwdev); +	rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); +	rtw89_phy_dig_resume(rtwdev, true); + +	rtw89_mcc_prepare(rtwdev, false);  }  static int rtw89_mcc_update(struct rtw89_dev *rtwdev)  {  	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn; +	bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn;  	struct rtw89_mcc_config *config = &mcc->config; +	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux;  	struct rtw89_mcc_config old_cfg = *config; +	bool courtesy_changed;  	bool sync_changed;  	int ret; @@ -2204,8 +2462,20 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)  	if (ret)  		return ret; +	if (old_ref_ignore_bcn != ref->ignore_bcn) +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn); +	else if (old_aux_ignore_bcn != aux->ignore_bcn) +		rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn); + +	if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy, +		   sizeof(old_cfg.pattern.courtesy)) == 0) +		courtesy_changed = false; +	else +		courtesy_changed = true; +  	if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT || -	    config->pattern.plan != RTW89_MCC_PLAN_NO_BT) { +	    config->pattern.plan != RTW89_MCC_PLAN_NO_BT || +	    courtesy_changed) {  		if (rtw89_concurrent_via_mrc(rtwdev))  			ret = __mrc_fw_start(rtwdev, true);  		else @@ -2232,31 +2502,167 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)  	return 0;  } +static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev, +					struct rtw89_mcc_role *mcc_role, +					unsigned int ordered_idx, +					void *data) +{ +	struct rtw89_mcc_role **role = data; + +	if (mcc_role->is_gc) +		*role = mcc_role; + +	return 0; +} + +static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev) +{ +	struct rtw89_mcc_info *mcc = &rtwdev->mcc; +	struct rtw89_mcc_role *role = NULL; + +	if (mcc->mode != RTW89_MCC_MODE_GC_STA) +		return NULL; + +	rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role); + +	return role; +} + +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ +	struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, +							  mcc_gc_detect_beacon_work.work); +	struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); +	enum rtw89_entity_mode mode; +	struct rtw89_dev *rtwdev; + +	lockdep_assert_wiphy(wiphy); + +	rtwdev = rtwvif_link->rtwvif->rtwdev; + +	mode = rtw89_get_entity_mode(rtwdev); +	if (mode != RTW89_ENTITY_MODE_MCC) +		return; + +	if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf) +		rtwvif_link->detect_bcn_count = 0; +	else +		rtwvif_link->detect_bcn_count++; + +	if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES) +		rtw89_chanctx_proceed(rtwdev, NULL); +	else +		ieee80211_connection_loss(vif); +} + +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, +			     struct rtw89_vif_link *rtwvif_link) +{ +	enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); +	struct rtw89_chanctx_pause_parm pause_parm = { +		.rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, +		.trigger = rtwvif_link, +	}; +	struct ieee80211_bss_conf *bss_conf; +	struct rtw89_mcc_role *role; +	u16 bcn_int; + +	if (mode != RTW89_ENTITY_MODE_MCC) +		return false; + +	role = rtw89_mcc_get_gc_role(rtwdev); +	if (!role) +		return false; + +	if (role->rtwvif_link != rtwvif_link) +		return false; + +	rtw89_debug(rtwdev, RTW89_DBG_CHAN, +		    "MCC GC beacon loss, pause MCC to detect GO beacon\n"); + +	rcu_read_lock(); + +	bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); +	bcn_int = bss_conf->beacon_int; + +	rcu_read_unlock(); + +	rtw89_chanctx_pause(rtwdev, &pause_parm); +	rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); +	wiphy_delayed_work_queue(rtwdev->hw->wiphy, +				 &rtwvif_link->mcc_gc_detect_beacon_work, +				 usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int))); + +	return true; +} + +static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, +					struct rtw89_mcc_role *role) +{ +	struct ieee80211_vif *vif; +	bool start_detect; +	int ret; + +	ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, +				       RTW89_MCC_PROBE_TIMEOUT); +	if (ret) +		role->probe_count++; +	else +		role->probe_count = 0; + +	if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES) +		return; + +	rtw89_debug(rtwdev, RTW89_DBG_CHAN, +		    "MCC <macid %d> can not detect AP/GO\n", role->rtwvif_link->mac_id); + +	start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link); +	if (start_detect) +		return; + +	vif = rtwvif_link_to_vif(role->rtwvif_link); +	ieee80211_connection_loss(vif); +} +  static void rtw89_mcc_track(struct rtw89_dev *rtwdev)  {  	struct rtw89_mcc_info *mcc = &rtwdev->mcc;  	struct rtw89_mcc_config *config = &mcc->config;  	struct rtw89_mcc_pattern *pattern = &config->pattern; -	s16 tolerance; +	struct rtw89_mcc_role *ref = &mcc->role_ref; +	struct rtw89_mcc_role *aux = &mcc->role_aux; +	u16 tolerance;  	u16 bcn_ofst;  	u16 diff; +	if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) +		rtw89_mcc_detect_connection(rtwdev, aux); +	else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) +		rtw89_mcc_detect_connection(rtwdev, ref); +  	if (mcc->mode != RTW89_MCC_MODE_GC_STA)  		return;  	bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev); +	if (bcn_ofst == config->beacon_offset) +		return; +  	if (bcn_ofst > config->beacon_offset) {  		diff = bcn_ofst - config->beacon_offset;  		if (pattern->tob_aux < 0)  			tolerance = -pattern->tob_aux; -		else +		else if (pattern->toa_aux > 0)  			tolerance = pattern->toa_aux; +		else +			return; /* no chance to improve */  	} else {  		diff = config->beacon_offset - bcn_ofst;  		if (pattern->toa_aux < 0)  			tolerance = -pattern->toa_aux; -		else +		else if (pattern->tob_aux > 0)  			tolerance = pattern->tob_aux; +		else +			return; /* no chance to improve */  	}  	if (diff <= tolerance) @@ -2390,7 +2796,31 @@ static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev)  	rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL);  } -void rtw89_chanctx_work(struct work_struct *work) +static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev, +					struct rtw89_mcc_role *mcc_role, +					unsigned int ordered_idx, +					void *data) +{ +	struct rtw89_mcc_links_info *info = data; + +	info->links[ordered_idx] = mcc_role->rtwvif_link; +	return 0; +} + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info) +{ +	enum rtw89_entity_mode mode; + +	memset(info, 0, sizeof(*info)); + +	mode = rtw89_get_entity_mode(rtwdev); +	if (unlikely(mode != RTW89_ENTITY_MODE_MCC)) +		return; + +	rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info); +} + +void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work)  {  	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,  						chanctx_work.work); @@ -2401,12 +2831,10 @@ void rtw89_chanctx_work(struct work_struct *work)  	int ret;  	int i; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(wiphy); -	if (hal->entity_pause) { -		mutex_unlock(&rtwdev->mutex); +	if (hal->entity_pause)  		return; -	}  	for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) {  		if (test_and_clear_bit(i, hal->changes)) @@ -2445,8 +2873,6 @@ void rtw89_chanctx_work(struct work_struct *work)  	default:  		break;  	} - -	mutex_unlock(&rtwdev->mutex);  }  void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, @@ -2462,6 +2888,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,  		return;  	case RTW89_ENTITY_MODE_MCC_PREPARE:  		delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); +		rtw89_phy_dig_suspend(rtwdev);  		break;  	case RTW89_ENTITY_MODE_MCC:  		delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC); @@ -2477,8 +2904,8 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,  	rtw89_debug(rtwdev, RTW89_DBG_CHAN,  		    "queue chanctx work for mode %d with delay %d us\n",  		    mode, delay); -	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work, -				     usecs_to_jiffies(delay)); +	wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->chanctx_work, +				 usecs_to_jiffies(delay));  }  void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) @@ -2486,12 +2913,207 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)  	rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT);  } +static enum rtw89_mr_wtype __rtw89_query_mr_wtype(struct rtw89_dev *rtwdev) +{ +	struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; +	enum rtw89_chanctx_idx chanctx_idx; +	struct ieee80211_vif *vif; +	struct rtw89_vif *rtwvif; +	unsigned int num_mld = 0; +	unsigned int num_ml = 0; +	unsigned int cnt = 0; +	u8 role_idx; +	u8 idx; + +	for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { +		rtwvif = mgnt->active_roles[role_idx]; +		if (!rtwvif) +			continue; + +		cnt++; + +		vif = rtwvif_to_vif(rtwvif); +		if (!ieee80211_vif_is_mld(vif)) +			continue; + +		num_mld++; + +		for (idx = 0; idx < __RTW89_MLD_MAX_LINK_NUM; idx++) { +			chanctx_idx = mgnt->chanctx_tbl[role_idx][idx]; +			if (chanctx_idx != RTW89_CHANCTX_IDLE) +				num_ml++; +		} +	} + +	if (num_mld > 1) +		goto err; + +	switch (cnt) { +	case 0: +		return RTW89_MR_WTYPE_NONE; +	case 1: +		if (!num_mld) +			return RTW89_MR_WTYPE_NONMLD; +		switch (num_ml) { +		case 1: +			return RTW89_MR_WTYPE_MLD1L1R; +		case 2: +			return RTW89_MR_WTYPE_MLD2L1R; +		default: +			break; +		} +		break; +	case 2: +		if (!num_mld) +			return RTW89_MR_WTYPE_NONMLD_NONMLD; +		switch (num_ml) { +		case 1: +			return RTW89_MR_WTYPE_MLD1L1R_NONMLD; +		case 2: +			return RTW89_MR_WTYPE_MLD2L1R_NONMLD; +		default: +			break; +		} +		break; +	default: +		break; +	} + +err: +	rtw89_warn(rtwdev, "%s: unhandled cnt %u mld %u ml %u\n", __func__, +		   cnt, num_mld, num_ml); +	return RTW89_MR_WTYPE_UNKNOWN; +} + +static enum rtw89_mr_wmode __rtw89_query_mr_wmode(struct rtw89_dev *rtwdev, +						  u8 inst_idx) +{ +	struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; +	unsigned int num[NUM_NL80211_IFTYPES] = {}; +	enum rtw89_chanctx_idx chanctx_idx; +	struct ieee80211_vif *vif; +	struct rtw89_vif *rtwvif; +	unsigned int cnt = 0; +	u8 role_idx; + +	if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) +		return RTW89_MR_WMODE_UNKNOWN; + +	for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { +		chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; +		if (chanctx_idx == RTW89_CHANCTX_IDLE) +			continue; + +		rtwvif = mgnt->active_roles[role_idx]; +		if (unlikely(!rtwvif)) +			continue; + +		vif = rtwvif_to_vif(rtwvif); +		num[vif->type]++; +		cnt++; +	} + +	switch (cnt) { +	case 0: +		return RTW89_MR_WMODE_NONE; +	case 1: +		if (num[NL80211_IFTYPE_STATION]) +			return RTW89_MR_WMODE_1CLIENT; +		if (num[NL80211_IFTYPE_AP]) +			return RTW89_MR_WMODE_1AP; +		break; +	case 2: +		if (num[NL80211_IFTYPE_STATION] == 2) +			return RTW89_MR_WMODE_2CLIENTS; +		if (num[NL80211_IFTYPE_AP] == 2) +			return RTW89_MR_WMODE_2APS; +		if (num[NL80211_IFTYPE_STATION] && num[NL80211_IFTYPE_AP]) +			return RTW89_MR_WMODE_1AP_1CLIENT; +		break; +	default: +		break; +	} + +	rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); +	return RTW89_MR_WMODE_UNKNOWN; +} + +static enum rtw89_mr_ctxtype __rtw89_query_mr_ctxtype(struct rtw89_dev *rtwdev, +						      u8 inst_idx) +{ +	struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; +	DECLARE_BITMAP(map, NUM_OF_RTW89_CHANCTX) = {}; +	unsigned int num[RTW89_BAND_NUM] = {}; +	enum rtw89_chanctx_idx chanctx_idx; +	const struct rtw89_chan *chan; +	unsigned int cnt = 0; +	u8 role_idx; + +	if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) +		return RTW89_MR_CTX_UNKNOWN; + +	for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { +		chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; +		if (chanctx_idx == RTW89_CHANCTX_IDLE) +			continue; + +		if (__test_and_set_bit(chanctx_idx, map)) +			continue; + +		chan = rtw89_chan_get(rtwdev, chanctx_idx); +		num[chan->band_type]++; +		cnt++; +	} + +	switch (cnt) { +	case 0: +		return RTW89_MR_CTX_NONE; +	case 1: +		if (num[RTW89_BAND_2G]) +			return RTW89_MR_CTX1_2GHZ; +		if (num[RTW89_BAND_5G]) +			return RTW89_MR_CTX1_5GHZ; +		if (num[RTW89_BAND_6G]) +			return RTW89_MR_CTX1_6GHZ; +		break; +	case 2: +		if (num[RTW89_BAND_2G] == 2) +			return RTW89_MR_CTX2_2GHZ; +		if (num[RTW89_BAND_5G] == 2) +			return RTW89_MR_CTX2_5GHZ; +		if (num[RTW89_BAND_6G] == 2) +			return RTW89_MR_CTX2_6GHZ; +		if (num[RTW89_BAND_2G] && num[RTW89_BAND_5G]) +			return RTW89_MR_CTX2_2GHZ_5GHZ; +		if (num[RTW89_BAND_2G] && num[RTW89_BAND_6G]) +			return RTW89_MR_CTX2_2GHZ_6GHZ; +		if (num[RTW89_BAND_5G] && num[RTW89_BAND_6G]) +			return RTW89_MR_CTX2_5GHZ_6GHZ; +		break; +	default: +		break; +	} + +	rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); +	return RTW89_MR_CTX_UNKNOWN; +} + +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, +				 struct rtw89_mr_chanctx_info *info) +{ +	lockdep_assert_wiphy(rtwdev->hw->wiphy); + +	info->wtype = __rtw89_query_mr_wtype(rtwdev); +	info->wmode = __rtw89_query_mr_wmode(rtwdev, inst_idx); +	info->ctxtype = __rtw89_query_mr_ctxtype(rtwdev, inst_idx); +} +  void rtw89_chanctx_track(struct rtw89_dev *rtwdev)  {  	struct rtw89_hal *hal = &rtwdev->hal;  	enum rtw89_entity_mode mode; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	if (hal->entity_pause)  		return; @@ -2507,22 +3129,22 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev)  }  void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, -			 enum rtw89_chanctx_pause_reasons rsn) +			 const struct rtw89_chanctx_pause_parm *pause_parm)  {  	struct rtw89_hal *hal = &rtwdev->hal;  	enum rtw89_entity_mode mode; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	if (hal->entity_pause)  		return; -	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", rsn); +	rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", pause_parm->rsn);  	mode = rtw89_get_entity_mode(rtwdev);  	switch (mode) {  	case RTW89_ENTITY_MODE_MCC: -		rtw89_mcc_stop(rtwdev); +		rtw89_mcc_stop(rtwdev, pause_parm);  		break;  	default:  		break; @@ -2555,7 +3177,7 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev,  	enum rtw89_entity_mode mode;  	int ret; -	lockdep_assert_held(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy);  	if (unlikely(!hal->entity_pause)) {  		rtw89_chanctx_proceed_cb(rtwdev, cb_parm); @@ -2670,10 +3292,9 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,  void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,  			      struct ieee80211_chanctx_conf *ctx)  { -	struct rtw89_hal *hal = &rtwdev->hal;  	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; -	clear_bit(cfg->idx, hal->entity_map); +	rtw89_config_entity_chandef(rtwdev, cfg->idx, NULL);  }  void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, @@ -2687,6 +3308,9 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,  		rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);  		rtw89_set_channel(rtwdev);  	} + +	if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) +		rtw89_chan_update_punctured(rtwdev, idx, &ctx->def);  }  int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, @@ -2698,11 +3322,15 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,  	struct rtw89_hal *hal = &rtwdev->hal;  	struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;  	struct rtw89_entity_weight w = {}; +	int ret;  	rtwvif_link->chanctx_idx = cfg->idx;  	rtwvif_link->chanctx_assigned = true;  	cfg->ref_count++; +	if (rtwdev->scanning) +		rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); +  	if (list_empty(&rtwvif->mgnt_entry))  		list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); @@ -2717,7 +3345,13 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,  	rtw89_swap_chanctx(rtwdev, cfg->idx, RTW89_CHANCTX_0);  out: -	return rtw89_set_channel(rtwdev); +	ret = rtw89_set_channel(rtwdev); +	if (ret) +		return ret; + +	rtw89_tas_reset(rtwdev, true); + +	return 0;  }  void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, @@ -2736,6 +3370,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,  	rtwvif_link->chanctx_assigned = false;  	cfg->ref_count--; +	if (rtwdev->scanning) +		rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); +  	if (!rtw89_vif_is_active_role(rtwvif))  		list_del_init(&rtwvif->mgnt_entry); @@ -2761,7 +3398,7 @@ out:  		cur = rtw89_get_entity_mode(rtwdev);  		switch (cur) {  		case RTW89_ENTITY_MODE_MCC: -			rtw89_mcc_stop(rtwdev); +			rtw89_mcc_stop(rtwdev, NULL);  			break;  		default:  			break; @@ -2787,3 +3424,37 @@ out:  		break;  	}  } + +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, +				   struct rtw89_vif_link *rtwvif_link, +				   struct ieee80211_chanctx_conf *old_ctx, +				   struct ieee80211_chanctx_conf *new_ctx, +				   bool replace) +{ +	int ret; + +	rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx); + +	if (!replace) +		goto assign; + +	rtw89_chanctx_ops_remove(rtwdev, old_ctx); +	ret = rtw89_chanctx_ops_add(rtwdev, new_ctx); +	if (ret) { +		rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n", +			  __func__, ret); +		return ret; +	} + +assign: +	ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx); +	if (ret) { +		rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n", +			  __func__, ret); +		return ret; +	} + +	_rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def); + +	return 0; +} | 
