diff options
Diffstat (limited to 'sys/contrib/dev/rtw89/mac80211.c')
| -rw-r--r-- | sys/contrib/dev/rtw89/mac80211.c | 420 | 
1 files changed, 219 insertions, 201 deletions
| diff --git a/sys/contrib/dev/rtw89/mac80211.c b/sys/contrib/dev/rtw89/mac80211.c index 3eb074c591cf..c1ca6d741b32 100644 --- a/sys/contrib/dev/rtw89/mac80211.c +++ b/sys/contrib/dev/rtw89/mac80211.c @@ -16,10 +16,6 @@  #include "util.h"  #include "wow.h" -#if defined(__FreeBSD__) -DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T)) -#endif -  static void rtw89_ops_tx(struct ieee80211_hw *hw,  			 struct ieee80211_tx_control *control,  			 struct sk_buff *skb) @@ -61,32 +57,30 @@ static void rtw89_ops_wake_tx_queue(struct ieee80211_hw *hw,  static int rtw89_ops_start(struct ieee80211_hw *hw)  {  	struct rtw89_dev *rtwdev = hw->priv; -	int ret; -	mutex_lock(&rtwdev->mutex); -	ret = rtw89_core_start(rtwdev); -	mutex_unlock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); -	return ret; +	return rtw89_core_start(rtwdev);  }  static void rtw89_ops_stop(struct ieee80211_hw *hw, bool suspend)  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_core_stop(rtwdev); -	mutex_unlock(&rtwdev->mutex);  } -static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) +static int rtw89_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)  {  	struct rtw89_dev *rtwdev = hw->priv; +	lockdep_assert_wiphy(hw->wiphy); +  	/* let previous ips work finish to ensure we don't leave ips twice */ -	cancel_work_sync(&rtwdev->ips_work); +	wiphy_work_cancel(hw->wiphy, &rtwdev->ips_work); -	mutex_lock(&rtwdev->mutex);  	rtw89_leave_ps_mode(rtwdev);  	if ((changed & IEEE80211_CONF_CHANGE_IDLE) && @@ -104,8 +98,6 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed)  	    !rtwdev->scanning)  		rtw89_enter_ips(rtwdev); -	mutex_unlock(&rtwdev->mutex); -  	return 0;  } @@ -119,14 +111,22 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,  	rtw89_vif_type_mapping(rtwvif_link, false); -	INIT_WORK(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); +	wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); +	wiphy_delayed_work_init(&rtwvif_link->csa_beacon_work, rtw89_core_csa_beacon_work); +	wiphy_delayed_work_init(&rtwvif_link->mcc_gc_detect_beacon_work, +				rtw89_mcc_gc_detect_beacon_work); +  	INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); +	rtw89_p2p_noa_once_init(rtwvif_link); +  	rtwvif_link->hit_rule = 0;  	rtwvif_link->bcn_hit_cond = 0;  	rtwvif_link->chanctx_assigned = false;  	rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;  	rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; +	rtwvif_link->rand_tsf_done = false; +	rtwvif_link->detect_bcn_count = 0;  	rcu_read_lock(); @@ -146,9 +146,14 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,  static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev,  					  struct rtw89_vif_link *rtwvif_link)  { -	mutex_unlock(&rtwdev->mutex); -	cancel_work_sync(&rtwvif_link->update_beacon_work); -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(rtwdev->hw->wiphy); + +	wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work); +	wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work); +	wiphy_delayed_work_cancel(rtwdev->hw->wiphy, +				  &rtwvif_link->mcc_gc_detect_beacon_work); + +	rtw89_p2p_noa_once_deinit(rtwvif_link);  	rtw89_leave_ps_mode(rtwdev); @@ -166,11 +171,11 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,  	u8 mac_id, port;  	int ret = 0; +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n",  		    vif->addr, vif->type, vif->p2p); -	mutex_lock(&rtwdev->mutex); -  	rtw89_leave_ips_by_hwflags(rtwdev);  	if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) @@ -178,10 +183,8 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,  				     IEEE80211_VIF_SUPPORTS_CQM_RSSI;  	mac_id = rtw89_acquire_mac_id(rtwdev); -	if (mac_id == RTW89_MAX_MAC_ID_NUM) { -		ret = -ENOSPC; -		goto err; -	} +	if (mac_id == RTW89_MAX_MAC_ID_NUM) +		return -ENOSPC;  	port = rtw89_core_acquire_bit_map(rtwdev->hw_port, RTW89_PORT_NUM);  	if (port == RTW89_PORT_NUM) { @@ -196,13 +199,14 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,  	if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) {  		list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);  		INIT_LIST_HEAD(&rtwvif->mgnt_entry); +		INIT_LIST_HEAD(&rtwvif->dlink_pool);  	}  	ether_addr_copy(rtwvif->mac_addr, vif->addr);  	rtwvif->offchan = false;  	rtwvif->roc.state = RTW89_ROC_IDLE; -	INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); +	wiphy_delayed_work_init(&rtwvif->roc.roc_work, rtw89_roc_work);  	rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); @@ -217,8 +221,6 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,  		goto unset_link;  	rtw89_recalc_lps(rtwdev); - -	mutex_unlock(&rtwdev->mutex);  	return 0;  unset_link: @@ -228,8 +230,6 @@ release_port:  	rtw89_core_release_bit_map(rtwdev->hw_port, port);  release_macid:  	rtw89_release_mac_id(rtwdev, mac_id); -err: -	mutex_unlock(&rtwdev->mutex);  	return ret;  } @@ -243,12 +243,12 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw,  	u8 port = rtw89_vif_get_main_port(rtwvif);  	struct rtw89_vif_link *rtwvif_link; +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n",  		    vif->addr, vif->type, vif->p2p); -	cancel_delayed_work_sync(&rtwvif->roc.roc_work); - -	mutex_lock(&rtwdev->mutex); +	wiphy_delayed_work_cancel(hw->wiphy, &rtwvif->roc.roc_work);  	rtwvif_link = rtwvif->links[RTW89_VIF_IDLE_LINK_ID];  	if (unlikely(!rtwvif_link)) { @@ -269,8 +269,6 @@ bottom:  	rtw89_recalc_lps(rtwdev);  	rtw89_enter_ips_by_hwflags(rtwdev); - -	mutex_unlock(&rtwdev->mutex);  }  static int rtw89_ops_change_interface(struct ieee80211_hw *hw, @@ -308,7 +306,8 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,  	const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;  	u32 rx_fltr; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_ps_mode(rtwdev);  	*new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | @@ -371,14 +370,11 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,  			   B_AX_RX_FLTR_CFG_MASK,  			   rx_fltr);  	if (!rtwdev->dbcc_en) -		goto out; +		return;  	rtw89_write32_mask(rtwdev,  			   rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1),  			   B_AX_RX_FLTR_CFG_MASK,  			   rx_fltr); - -out: -	mutex_unlock(&rtwdev->mutex);  }  static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { @@ -497,6 +493,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,  	int i;  	if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { +		rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; +  		/* for station mode, assign the mac_id from itself */  		macid = rtw89_vif_get_main_macid(rtwvif);  	} else { @@ -512,6 +510,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,  	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)  		rtw89_core_txq_init(rtwdev, sta->txq[i]); +	INIT_LIST_HEAD(&rtwsta->dlink_pool); +  	skb_queue_head_init(&rtwsta->roc_queue);  	bitmap_zero(rtwsta->pairwise_sec_cam_map, RTW89_MAX_SEC_CAM_NUM); @@ -674,6 +674,7 @@ static void __rtw89_ops_bss_link_assoc(struct rtw89_dev *rtwdev,  	rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link);  	rtw89_mac_port_update(rtwdev, rtwvif_link);  	rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, rtwvif_link); +	rtw89_mac_set_he_tb(rtwdev, rtwvif_link);  }  static void __rtw89_ops_bss_assoc(struct rtw89_dev *rtwdev, @@ -693,7 +694,8 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_ps_mode(rtwdev);  	if (changed & BSS_CHANGED_ASSOC) { @@ -716,8 +718,6 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,  	if (changed & BSS_CHANGED_ARP_FILTER)  		rtwvif->ip_addr = vif->cfg.arp_addr_list[0]; - -	mutex_unlock(&rtwdev->mutex);  }  static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw, @@ -729,7 +729,8 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_ps_mode(rtwdev);  	rtwvif_link = rtwvif->links[conf->link_id]; @@ -737,7 +738,7 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, conf->link_id); -		goto out; +		return;  	}  	if (changed & BSS_CHANGED_BSSID) { @@ -767,9 +768,6 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,  	if (changed & BSS_CHANGED_TPE)  		rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true); - -out: -	mutex_unlock(&rtwdev->mutex);  }  static int rtw89_ops_start_ap(struct ieee80211_hw *hw, @@ -782,22 +780,19 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,  	const struct rtw89_chan *chan;  	int ret = 0; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtwvif_link = rtwvif->links[link_conf->link_id];  	if (unlikely(!rtwvif_link)) {  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, link_conf->link_id); -		ret = -ENOLINK; -		goto out; +		return -ENOLINK;  	}  	chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); -	if (chan->band_type == RTW89_BAND_6G) { -		mutex_unlock(&rtwdev->mutex); +	if (chan->band_type == RTW89_BAND_6G)  		return -EOPNOTSUPP; -	}  	if (rtwdev->scanning)  		rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); @@ -814,15 +809,12 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,  	if (RTW89_CHK_FW_FEATURE(NOTIFY_AP_INFO, &rtwdev->fw)) {  		ret = rtw89_fw_h2c_ap_info_refcount(rtwdev, true);  		if (ret) -			goto out; +			return ret;  	}  	rtw89_queue_chanctx_work(rtwdev); -out: -	mutex_unlock(&rtwdev->mutex); - -	return ret; +	return 0;  }  static @@ -833,14 +825,14 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtwvif_link = rtwvif->links[link_conf->link_id];  	if (unlikely(!rtwvif_link)) {  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, link_conf->link_id); -		goto out; +		return;  	}  	if (RTW89_CHK_FW_FEATURE(NOTIFY_AP_INFO, &rtwdev->fw)) @@ -849,22 +841,18 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	rtw89_mac_stop_ap(rtwdev, rtwvif_link);  	rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL);  	rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); - -out: -	mutex_unlock(&rtwdev->mutex);  }  static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,  			     bool set)  { -	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);  	struct rtw89_vif *rtwvif = rtwsta->rtwvif;  	struct rtw89_vif_link *rtwvif_link;  	unsigned int link_id;  	rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) -		ieee80211_queue_work(rtwdev->hw, &rtwvif_link->update_beacon_work); +		wiphy_work_queue(hw->wiphy, &rtwvif_link->update_beacon_work);  	return 0;  } @@ -877,9 +865,9 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw,  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	int ret = 0; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_ps_mode(rtwdev);  	rtwvif_link = rtwvif->links[link_id]; @@ -887,17 +875,13 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw,  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, link_id); -		ret = -ENOLINK; -		goto out; +		return -ENOLINK;  	}  	rtwvif_link->tx_params[ac] = *params;  	__rtw89_conf_tx(rtwdev, rtwvif_link, ac); -out: -	mutex_unlock(&rtwdev->mutex); - -	return ret; +	return 0;  }  static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, @@ -941,14 +925,11 @@ static int rtw89_ops_sta_state(struct ieee80211_hw *hw,  			       enum ieee80211_sta_state new_state)  {  	struct rtw89_dev *rtwdev = hw->priv; -	int ret; -	mutex_lock(&rtwdev->mutex); -	rtw89_leave_ps_mode(rtwdev); -	ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); -	mutex_unlock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); -	return ret; +	rtw89_leave_ps_mode(rtwdev); +	return __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state);  }  static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -957,9 +938,10 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  			     struct ieee80211_key_conf *key)  {  	struct rtw89_dev *rtwdev = hw->priv; -	int ret = 0; +	int ret; + +	lockdep_assert_wiphy(hw->wiphy); -	mutex_lock(&rtwdev->mutex);  	rtw89_leave_ps_mode(rtwdev);  	switch (cmd) { @@ -968,7 +950,7 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		ret = rtw89_cam_sec_key_add(rtwdev, vif, sta, key);  		if (ret && ret != -EOPNOTSUPP) {  			rtw89_err(rtwdev, "failed to add key to sec cam\n"); -			goto out; +			return ret;  		}  		break;  	case DISABLE_KEY: @@ -978,14 +960,11 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, true);  		if (ret) {  			rtw89_err(rtwdev, "failed to remove key from sec cam\n"); -			goto out; +			return ret;  		}  		break;  	} -out: -	mutex_unlock(&rtwdev->mutex); -  	return ret;  } @@ -1001,38 +980,32 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,  	struct ieee80211_txq *txq = sta->txq[tid];  	struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; +	lockdep_assert_wiphy(rtwdev->hw->wiphy); +  	switch (params->action) {  	case IEEE80211_AMPDU_TX_START:  		return IEEE80211_AMPDU_TX_START_IMMEDIATE;  	case IEEE80211_AMPDU_TX_STOP_CONT:  	case IEEE80211_AMPDU_TX_STOP_FLUSH:  	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: -		mutex_lock(&rtwdev->mutex);  		clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags);  		clear_bit(tid, rtwsta->ampdu_map);  		rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); -		mutex_unlock(&rtwdev->mutex);  		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);  		break;  	case IEEE80211_AMPDU_TX_OPERATIONAL: -		mutex_lock(&rtwdev->mutex);  		set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags);  		rtwsta->ampdu_params[tid].agg_num = params->buf_size;  		rtwsta->ampdu_params[tid].amsdu = params->amsdu;  		set_bit(tid, rtwsta->ampdu_map);  		rtw89_leave_ps_mode(rtwdev);  		rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); -		mutex_unlock(&rtwdev->mutex);  		break;  	case IEEE80211_AMPDU_RX_START: -		mutex_lock(&rtwdev->mutex);  		rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, true, params); -		mutex_unlock(&rtwdev->mutex);  		break;  	case IEEE80211_AMPDU_RX_STOP: -		mutex_lock(&rtwdev->mutex);  		rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, false, params); -		mutex_unlock(&rtwdev->mutex);  		break;  	default:  		WARN_ON(1); @@ -1042,15 +1015,16 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,  	return 0;  } -static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, +				       u32 value)  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_ps_mode(rtwdev);  	if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags))  		rtw89_mac_update_rts_threshold(rtwdev); -	mutex_unlock(&rtwdev->mutex);  	return 0;  } @@ -1063,7 +1037,7 @@ static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw,  	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);  	struct rtw89_sta_link *rtwsta_link; -	rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); +	rtwsta_link = rtw89_get_designated_link(rtwsta);  	if (unlikely(!rtwsta_link))  		return; @@ -1090,7 +1064,8 @@ static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_leave_lps(rtwdev);  	rtw89_hci_flush_queues(rtwdev, queues, drop); @@ -1098,8 +1073,6 @@ static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  		__rtw89_drop_packets(rtwdev, vif);  	else  		rtw89_mac_flush_txq(rtwdev, queues, drop); - -	mutex_unlock(&rtwdev->mutex);  }  struct rtw89_iter_bitrate_mask_data { @@ -1146,20 +1119,22 @@ static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw,  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_phy_rate_pattern_vif(rtwdev, vif, mask);  	rtw89_ra_mask_info_update(rtwdev, vif, mask); -	mutex_unlock(&rtwdev->mutex);  	return 0;  }  static -int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +int rtw89_ops_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant)  {  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_hal *hal = &rtwdev->hal; +	lockdep_assert_wiphy(hw->wiphy); +  	if (hal->ant_diversity) {  		if (tx_ant != rx_ant || hweight32(tx_ant) != 1)  			return -EINVAL; @@ -1167,18 +1142,17 @@ int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)  		return -EINVAL;  	} -	mutex_lock(&rtwdev->mutex);  	hal->antenna_tx = tx_ant;  	hal->antenna_rx = rx_ant;  	hal->tx_path_diversity = false;  	hal->ant_diversity_fixed = true; -	mutex_unlock(&rtwdev->mutex);  	return 0;  }  static -int rtw89_ops_get_antenna(struct ieee80211_hw *hw,  u32 *tx_ant, u32 *rx_ant) +int rtw89_ops_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, +			  u32 *rx_ant)  {  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_hal *hal = &rtwdev->hal; @@ -1197,18 +1171,17 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); -	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); +	rtwvif_link = rtw89_get_designated_link(rtwvif);  	if (unlikely(!rtwvif_link)) { -		rtw89_err(rtwdev, "sw scan start: find no link on HW-0\n"); -		goto out; +		rtw89_err(rtwdev, "sw scan start: find no designated link\n"); +		return;  	} -	rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false); +	rtw89_leave_lps(rtwdev); -out: -	mutex_unlock(&rtwdev->mutex); +	rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false);  }  static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, @@ -1218,18 +1191,15 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); -	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); +	rtwvif_link = rtw89_get_designated_link(rtwvif);  	if (unlikely(!rtwvif_link)) { -		rtw89_err(rtwdev, "sw scan complete: find no link on HW-0\n"); -		goto out; +		rtw89_err(rtwdev, "sw scan complete: find no designated link\n"); +		return;  	}  	rtw89_core_scan_complete(rtwdev, rtwvif_link, false); - -out: -	mutex_unlock(&rtwdev->mutex);  }  static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, @@ -1249,33 +1219,33 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	struct rtw89_vif_link *rtwvif_link;  	int ret; +	lockdep_assert_wiphy(hw->wiphy); +  	if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw))  		return 1; -	mutex_lock(&rtwdev->mutex); - -	if (rtwdev->scanning || rtwvif->offchan) { -		ret = -EBUSY; -		goto out; -	} +	if (rtwdev->scanning || rtwvif->offchan) +		return -EBUSY; -	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); +	rtwvif_link = rtw89_get_designated_link(rtwvif);  	if (unlikely(!rtwvif_link)) { -		rtw89_err(rtwdev, "hw scan: find no link on HW-0\n"); -		ret = -ENOLINK; -		goto out; +		rtw89_err(rtwdev, "hw scan: find no designated link\n"); +		return -ENOLINK;  	} -	rtw89_hw_scan_start(rtwdev, rtwvif_link, req); +	rtw89_leave_lps(rtwdev); +	rtw89_leave_ips_by_hwflags(rtwdev); + +	ret = rtw89_hw_scan_start(rtwdev, rtwvif_link, req); +	if (ret) +		return ret; +  	ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);  	if (ret) {  		rtw89_hw_scan_abort(rtwdev, rtwvif_link);  		rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret);  	} -out: -	mutex_unlock(&rtwdev->mutex); -  	return ret;  } @@ -1286,24 +1256,21 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; +	lockdep_assert_wiphy(hw->wiphy); +  	if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw))  		return; -	mutex_lock(&rtwdev->mutex); -  	if (!rtwdev->scanning) -		goto out; +		return; -	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); +	rtwvif_link = rtw89_get_designated_link(rtwvif);  	if (unlikely(!rtwvif_link)) { -		rtw89_err(rtwdev, "cancel hw scan: find no link on HW-0\n"); -		goto out; +		rtw89_err(rtwdev, "cancel hw scan: find no designated link\n"); +		return;  	}  	rtw89_hw_scan_abort(rtwdev, rtwvif_link); - -out: -	mutex_unlock(&rtwdev->mutex);  }  static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, @@ -1326,13 +1293,10 @@ static int rtw89_ops_add_chanctx(struct ieee80211_hw *hw,  				 struct ieee80211_chanctx_conf *ctx)  {  	struct rtw89_dev *rtwdev = hw->priv; -	int ret; -	mutex_lock(&rtwdev->mutex); -	ret = rtw89_chanctx_ops_add(rtwdev, ctx); -	mutex_unlock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); -	return ret; +	return rtw89_chanctx_ops_add(rtwdev, ctx);  }  static void rtw89_ops_remove_chanctx(struct ieee80211_hw *hw, @@ -1340,9 +1304,9 @@ static void rtw89_ops_remove_chanctx(struct ieee80211_hw *hw,  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_chanctx_ops_remove(rtwdev, ctx); -	mutex_unlock(&rtwdev->mutex);  }  static void rtw89_ops_change_chanctx(struct ieee80211_hw *hw, @@ -1351,9 +1315,9 @@ static void rtw89_ops_change_chanctx(struct ieee80211_hw *hw,  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	rtw89_chanctx_ops_change(rtwdev, ctx, changed); -	mutex_unlock(&rtwdev->mutex);  }  static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, @@ -1364,25 +1328,18 @@ static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw,  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	int ret; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtwvif_link = rtwvif->links[link_conf->link_id];  	if (unlikely(!rtwvif_link)) {  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, link_conf->link_id); -		ret = -ENOLINK; -		goto out; +		return -ENOLINK;  	} -	ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, ctx); - -out: -	mutex_unlock(&rtwdev->mutex); - -	return ret; +	return rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, ctx);  }  static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, @@ -1394,11 +1351,10 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);  	struct rtw89_vif_link *rtwvif_link; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtwvif_link = rtwvif->links[link_conf->link_id];  	if (unlikely(!rtwvif_link)) { -		mutex_unlock(&rtwdev->mutex);  		rtw89_err(rtwdev,  			  "%s: rtwvif link (link_id %u) is not active\n",  			  __func__, link_conf->link_id); @@ -1406,7 +1362,73 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw,  	}  	rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx); -	mutex_unlock(&rtwdev->mutex); +} + +static +int rtw89_ops_switch_vif_chanctx(struct ieee80211_hw *hw, +				 struct ieee80211_vif_chanctx_switch *vifs, +				 int n_vifs, +				 enum ieee80211_chanctx_switch_mode mode) +{ +	struct rtw89_dev *rtwdev = hw->priv; +	bool replace; +	int ret; +	int i; + +	lockdep_assert_wiphy(hw->wiphy); + +	switch (mode) { +	case CHANCTX_SWMODE_REASSIGN_VIF: +		replace = false; +		break; +	case CHANCTX_SWMODE_SWAP_CONTEXTS: +		replace = true; +		break; +	default: +		return -EOPNOTSUPP; +	} + +	for (i = 0; i < n_vifs; i++) { +		struct ieee80211_vif_chanctx_switch *p = &vifs[i]; +		struct ieee80211_bss_conf *link_conf = p->link_conf; +		struct rtw89_vif *rtwvif = vif_to_rtwvif(p->vif); +		struct rtw89_vif_link *rtwvif_link; + +		rtwvif_link = rtwvif->links[link_conf->link_id]; +		if (unlikely(!rtwvif_link)) { +			rtw89_err(rtwdev, +				  "%s: rtwvif link (link_id %u) is not active\n", +				  __func__, link_conf->link_id); +			return -ENOLINK; +		} + +		ret = rtw89_chanctx_ops_reassign_vif(rtwdev, rtwvif_link, +						     p->old_ctx, p->new_ctx, +						     replace); +		if (ret) +			return ret; +	} + +	return 0; +} + +static void rtw89_ops_channel_switch_beacon(struct ieee80211_hw *hw, +					    struct ieee80211_vif *vif, +					    struct cfg80211_chan_def *chandef) +{ +	struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); +	struct rtw89_dev *rtwdev = hw->priv; +	struct rtw89_vif_link *rtwvif_link; + +	BUILD_BUG_ON(RTW89_MLD_NON_STA_LINK_NUM != 1); + +	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); +	if (unlikely(!rtwvif_link)) { +		rtw89_err(rtwdev, "chsw bcn: find no link on HW-0\n"); +		return; +	} + +	wiphy_delayed_work_queue(hw->wiphy, &rtwvif_link->csa_beacon_work, 0);  }  static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, @@ -1419,13 +1441,12 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw,  	struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);  	struct rtw89_roc *roc = &rtwvif->roc; +	lockdep_assert_wiphy(hw->wiphy); +  	if (!rtwvif)  		return -EINVAL; -	mutex_lock(&rtwdev->mutex); -  	if (roc->state != RTW89_ROC_IDLE) { -		mutex_unlock(&rtwdev->mutex);  		return -EBUSY;  	} @@ -1443,8 +1464,6 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw,  	rtw89_roc_start(rtwdev, rtwvif); -	mutex_unlock(&rtwdev->mutex); -  	return 0;  } @@ -1454,14 +1473,14 @@ static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw,  	struct rtw89_dev *rtwdev = hw->priv;  	struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); +	lockdep_assert_wiphy(hw->wiphy); +  	if (!rtwvif)  		return -EINVAL; -	cancel_delayed_work_sync(&rtwvif->roc.roc_work); +	wiphy_delayed_work_cancel(hw->wiphy, &rtwvif->roc.roc_work); -	mutex_lock(&rtwdev->mutex);  	rtw89_roc_end(rtwdev, rtwvif); -	mutex_unlock(&rtwdev->mutex);  	return 0;  } @@ -1482,14 +1501,14 @@ static int rtw89_ops_set_tid_config(struct ieee80211_hw *hw,  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	if (sta)  		rtw89_core_set_tid_config(rtwdev, sta, tid_config);  	else  		ieee80211_iterate_stations_atomic(rtwdev->hw,  						  rtw89_set_tid_config_iter,  						  tid_config); -	mutex_unlock(&rtwdev->mutex);  	return 0;  } @@ -1513,7 +1532,7 @@ static bool rtw89_ops_can_activate_links(struct ieee80211_hw *hw,  {  	struct rtw89_dev *rtwdev = hw->priv; -	guard(mutex)(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	return rtw89_can_work_on_links(rtwdev, vif, active_links);  } @@ -1575,7 +1594,7 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw,  	int ret = 0;  	int i; -	guard(mutex)(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtw89_debug(rtwdev, RTW89_DBG_STATE,  		    "%s: old_links (0x%08x) -> new_links (0x%08x)\n", @@ -1724,7 +1743,7 @@ int rtw89_ops_change_sta_links(struct ieee80211_hw *hw,  	unsigned long set_links = new_links & ~old_links;  	int ret = 0; -	guard(mutex)(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	rtw89_debug(rtwdev, RTW89_DBG_STATE,  		    "%s: old_links (0x%08x) -> new_links (0x%08x)\n", @@ -1754,16 +1773,16 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw,  	struct rtw89_dev *rtwdev = hw->priv;  	int ret; -	set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); -	cancel_delayed_work_sync(&rtwdev->track_work); +	lockdep_assert_wiphy(hw->wiphy); -	mutex_lock(&rtwdev->mutex); -	ret = rtw89_wow_suspend(rtwdev, wowlan); -	mutex_unlock(&rtwdev->mutex); +	set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); +	wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work); +	wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_ps_work); +	ret = rtw89_wow_suspend(rtwdev, wowlan);  	if (ret) {  		rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); -		clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); +		clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags);  		return 1;  	} @@ -1775,15 +1794,17 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw)  	struct rtw89_dev *rtwdev = hw->priv;  	int ret; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy); +  	ret = rtw89_wow_resume(rtwdev);  	if (ret)  		rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); -	mutex_unlock(&rtwdev->mutex); -	clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); -	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, -				     RTW89_TRACK_WORK_PERIOD); +	clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); +	wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work, +				 RTW89_TRACK_WORK_PERIOD); +	wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_ps_work, +				 RTW89_TRACK_PS_WORK_PERIOD);  	return ret ? 1 : 0;  } @@ -1803,18 +1824,16 @@ static void rtw89_set_rekey_data(struct ieee80211_hw *hw,  	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;  	struct rtw89_wow_gtk_info *gtk_info = &rtw_wow->gtk_info; +	lockdep_assert_wiphy(hw->wiphy); +  	if (data->kek_len > sizeof(gtk_info->kek) ||  	    data->kck_len > sizeof(gtk_info->kck)) {  		rtw89_warn(rtwdev, "kek or kck length over fw limit\n");  		return;  	} -	mutex_lock(&rtwdev->mutex); -  	memcpy(gtk_info->kek, data->kek, data->kek_len);  	memcpy(gtk_info->kck, data->kck, data->kck_len); - -	mutex_unlock(&rtwdev->mutex);  }  #endif @@ -1822,16 +1841,13 @@ static void rtw89_ops_rfkill_poll(struct ieee80211_hw *hw)  {  	struct rtw89_dev *rtwdev = hw->priv; -	mutex_lock(&rtwdev->mutex); +	lockdep_assert_wiphy(hw->wiphy);  	/* wl_disable GPIO get floating when entering LPS */  	if (test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) -		goto out; +		return;  	rtw89_core_rfkill_poll(rtwdev, false); - -out: -	mutex_unlock(&rtwdev->mutex);  }  const struct ieee80211_ops rtw89_ops = { @@ -1869,6 +1885,8 @@ const struct ieee80211_ops rtw89_ops = {  	.change_chanctx		= rtw89_ops_change_chanctx,  	.assign_vif_chanctx	= rtw89_ops_assign_vif_chanctx,  	.unassign_vif_chanctx	= rtw89_ops_unassign_vif_chanctx, +	.switch_vif_chanctx	= rtw89_ops_switch_vif_chanctx, +	.channel_switch_beacon	= rtw89_ops_channel_switch_beacon,  	.remain_on_channel		= rtw89_ops_remain_on_channel,  	.cancel_remain_on_channel	= rtw89_ops_cancel_remain_on_channel,  	.set_sar_specs		= rtw89_ops_set_sar_specs, | 
