diff options
Diffstat (limited to 'sys/contrib/dev/mediatek/mt76/mt7996/mcu.c')
| -rw-r--r-- | sys/contrib/dev/mediatek/mt76/mt7996/mcu.c | 907 | 
1 files changed, 576 insertions, 331 deletions
| diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c index 381f9ff41d9a..5099aa2004b7 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c @@ -13,7 +13,7 @@  #define fw_name(_dev, name, ...)	({			\  	char *_fw;						\  	switch (mt76_chip(&(_dev)->mt76)) {			\ -	case 0x7992:						\ +	case MT7992_DEVICE_ID:						\  		switch ((_dev)->var.type) {			\  		case MT7992_VAR_TYPE_23:			\  			_fw = MT7992_##name##_23;		\ @@ -22,7 +22,10 @@  			_fw = MT7992_##name;			\  		}						\  		break;						\ -	case 0x7990:						\ +	case MT7990_DEVICE_ID:					\ +		_fw = MT7990_##name;				\ +		break;						\ +	case MT7996_DEVICE_ID:						\  	default:						\  		switch ((_dev)->var.type) {			\  		case MT7996_VAR_TYPE_233:			\ @@ -118,13 +121,13 @@ mt7996_mcu_get_sta_nss(u16 mcs_map)  }  static void -mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, -			  u16 mcs_map) +mt7996_mcu_set_sta_he_mcs(struct ieee80211_link_sta *link_sta, +			  struct mt7996_vif_link *link, +			  __le16 *he_mcs, u16 mcs_map)  { -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; -	enum nl80211_band band = msta->vif->deflink.phy->mt76->chandef.chan->band; -	const u16 *mask = msta->vif->deflink.bitrate_mask.control[band].he_mcs; -	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; +	int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss; +	enum nl80211_band band = link->phy->mt76->chandef.chan->band; +	const u16 *mask = link->bitrate_mask.control[band].he_mcs;  	for (nss = 0; nss < max_nss; nss++) {  		int mcs; @@ -167,11 +170,11 @@ mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,  }  static void -mt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, -			   const u16 *mask) +mt7996_mcu_set_sta_vht_mcs(struct ieee80211_link_sta *link_sta, +			   __le16 *vht_mcs, const u16 *mask)  { -	u16 mcs, mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); -	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; +	u16 mcs, mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map); +	int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss;  	for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {  		switch (mcs_map & 0x3) { @@ -193,13 +196,13 @@ mt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,  }  static void -mt7996_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, -			  const u8 *mask) +mt7996_mcu_set_sta_ht_mcs(struct ieee80211_link_sta *link_sta, +			  u8 *ht_mcs, const u8 *mask)  { -	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; +	int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss;  	for (nss = 0; nss < max_nss; nss++) -		ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss]; +		ht_mcs[nss] = link_sta->ht_cap.mcs.rx_mask[nss] & mask[nss];  }  static int @@ -265,7 +268,7 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,  	txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);  	txd = (__le32 *)skb_push(skb, txd_len); -	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) +	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state) && mt7996_has_wa(dev))  		qid = MT_MCUQ_WA;  	else  		qid = MT_MCUQ_WM; @@ -335,8 +338,12 @@ exit:  int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)  {  	struct { +		u8 _rsv[4]; + +		__le16 tag; +		__le16 len;  		__le32 args[3]; -	} req = { +	} __packed req = {  		.args = {  			cpu_to_le32(a1),  			cpu_to_le32(a2), @@ -344,7 +351,16 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)  		},  	}; -	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false); +	if (mt7996_has_wa(dev)) +		return mt76_mcu_send_msg(&dev->mt76, cmd, &req.args, +					 sizeof(req.args), false); + +	req.tag = cpu_to_le16(cmd == MCU_WA_PARAM_CMD(QUERY) ? UNI_CMD_SDO_QUERY : +							       UNI_CMD_SDO_SET); +	req.len = cpu_to_le16(sizeof(req) - 4); + +	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO), &req, +				 sizeof(req), false);  }  static void @@ -364,21 +380,27 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)  	r = (struct mt7996_mcu_rdd_report *)skb->data; -	if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys)) -		return; - -	if (r->band_idx == MT_RX_SEL2 && !dev->rdd2_phy) -		return; - -	if (r->band_idx == MT_RX_SEL2) +	switch (r->rdd_idx) { +	case MT_RDD_IDX_BAND2: +		mphy = dev->mt76.phys[MT_BAND2]; +		break; +	case MT_RDD_IDX_BAND1: +		mphy = dev->mt76.phys[MT_BAND1]; +		break; +	case MT_RDD_IDX_BACKGROUND: +		if (!dev->rdd2_phy) +			return;  		mphy = dev->rdd2_phy->mt76; -	else -		mphy = dev->mt76.phys[r->band_idx]; +		break; +	default: +		dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); +		return; +	}  	if (!mphy)  		return; -	if (r->band_idx == MT_RX_SEL2) +	if (r->rdd_idx == MT_RDD_IDX_BACKGROUND)  		cfg80211_background_radar_event(mphy->hw->wiphy,  						&dev->rdd2_chandef,  						GFP_ATOMIC); @@ -548,7 +570,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)  		switch (le16_to_cpu(res->tag)) {  		case UNI_ALL_STA_TXRX_RATE:  			wlan_idx = le16_to_cpu(res->rate[i].wlan_idx); -			wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); +			wcid = mt76_wcid_ptr(dev, wlan_idx);  			if (!wcid)  				break; @@ -558,7 +580,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)  			break;  		case UNI_ALL_STA_TXRX_ADM_STAT:  			wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx); -			wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); +			wcid = mt76_wcid_ptr(dev, wlan_idx);  			if (!wcid)  				break; @@ -572,7 +594,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)  			break;  		case UNI_ALL_STA_TXRX_MSDU_COUNT:  			wlan_idx = le16_to_cpu(res->msdu_cnt[i].wlan_idx); -			wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); +			wcid = mt76_wcid_ptr(dev, wlan_idx);  			if (!wcid)  				break; @@ -669,10 +691,7 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)  			e = (void *)skb->data;  			idx = le16_to_cpu(e->wlan_id); -			if (idx >= ARRAY_SIZE(dev->mt76.wcid)) -				break; - -			wcid = rcu_dereference(dev->mt76.wcid[idx]); +			wcid = mt76_wcid_ptr(dev, idx);  			if (!wcid || !wcid->sta)  				break; @@ -1079,7 +1098,8 @@ __mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int  int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,  			    struct ieee80211_bss_conf *link_conf, -			    struct mt76_vif_link *mlink, int enable) +			    struct mt76_vif_link *mlink, +			    struct mt7996_sta_link *msta_link, int enable)  {  	struct mt7996_dev *dev = phy->dev;  	struct sk_buff *skb; @@ -1096,7 +1116,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,  	/* bss_basic must be first */  	mt7996_mcu_bss_basic_tlv(skb, vif, link_conf, mlink, phy->mt76, -				 mlink->wcid->idx, enable); +				 msta_link->wcid.idx, enable);  	mt7996_mcu_bss_sec_tlv(skb, mlink);  	if (vif->type == NL80211_IFTYPE_MONITOR) @@ -1174,37 +1194,34 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,  /** starec & wtbl **/  int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,  			 struct ieee80211_ampdu_params *params, -			 bool enable) +			 struct mt7996_vif_link *link, +			 struct mt7996_sta_link *msta_link, bool enable)  { -	struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; -	struct mt7996_vif *mvif = msta->vif; -  	if (enable && !params->amsdu) -		msta->wcid.amsdu = false; +		msta_link->wcid.amsdu = false; -	return mt7996_mcu_sta_ba(dev, &mvif->deflink.mt76, params, enable, true); +	return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, true);  }  int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,  			 struct ieee80211_ampdu_params *params, -			 bool enable) +			 struct mt7996_vif_link *link, bool enable)  { -	struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; -	struct mt7996_vif *mvif = msta->vif; - -	return mt7996_mcu_sta_ba(dev, &mvif->deflink.mt76, params, enable, false); +	return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, false);  }  static void -mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7996_mcu_sta_he_tlv(struct sk_buff *skb, +		      struct ieee80211_link_sta *link_sta, +		      struct mt7996_vif_link *link)  { -	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; +	struct ieee80211_he_cap_elem *elem = &link_sta->he_cap.he_cap_elem;  	struct ieee80211_he_mcs_nss_supp mcs_map;  	struct sta_rec_he_v2 *he;  	struct tlv *tlv;  	int i = 0; -	if (!sta->deflink.he_cap.has_he) +	if (!link_sta->he_cap.has_he)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he)); @@ -1216,21 +1233,21 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)  		he->he_phy_cap[i] = elem->phy_cap_info[i];  	} -	mcs_map = sta->deflink.he_cap.he_mcs_nss_supp; -	switch (sta->deflink.bandwidth) { +	mcs_map = link_sta->he_cap.he_mcs_nss_supp; +	switch (link_sta->bandwidth) {  	case IEEE80211_STA_RX_BW_160:  		if (elem->phy_cap_info[0] &  		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) -			mt7996_mcu_set_sta_he_mcs(sta, +			mt7996_mcu_set_sta_he_mcs(link_sta, link,  						  &he->max_nss_mcs[CMD_HE_MCS_BW8080],  						  le16_to_cpu(mcs_map.rx_mcs_80p80)); -		mt7996_mcu_set_sta_he_mcs(sta, +		mt7996_mcu_set_sta_he_mcs(link_sta, link,  					  &he->max_nss_mcs[CMD_HE_MCS_BW160],  					  le16_to_cpu(mcs_map.rx_mcs_160));  		fallthrough;  	default: -		mt7996_mcu_set_sta_he_mcs(sta, +		mt7996_mcu_set_sta_he_mcs(link_sta, link,  					  &he->max_nss_mcs[CMD_HE_MCS_BW80],  					  le16_to_cpu(mcs_map.rx_mcs_80));  		break; @@ -1240,24 +1257,26 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)  }  static void -mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, +			 struct ieee80211_link_sta *link_sta)  {  	struct sta_rec_he_6g_capa *he_6g;  	struct tlv *tlv; -	if (!sta->deflink.he_6ghz_capa.capa) +	if (!link_sta->he_6ghz_capa.capa)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g));  	he_6g = (struct sta_rec_he_6g_capa *)tlv; -	he_6g->capa = sta->deflink.he_6ghz_capa.capa; +	he_6g->capa = link_sta->he_6ghz_capa.capa;  }  static void -mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, +		       struct ieee80211_link_sta *link_sta)  { -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;  	struct ieee80211_vif *vif = container_of((void *)msta->vif,  						 struct ieee80211_vif, drv_priv);  	struct ieee80211_eht_mcs_nss_supp *mcs_map; @@ -1265,11 +1284,11 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)  	struct sta_rec_eht *eht;  	struct tlv *tlv; -	if (!sta->deflink.eht_cap.has_eht) +	if (!link_sta->eht_cap.has_eht)  		return; -	mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp; -	elem = &sta->deflink.eht_cap.eht_cap_elem; +	mcs_map = &link_sta->eht_cap.eht_mcs_nss_supp; +	elem = &link_sta->eht_cap.eht_cap_elem;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht)); @@ -1280,7 +1299,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)  	eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);  	if (vif->type != NL80211_IFTYPE_STATION && -	    (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & +	    (link_sta->he_cap.he_cap_elem.phy_cap_info[0] &  	     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |  	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |  	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | @@ -1296,47 +1315,48 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)  }  static void -mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)  {  	struct sta_rec_ht_uni *ht;  	struct tlv *tlv; -	if (!sta->deflink.ht_cap.ht_supported) +	if (!link_sta->ht_cap.ht_supported)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));  	ht = (struct sta_rec_ht_uni *)tlv; -	ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); -	ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor, +	ht->ht_cap = cpu_to_le16(link_sta->ht_cap.cap); +	ht->ampdu_param = u8_encode_bits(link_sta->ht_cap.ampdu_factor,  					 IEEE80211_HT_AMPDU_PARM_FACTOR) | -			  u8_encode_bits(sta->deflink.ht_cap.ampdu_density, +			  u8_encode_bits(link_sta->ht_cap.ampdu_density,  					 IEEE80211_HT_AMPDU_PARM_DENSITY);  }  static void -mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)  {  	struct sta_rec_vht *vht;  	struct tlv *tlv;  	/* For 6G band, this tlv is necessary to let hw work normally */ -	if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported) +	if (!link_sta->he_6ghz_capa.capa && !link_sta->vht_cap.vht_supported)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));  	vht = (struct sta_rec_vht *)tlv; -	vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); -	vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; -	vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; +	vht->vht_cap = cpu_to_le32(link_sta->vht_cap.cap); +	vht->vht_rx_mcs_map = link_sta->vht_cap.vht_mcs.rx_mcs_map; +	vht->vht_tx_mcs_map = link_sta->vht_cap.vht_mcs.tx_mcs_map;  }  static void  mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb, -			 struct ieee80211_vif *vif, struct ieee80211_sta *sta) +			 struct ieee80211_vif *vif, +			 struct ieee80211_link_sta *link_sta, +			 struct mt7996_sta_link *msta_link)  { -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;  	struct sta_rec_amsdu *amsdu;  	struct tlv *tlv; @@ -1345,16 +1365,16 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  	    vif->type != NL80211_IFTYPE_AP)  		return; -	if (!sta->deflink.agg.max_amsdu_len) +	if (!link_sta->agg.max_amsdu_len)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));  	amsdu = (struct sta_rec_amsdu *)tlv;  	amsdu->max_amsdu_num = 8;  	amsdu->amsdu_en = true; -	msta->wcid.amsdu = true; +	msta_link->wcid.amsdu = true; -	switch (sta->deflink.agg.max_amsdu_len) { +	switch (link_sta->agg.max_amsdu_len) {  	case IEEE80211_MAX_MPDU_LEN_VHT_11454:  		amsdu->max_mpdu_size =  			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; @@ -1371,30 +1391,31 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  static void  mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb, -			struct ieee80211_vif *vif, struct ieee80211_sta *sta) +			struct ieee80211_bss_conf *link_conf, +			struct ieee80211_link_sta *link_sta)  { -	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; +	struct ieee80211_he_cap_elem *elem = &link_sta->he_cap.he_cap_elem;  	struct sta_rec_muru *muru;  	struct tlv *tlv; -	if (vif->type != NL80211_IFTYPE_STATION && -	    vif->type != NL80211_IFTYPE_AP) +	if (link_conf->vif->type != NL80211_IFTYPE_STATION && +	    link_conf->vif->type != NL80211_IFTYPE_AP)  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));  	muru = (struct sta_rec_muru *)tlv; -	muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer || -			       vif->bss_conf.he_mu_beamformer || -			       vif->bss_conf.vht_mu_beamformer || -			       vif->bss_conf.vht_mu_beamformee; +	muru->cfg.mimo_dl_en = link_conf->eht_mu_beamformer || +			       link_conf->he_mu_beamformer || +			       link_conf->vht_mu_beamformer || +			       link_conf->vht_mu_beamformee;  	muru->cfg.ofdma_dl_en = true; -	if (sta->deflink.vht_cap.vht_supported) +	if (link_sta->vht_cap.vht_supported)  		muru->mimo_dl.vht_mu_bfee = -			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); +			!!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); -	if (!sta->deflink.he_cap.has_he) +	if (!link_sta->he_cap.has_he)  		return;  	muru->mimo_dl.partial_bw_dl_mimo = @@ -1425,49 +1446,50 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  }  static inline bool -mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif, -			struct ieee80211_sta *sta, bool bfee) +mt7996_is_ebf_supported(struct mt7996_phy *phy, +			struct ieee80211_bss_conf *link_conf, +			struct ieee80211_link_sta *link_sta, bool bfee)  {  	int sts = hweight16(phy->mt76->chainmask); -	if (vif->type != NL80211_IFTYPE_STATION && -	    vif->type != NL80211_IFTYPE_AP) +	if (link_conf->vif->type != NL80211_IFTYPE_STATION && +	    link_conf->vif->type != NL80211_IFTYPE_AP)  		return false;  	if (!bfee && sts < 2)  		return false; -	if (sta->deflink.eht_cap.has_eht) { -		struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap; +	if (link_sta->eht_cap.has_eht) { +		struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap;  		struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;  		if (bfee) -			return vif->bss_conf.eht_su_beamformee && +			return link_conf->eht_su_beamformee &&  			       EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);  		else -			return vif->bss_conf.eht_su_beamformer && +			return link_conf->eht_su_beamformer &&  			       EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);  	} -	if (sta->deflink.he_cap.has_he) { -		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; +	if (link_sta->he_cap.has_he) { +		struct ieee80211_he_cap_elem *pe = &link_sta->he_cap.he_cap_elem;  		if (bfee) -			return vif->bss_conf.he_su_beamformee && +			return link_conf->he_su_beamformee &&  			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);  		else -			return vif->bss_conf.he_su_beamformer && +			return link_conf->he_su_beamformer &&  			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);  	} -	if (sta->deflink.vht_cap.vht_supported) { -		u32 cap = sta->deflink.vht_cap.cap; +	if (link_sta->vht_cap.vht_supported) { +		u32 cap = link_sta->vht_cap.cap;  		if (bfee) -			return vif->bss_conf.vht_su_beamformee && +			return link_conf->vht_su_beamformee &&  			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);  		else -			return vif->bss_conf.vht_su_beamformer && +			return link_conf->vht_su_beamformer &&  			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);  	} @@ -1488,10 +1510,11 @@ mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf, struct mt7996_phy *phy)  }  static void -mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy, -		       struct sta_rec_bf *bf, bool explicit) +mt7996_mcu_sta_bfer_ht(struct ieee80211_link_sta *link_sta, +		       struct mt7996_phy *phy, struct sta_rec_bf *bf, +		       bool explicit)  { -	struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs; +	struct ieee80211_mcs_info *mcs = &link_sta->ht_cap.mcs;  	u8 n = 0;  	bf->tx_mode = MT_PHY_TYPE_HT; @@ -1514,10 +1537,11 @@ mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,  }  static void -mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy, -			struct sta_rec_bf *bf, bool explicit) +mt7996_mcu_sta_bfer_vht(struct ieee80211_link_sta *link_sta, +			struct mt7996_phy *phy, struct sta_rec_bf *bf, +			bool explicit)  { -	struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; +	struct ieee80211_sta_vht_cap *pc = &link_sta->vht_cap;  	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;  	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);  	u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); @@ -1538,24 +1562,24 @@ mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,  		bf->ncol = min_t(u8, nss_mcs, bf->nrow);  		bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, bf->ncol); -		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) +		if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160)  			bf->nrow = 1;  	} else {  		bf->nrow = tx_ant;  		bf->ncol = min_t(u8, nss_mcs, bf->nrow);  		bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); -		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) +		if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160)  			bf->ibf_nrow = 1;  	}  }  static void -mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, -		       struct mt7996_phy *phy, struct sta_rec_bf *bf, -		       bool explicit) +mt7996_mcu_sta_bfer_he(struct ieee80211_link_sta *link_sta, +		       struct ieee80211_vif *vif, struct mt7996_phy *phy, +		       struct sta_rec_bf *bf, bool explicit)  { -	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap; +	struct ieee80211_sta_he_cap *pc = &link_sta->he_cap;  	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;  	const struct ieee80211_sta_he_cap *vc =  		mt76_connac_get_he_phy_cap(phy->mt76, vif); @@ -1584,7 +1608,7 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,  	bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :  				  min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); -	if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160) +	if (link_sta->bandwidth != IEEE80211_STA_RX_BW_160)  		return;  	/* go over for 160MHz and 80p80 */ @@ -1616,11 +1640,11 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,  }  static void -mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif, -			struct mt7996_phy *phy, struct sta_rec_bf *bf, -			bool explicit) +mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta, +			struct ieee80211_vif *vif, struct mt7996_phy *phy, +			struct sta_rec_bf *bf, bool explicit)  { -	struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap; +	struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap;  	struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;  	struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;  	const struct ieee80211_sta_eht_cap *vc = @@ -1644,10 +1668,10 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,  	bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :  				  min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); -	if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160) +	if (link_sta->bandwidth < IEEE80211_STA_RX_BW_160)  		return; -	switch (sta->deflink.bandwidth) { +	switch (link_sta->bandwidth) {  	case IEEE80211_STA_RX_BW_160:  		snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]);  		sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]); @@ -1675,13 +1699,15 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,  static void  mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, -			struct ieee80211_vif *vif, struct ieee80211_sta *sta) +			struct ieee80211_bss_conf *link_conf, +			struct ieee80211_link_sta *link_sta, +			struct mt7996_vif_link *link)  {  #define EBF_MODE	BIT(0)  #define IBF_MODE	BIT(1)  #define BF_MAT_ORDER	4 -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_phy *phy = mvif->deflink.phy; +	struct ieee80211_vif *vif = link_conf->vif; +	struct mt7996_phy *phy = link->phy;  	int tx_ant = hweight16(phy->mt76->chainmask) - 1;  	struct sta_rec_bf *bf;  	struct tlv *tlv; @@ -1693,10 +1719,10 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  	};  	bool ebf; -	if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) +	if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))  		return; -	ebf = mt7996_is_ebf_supported(phy, vif, sta, false); +	ebf = mt7996_is_ebf_supported(phy, link_conf, link_sta, false);  	if (!ebf && !dev->ibf)  		return; @@ -1707,28 +1733,29 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  	 * vht: support eBF and iBF  	 * ht: iBF only, since mac80211 lacks of eBF support  	 */ -	if (sta->deflink.eht_cap.has_eht) -		mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf, ebf); -	else if (sta->deflink.he_cap.has_he) -		mt7996_mcu_sta_bfer_he(sta, vif, phy, bf, ebf); -	else if (sta->deflink.vht_cap.vht_supported) -		mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf); -	else if (sta->deflink.ht_cap.ht_supported) -		mt7996_mcu_sta_bfer_ht(sta, phy, bf, ebf); +	if (link_sta->eht_cap.has_eht) +		mt7996_mcu_sta_bfer_eht(link_sta, vif, link->phy, bf, ebf); +	else if (link_sta->he_cap.has_he) +		mt7996_mcu_sta_bfer_he(link_sta, vif, link->phy, bf, ebf); +	else if (link_sta->vht_cap.vht_supported) +		mt7996_mcu_sta_bfer_vht(link_sta, link->phy, bf, ebf); +	else if (link_sta->ht_cap.ht_supported) +		mt7996_mcu_sta_bfer_ht(link_sta, link->phy, bf, ebf);  	else  		return;  	bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0);  	if (is_mt7992(&dev->mt76) && tx_ant == 4)  		bf->bf_cap |= IBF_MODE; -	bf->bw = sta->deflink.bandwidth; -	bf->ibf_dbw = sta->deflink.bandwidth; + +	bf->bw = link_sta->bandwidth; +	bf->ibf_dbw = link_sta->bandwidth;  	bf->ibf_nrow = tx_ant; -	if (sta->deflink.eht_cap.has_eht || sta->deflink.he_cap.has_he) +	if (link_sta->eht_cap.has_eht || link_sta->he_cap.has_he)  		bf->ibf_timeout = is_mt7996(&dev->mt76) ? MT7996_IBF_TIMEOUT :  							  MT7992_IBF_TIMEOUT; -	else if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) +	else if (!ebf && link_sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)  		bf->ibf_timeout = MT7996_IBF_TIMEOUT_LEGACY;  	else  		bf->ibf_timeout = MT7996_IBF_TIMEOUT; @@ -1742,7 +1769,7 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  				      matrix[bf->nrow][bf->ncol] : 0;  	} -	switch (sta->deflink.bandwidth) { +	switch (link_sta->bandwidth) {  	case IEEE80211_STA_RX_BW_160:  	case IEEE80211_STA_RX_BW_80:  		bf->mem_total = bf->mem_20m * 2; @@ -1758,31 +1785,32 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,  static void  mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, -			struct ieee80211_vif *vif, struct ieee80211_sta *sta) +			struct ieee80211_bss_conf *link_conf, +			struct ieee80211_link_sta *link_sta, +			struct mt7996_vif_link *link)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_phy *phy = mvif->deflink.phy; +	struct mt7996_phy *phy = link->phy;  	int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;  	struct sta_rec_bfee *bfee;  	struct tlv *tlv;  	u8 nrow = 0; -	if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he)) +	if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he))  		return; -	if (!mt7996_is_ebf_supported(phy, vif, sta, true)) +	if (!mt7996_is_ebf_supported(phy, link_conf, link_sta, true))  		return;  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));  	bfee = (struct sta_rec_bfee *)tlv; -	if (sta->deflink.he_cap.has_he) { -		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; +	if (link_sta->he_cap.has_he) { +		struct ieee80211_he_cap_elem *pe = &link_sta->he_cap.he_cap_elem;  		nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,  			      pe->phy_cap_info[5]); -	} else if (sta->deflink.vht_cap.vht_supported) { -		struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; +	} else if (link_sta->vht_cap.vht_supported) { +		struct ieee80211_sta_vht_cap *pc = &link_sta->vht_cap;  		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,  				 pc->cap); @@ -1866,8 +1894,8 @@ mt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)  int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,  				   void *data, u16 version)  { +	struct uni_header hdr = {};  	struct ra_fixed_rate *req; -	struct uni_header hdr;  	struct sk_buff *skb;  	struct tlv *tlv;  	int len; @@ -1889,21 +1917,35 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,  				     MCU_WM_UNI_CMD(RA), true);  } -int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, -			       struct ieee80211_sta *sta, void *data, u32 field) +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, +			       void *data, u8 link_id, u32 field)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; -	struct sta_phy_uni *phy = data; +	struct mt7996_vif *mvif = msta->vif; +	struct mt7996_sta_link *msta_link;  	struct sta_rec_ra_fixed_uni *ra; +	struct sta_phy_uni *phy = data; +	struct mt76_vif_link *mlink;  	struct sk_buff *skb; +	int err = -ENODEV;  	struct tlv *tlv; -	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, -					      &msta->wcid, +	rcu_read_lock(); + +	mlink = rcu_dereference(mvif->mt76.link[link_id]); +	if (!mlink) +		goto error_unlock; + +	msta_link = rcu_dereference(msta->link[link_id]); +	if (!msta_link) +		goto error_unlock; + +	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink, +					      &msta_link->wcid,  					      MT7996_STA_UPDATE_MAX_SIZE); -	if (IS_ERR(skb)) -		return PTR_ERR(skb); +	if (IS_ERR(skb)) { +		err = PTR_ERR(skb); +		goto error_unlock; +	}  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));  	ra = (struct sta_rec_ra_fixed_uni *)tlv; @@ -1918,131 +1960,179 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif  		if (phy)  			ra->phy = *phy;  		break; -	case RATE_PARAM_MMPS_UPDATE: -		ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); +	case RATE_PARAM_MMPS_UPDATE: { +		struct ieee80211_sta *sta = wcid_to_sta(&msta_link->wcid); +		struct ieee80211_link_sta *link_sta; + +		link_sta = rcu_dereference(sta->link[link_id]); +		if (!link_sta) { +			dev_kfree_skb(skb); +			goto error_unlock; +		} + +		ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);  		break; +	}  	default:  		break;  	}  	ra->field = cpu_to_le32(field); +	rcu_read_unlock(); +  	return mt76_mcu_skb_send_msg(&dev->mt76, skb,  				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +error_unlock: +	rcu_read_unlock(); + +	return err;  }  static int -mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif, -			       struct ieee80211_sta *sta) +mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta, +			       struct ieee80211_vif *vif, u8 link_id)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct cfg80211_chan_def *chandef = &mvif->deflink.phy->mt76->chandef; -	struct cfg80211_bitrate_mask *mask = &mvif->deflink.bitrate_mask; -	enum nl80211_band band = chandef->chan->band; +	struct ieee80211_link_sta *link_sta; +	struct cfg80211_bitrate_mask mask; +	struct mt7996_sta_link *msta_link; +	struct mt7996_vif_link *link;  	struct sta_phy_uni phy = {}; -	int ret, nrates = 0; +	struct ieee80211_sta *sta; +	int ret, nrates = 0, idx; +	enum nl80211_band band; +	bool has_he;  #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he)			\  	do {									\ -		u8 i, gi = mask->control[band]._gi;				\ +		u8 i, gi = mask.control[band]._gi;				\  		gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;		\  		phy.sgi = gi;							\ -		phy.he_ltf = mask->control[band].he_ltf;			\ -		for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {	\ -			if (!mask->control[band]._mcs[i])			\ +		phy.he_ltf = mask.control[band].he_ltf;				\ +		for (i = 0; i < ARRAY_SIZE(mask.control[band]._mcs); i++) {	\ +			if (!mask.control[band]._mcs[i])			\  				continue;					\ -			nrates += hweight16(mask->control[band]._mcs[i]);	\ -			phy.mcs = ffs(mask->control[band]._mcs[i]) - 1;		\ +			nrates += hweight16(mask.control[band]._mcs[i]);	\ +			phy.mcs = ffs(mask.control[band]._mcs[i]) - 1;		\  			if (_ht)						\  				phy.mcs += 8 * i;				\  		}								\  	} while (0) -	if (sta->deflink.he_cap.has_he) { +	rcu_read_lock(); + +	link = mt7996_vif_link(dev, vif, link_id); +	if (!link) +		goto error_unlock; + +	msta_link = rcu_dereference(msta->link[link_id]); +	if (!msta_link) +		goto error_unlock; + +	sta = wcid_to_sta(&msta_link->wcid); +	link_sta = rcu_dereference(sta->link[link_id]); +	if (!link_sta) +		goto error_unlock; + +	band = link->phy->mt76->chandef.chan->band; +	has_he = link_sta->he_cap.has_he; +	mask = link->bitrate_mask; +	idx = msta_link->wcid.idx; + +	if (has_he) {  		__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1); -	} else if (sta->deflink.vht_cap.vht_supported) { +	} else if (link_sta->vht_cap.vht_supported) {  		__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0); -	} else if (sta->deflink.ht_cap.ht_supported) { +	} else if (link_sta->ht_cap.ht_supported) {  		__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);  	} else { -		nrates = hweight32(mask->control[band].legacy); -		phy.mcs = ffs(mask->control[band].legacy) - 1; +		nrates = hweight32(mask.control[band].legacy); +		phy.mcs = ffs(mask.control[band].legacy) - 1;  	} + +	rcu_read_unlock(); +  #undef __sta_phy_bitrate_mask_check  	/* fall back to auto rate control */ -	if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI && -	    mask->control[band].he_gi == GENMASK(7, 0) && -	    mask->control[band].he_ltf == GENMASK(7, 0) && +	if (mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI && +	    mask.control[band].he_gi == GENMASK(7, 0) && +	    mask.control[band].he_ltf == GENMASK(7, 0) &&  	    nrates != 1)  		return 0;  	/* fixed single rate */  	if (nrates == 1) { -		ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, +		ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,  						 RATE_PARAM_FIXED_MCS);  		if (ret)  			return ret;  	}  	/* fixed GI */ -	if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI || -	    mask->control[band].he_gi != GENMASK(7, 0)) { -		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	if (mask.control[band].gi != NL80211_TXRATE_DEFAULT_GI || +	    mask.control[band].he_gi != GENMASK(7, 0)) {  		u32 addr;  		/* firmware updates only TXCMD but doesn't take WTBL into  		 * account, so driver should update here to reflect the  		 * actual txrate hardware sends out.  		 */ -		addr = mt7996_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7); -		if (sta->deflink.he_cap.has_he) +		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 7); +		if (has_he)  			mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);  		else  			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi); -		ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, +		ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,  						 RATE_PARAM_FIXED_GI);  		if (ret)  			return ret;  	}  	/* fixed HE_LTF */ -	if (mask->control[band].he_ltf != GENMASK(7, 0)) { -		ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, +	if (mask.control[band].he_ltf != GENMASK(7, 0)) { +		ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,  						 RATE_PARAM_FIXED_HE_LTF);  		if (ret)  			return ret;  	}  	return 0; + +error_unlock: +	rcu_read_unlock(); + +	return -ENODEV;  }  static void  mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, -			     struct ieee80211_vif *vif, struct ieee80211_sta *sta) +			     struct ieee80211_vif *vif, +			     struct ieee80211_bss_conf *link_conf, +			     struct ieee80211_link_sta *link_sta, +			     struct mt7996_vif_link *link)  {  #define INIT_RCPI 180 -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt76_phy *mphy = mvif->deflink.phy->mt76; +	struct mt76_phy *mphy = link->phy->mt76;  	struct cfg80211_chan_def *chandef = &mphy->chandef; -	struct cfg80211_bitrate_mask *mask = &mvif->deflink.bitrate_mask; +	struct cfg80211_bitrate_mask *mask = &link->bitrate_mask; +	u32 cap = link_sta->sta->wme ? STA_CAP_WMM : 0;  	enum nl80211_band band = chandef->chan->band;  	struct sta_rec_ra_uni *ra;  	struct tlv *tlv; -	u32 supp_rate = sta->deflink.supp_rates[band]; -	u32 cap = sta->wme ? STA_CAP_WMM : 0; +	u32 supp_rate = link_sta->supp_rates[band];  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));  	ra = (struct sta_rec_ra_uni *)tlv;  	ra->valid = true;  	ra->auto_rate = true; -	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink); +	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, link_sta);  	ra->channel = chandef->chan->hw_value; -	ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ? -		 CMD_CBW_320MHZ : sta->deflink.bandwidth; +	ra->bw = (link_sta->bandwidth == IEEE80211_STA_RX_BW_320) ? +		 CMD_CBW_320MHZ : link_sta->bandwidth;  	ra->phy.bw = ra->bw; -	ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); +	ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);  	if (supp_rate) {  		supp_rate &= mask->control[band].legacy; @@ -2062,60 +2152,60 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,  		}  	} -	if (sta->deflink.ht_cap.ht_supported) { +	if (link_sta->ht_cap.ht_supported) {  		ra->supp_mode |= MODE_HT; -		ra->af = sta->deflink.ht_cap.ampdu_factor; -		ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); +		ra->af = link_sta->ht_cap.ampdu_factor; +		ra->ht_gf = !!(link_sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);  		cap |= STA_CAP_HT; -		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) +		if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)  			cap |= STA_CAP_SGI_20; -		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) +		if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)  			cap |= STA_CAP_SGI_40; -		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) +		if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)  			cap |= STA_CAP_TX_STBC; -		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) +		if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)  			cap |= STA_CAP_RX_STBC; -		if (vif->bss_conf.ht_ldpc && -		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) +		if (link_conf->ht_ldpc && +		    (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))  			cap |= STA_CAP_LDPC; -		mt7996_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, +		mt7996_mcu_set_sta_ht_mcs(link_sta, ra->ht_mcs,  					  mask->control[band].ht_mcs);  		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;  	} -	if (sta->deflink.vht_cap.vht_supported) { +	if (link_sta->vht_cap.vht_supported) {  		u8 af;  		ra->supp_mode |= MODE_VHT;  		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, -			       sta->deflink.vht_cap.cap); +			       link_sta->vht_cap.cap);  		ra->af = max_t(u8, ra->af, af);  		cap |= STA_CAP_VHT; -		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) +		if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)  			cap |= STA_CAP_VHT_SGI_80; -		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) +		if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)  			cap |= STA_CAP_VHT_SGI_160; -		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) +		if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)  			cap |= STA_CAP_VHT_TX_STBC; -		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) +		if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)  			cap |= STA_CAP_VHT_RX_STBC; -		if ((vif->type != NL80211_IFTYPE_AP || vif->bss_conf.vht_ldpc) && -		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) +		if ((vif->type != NL80211_IFTYPE_AP || link_conf->vht_ldpc) && +		    (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))  			cap |= STA_CAP_VHT_LDPC; -		mt7996_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, +		mt7996_mcu_set_sta_vht_mcs(link_sta, ra->supp_vht_mcs,  					   mask->control[band].vht_mcs);  	} -	if (sta->deflink.he_cap.has_he) { +	if (link_sta->he_cap.has_he) {  		ra->supp_mode |= MODE_HE;  		cap |= STA_CAP_HE; -		if (sta->deflink.he_6ghz_capa.capa) -			ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, +		if (link_sta->he_6ghz_capa.capa) +			ra->af = le16_get_bits(link_sta->he_6ghz_capa.capa,  					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);  	}  	ra->sta_cap = cpu_to_le32(cap); @@ -2123,38 +2213,70 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,  	memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));  } -int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif, -			     struct ieee80211_sta *sta, bool changed) +int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta, +			     struct ieee80211_vif *vif, u8 link_id, +			     bool changed)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct ieee80211_bss_conf *link_conf; +	struct ieee80211_link_sta *link_sta; +	struct mt7996_sta_link *msta_link; +	struct mt7996_vif_link *link; +	struct ieee80211_sta *sta;  	struct sk_buff *skb; -	int ret; +	int ret = -ENODEV; + +	rcu_read_lock(); + +	link = mt7996_vif_link(dev, vif, link_id); +	if (!link) +		goto error_unlock; + +	msta_link = rcu_dereference(msta->link[link_id]); +	if (!msta_link) +		goto error_unlock; + +	sta = wcid_to_sta(&msta_link->wcid); +	link_sta = rcu_dereference(sta->link[link_id]); +	if (!link_sta) +		goto error_unlock; -	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, -					      &msta->wcid, +	link_conf = rcu_dereference(vif->link_conf[link_id]); +	if (!link_conf) +		goto error_unlock; + +	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, +					      &msta_link->wcid,  					      MT7996_STA_UPDATE_MAX_SIZE); -	if (IS_ERR(skb)) -		return PTR_ERR(skb); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		goto error_unlock; +	}  	/* firmware rc algorithm refers to sta_rec_he for HE control.  	 * once dev->rc_work changes the settings driver should also  	 * update sta_rec_he here.  	 */  	if (changed) -		mt7996_mcu_sta_he_tlv(skb, sta); +		mt7996_mcu_sta_he_tlv(skb, link_sta, link);  	/* sta_rec_ra accommodates BW, NSS and only MCS range format  	 * i.e 0-{7,8,9} for VHT.  	 */ -	mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); +	mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link); + +	rcu_read_unlock();  	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,  				    MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);  	if (ret)  		return ret; -	return mt7996_mcu_add_rate_ctrl_fixed(dev, vif, sta); +	return mt7996_mcu_add_rate_ctrl_fixed(dev, msta, vif, link_id); + +error_unlock: +	rcu_read_unlock(); + +	return ret;  }  static int @@ -2163,6 +2285,7 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,  {  #define MT_STA_BSS_GROUP		1  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +	struct mt7996_sta_link *msta_link;  	struct mt7996_sta *msta;  	struct {  		u8 __rsv1[4]; @@ -2181,73 +2304,150 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,  		.val = cpu_to_le32(mvif->deflink.mt76.idx % 16),  	}; -	msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->deflink.sta; -	req.wlan_idx = cpu_to_le16(msta->wcid.idx); +	msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL; +	msta_link = msta ? &msta->deflink : &mvif->deflink.msta_link; +	req.wlan_idx = cpu_to_le16(msta_link->wcid.idx);  	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req,  				 sizeof(req), true);  } -int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, -		       struct mt76_vif_link *mlink, -		       struct ieee80211_sta *sta, int conn_state, bool newly) +static void +mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, +			     struct ieee80211_vif *vif, +			     struct ieee80211_sta *sta)  { -	struct ieee80211_link_sta *link_sta = NULL; -	struct mt76_wcid *wcid = mlink->wcid; -	struct sk_buff *skb; -	int ret; +	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	unsigned int nlinks = hweight16(sta->valid_links); +	struct mld_setup_link *mld_setup_link; +	struct ieee80211_link_sta *link_sta; +	struct sta_rec_mld_setup *mld_setup; +	struct mt7996_sta_link *msta_link; +	unsigned int link_id; +	struct tlv *tlv; + +	msta_link = mt76_dereference(msta->link[msta->deflink_id], &dev->mt76); +	if (!msta_link) +		return; -	if (sta) { -		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, +				      sizeof(struct sta_rec_mld_setup) + +				      sizeof(struct mld_setup_link) * nlinks); -		wcid = &msta->wcid; -		link_sta = &sta->deflink; +	mld_setup = (struct sta_rec_mld_setup *)tlv; +	memcpy(mld_setup->mld_addr, sta->addr, ETH_ALEN); +	mld_setup->setup_wcid = cpu_to_le16(msta_link->wcid.idx); +	mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx); + +	if (nlinks > 1) { +		link_id = __ffs(sta->valid_links & ~BIT(msta->deflink_id)); +		msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); +		if (!msta_link) +			return;  	} +	mld_setup->seconed_id = cpu_to_le16(msta_link->wcid.idx); +	mld_setup->link_num = nlinks; -	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink, wcid, +	mld_setup_link = (struct mld_setup_link *)mld_setup->link_info; +	for_each_sta_active_link(vif, sta, link_sta, link_id) { +		struct mt7996_vif_link *link; + +		msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); +		if (!msta_link) +			continue; + +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; + +		mld_setup_link->wcid = cpu_to_le16(msta_link->wcid.idx); +		mld_setup_link->bss_idx = link->mt76.idx; +		mld_setup_link++; +	} +} + +static void +mt7996_mcu_sta_eht_mld_tlv(struct mt7996_dev *dev, struct sk_buff *skb, +			   struct ieee80211_sta *sta) +{ +	struct sta_rec_eht_mld *eht_mld; +	struct tlv *tlv; +	int i; + +	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld)); +	eht_mld = (struct sta_rec_eht_mld *)tlv; + +	for (i = 0; i < ARRAY_SIZE(eht_mld->str_cap); i++) +		eht_mld->str_cap[i] = 0x7; +} + +int mt7996_mcu_add_sta(struct mt7996_dev *dev, +		       struct ieee80211_bss_conf *link_conf, +		       struct ieee80211_link_sta *link_sta, +		       struct mt7996_vif_link *link, +		       struct mt7996_sta_link *msta_link, +		       int conn_state, bool newly) +{ +	struct mt76_wcid *wcid = msta_link ? &msta_link->wcid : link->mt76.wcid; +	struct ieee80211_sta *sta = link_sta ? link_sta->sta : NULL; +	struct sk_buff *skb; +	int ret; + +	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, wcid,  					      MT7996_STA_UPDATE_MAX_SIZE);  	if (IS_ERR(skb))  		return PTR_ERR(skb);  	/* starec basic */ -	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta, +	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, link_conf, link_sta,  				      conn_state, newly);  	if (conn_state == CONN_STATE_DISCONNECT)  		goto out;  	/* starec hdr trans */ -	mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, wcid); +	mt7996_mcu_sta_hdr_trans_tlv(dev, skb, link_conf->vif, wcid);  	/* starec tx proc */  	mt7996_mcu_sta_tx_proc_tlv(skb);  	/* tag order is in accordance with firmware dependency. */ -	if (sta) { +	if (link_sta) {  		/* starec hdrt mode */  		mt7996_mcu_sta_hdrt_tlv(dev, skb); -		/* starec bfer */ -		mt7996_mcu_sta_bfer_tlv(dev, skb, vif, sta); +		if (conn_state == CONN_STATE_CONNECT) { +			/* starec bfer */ +			mt7996_mcu_sta_bfer_tlv(dev, skb, link_conf, link_sta, +						link); +			/* starec bfee */ +			mt7996_mcu_sta_bfee_tlv(dev, skb, link_conf, link_sta, +						link); +		}  		/* starec ht */ -		mt7996_mcu_sta_ht_tlv(skb, sta); +		mt7996_mcu_sta_ht_tlv(skb, link_sta);  		/* starec vht */ -		mt7996_mcu_sta_vht_tlv(skb, sta); +		mt7996_mcu_sta_vht_tlv(skb, link_sta);  		/* starec uapsd */ -		mt76_connac_mcu_sta_uapsd(skb, vif, sta); +		mt76_connac_mcu_sta_uapsd(skb, link_conf->vif, sta);  		/* starec amsdu */ -		mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta); +		mt7996_mcu_sta_amsdu_tlv(dev, skb, link_conf->vif, link_sta, +					 msta_link);  		/* starec he */ -		mt7996_mcu_sta_he_tlv(skb, sta); +		mt7996_mcu_sta_he_tlv(skb, link_sta, link);  		/* starec he 6g*/ -		mt7996_mcu_sta_he_6g_tlv(skb, sta); +		mt7996_mcu_sta_he_6g_tlv(skb, link_sta);  		/* starec eht */ -		mt7996_mcu_sta_eht_tlv(skb, sta); +		mt7996_mcu_sta_eht_tlv(skb, link_sta);  		/* starec muru */ -		mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta); -		/* starec bfee */ -		mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta); +		mt7996_mcu_sta_muru_tlv(dev, skb, link_conf, link_sta); + +		if (sta->mlo) { +			mt7996_mcu_sta_mld_setup_tlv(dev, skb, link_conf->vif, +						     sta); +			mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta); +		}  	} -	ret = mt7996_mcu_add_group(dev, vif, sta); +	ret = mt7996_mcu_add_group(dev, link_conf->vif, sta);  	if (ret) {  		dev_kfree_skb(skb);  		return ret; @@ -2257,6 +2457,24 @@ out:  				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);  } +int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, +				struct mt7996_vif_link *link, +				struct mt7996_sta_link *msta_link) +{ +	struct sk_buff *skb; + +	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, +					      &msta_link->wcid, +					      MT7996_STA_UPDATE_MAX_SIZE); +	if (IS_ERR(skb)) +		return PTR_ERR(skb); + +	mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, sizeof(struct tlv)); + +	return mt76_mcu_skb_send_msg(&dev->mt76, skb, +				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} +  static int  mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,  		       struct sk_buff *skb, @@ -2322,17 +2540,18 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,  	return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);  } -static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif, -			     u8 *pn) +static int mt7996_mcu_get_pn(struct mt7996_dev *dev, +			     struct mt7996_vif_link *link, +			     struct mt7996_sta_link *msta_link, u8 *pn)  {  #define TSC_TYPE_BIGTK_PN 2 -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct sta_rec_pn_info *pn_info;  	struct sk_buff *skb, *rskb;  	struct tlv *tlv;  	int ret; -	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, &mvif->deflink.sta.wcid); +	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, +					    &msta_link->wcid);  	if (IS_ERR(skb))  		return PTR_ERR(skb); @@ -2356,10 +2575,11 @@ static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif,  	return 0;  } -int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, +			       struct mt7996_vif_link *link, +			       struct mt7996_sta_link *msta_link,  			       struct ieee80211_key_conf *key)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_mcu_bcn_prot_tlv *bcn_prot;  	struct sk_buff *skb;  	struct tlv *tlv; @@ -2368,7 +2588,7 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif  		  sizeof(struct mt7996_mcu_bcn_prot_tlv);  	int ret; -	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, len); +	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, len);  	if (IS_ERR(skb))  		return PTR_ERR(skb); @@ -2376,7 +2596,7 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif  	bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv; -	ret = mt7996_mcu_get_pn(dev, vif, pn); +	ret = mt7996_mcu_get_pn(dev, link, msta_link, pn);  	if (ret) {  		dev_kfree_skb(skb);  		return ret; @@ -2554,13 +2774,15 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  			  struct ieee80211_bss_conf *link_conf)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); +	struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); +	struct mt76_vif_link *mlink = link ? &link->mt76 : NULL;  	struct ieee80211_mutable_offsets offs;  	struct ieee80211_tx_info *info;  	struct sk_buff *skb, *rskb;  	struct tlv *tlv;  	struct bss_bcn_content_tlv *bcn;  	int len, extra_len = 0; +	bool enabled = link_conf->enable_beacon;  	if (link_conf->nontransmitted)  		return 0; @@ -2568,13 +2790,16 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	if (!mlink)  		return -EINVAL; +	if (link->phy && link->phy->mt76->offchannel) +		enabled = false; +  	rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink,  					  MT7996_MAX_BSS_OFFLOAD_SIZE);  	if (IS_ERR(rskb))  		return PTR_ERR(rskb);  	skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id); -	if (link_conf->enable_beacon && !skb) { +	if (enabled && !skb) {  		dev_kfree_skb(rskb);  		return -EINVAL;  	} @@ -2593,7 +2818,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + extra_len, 4);  	tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len);  	bcn = (struct bss_bcn_content_tlv *)tlv; -	bcn->enable = link_conf->enable_beacon; +	bcn->enable = enabled;  	if (!bcn->enable)  		goto out; @@ -2611,13 +2836,14 @@ out:  }  int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, -				    struct ieee80211_vif *vif, u32 changed) +				    struct ieee80211_bss_conf *link_conf, +				    struct mt7996_vif_link *link, u32 changed)  {  #define OFFLOAD_TX_MODE_SU	BIT(0)  #define OFFLOAD_TX_MODE_MU	BIT(1) +	struct ieee80211_vif *vif = link_conf->vif;  	struct ieee80211_hw *hw = mt76_hw(dev); -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); +	struct mt7996_phy *phy = link->phy;  	struct mt76_wcid *wcid = &dev->mt76.global_wcid;  	struct bss_inband_discovery_tlv *discov;  	struct ieee80211_tx_info *info; @@ -2634,21 +2860,21 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,  	chandef = &phy->mt76->chandef;  	band = chandef->chan->band; -	if (vif->bss_conf.nontransmitted) +	if (link_conf->nontransmitted)  		return 0; -	rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, +	rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76,  					  MT7996_MAX_BSS_OFFLOAD_SIZE);  	if (IS_ERR(rskb))  		return PTR_ERR(rskb);  	if (changed & BSS_CHANGED_FILS_DISCOVERY && -	    vif->bss_conf.fils_discovery.max_interval) { -		interval = vif->bss_conf.fils_discovery.max_interval; +	    link_conf->fils_discovery.max_interval) { +		interval = link_conf->fils_discovery.max_interval;  		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);  	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP && -		   vif->bss_conf.unsol_bcast_probe_resp_interval) { -		interval = vif->bss_conf.unsol_bcast_probe_resp_interval; +		   link_conf->unsol_bcast_probe_resp_interval) { +		interval = link_conf->unsol_bcast_probe_resp_interval;  		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);  	} @@ -2918,6 +3144,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev)  	if (ret)  		return ret; +	if (!mt7996_has_wa(dev)) +		return 0; +  	ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP),  				MT7996_RAM_TYPE_DSP);  	if (ret) @@ -2928,10 +3157,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev)  }  static int -mt7996_firmware_state(struct mt7996_dev *dev, bool wa) +mt7996_firmware_state(struct mt7996_dev *dev, u8 fw_state)  { -	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, -			       wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD); +	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, fw_state);  	if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,  			    state, 1000)) { @@ -2963,13 +3191,14 @@ mt7996_mcu_restart(struct mt76_dev *dev)  static int mt7996_load_firmware(struct mt7996_dev *dev)  { +	u8 fw_state;  	int ret;  	/* make sure fw is download state */ -	if (mt7996_firmware_state(dev, false)) { +	if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) {  		/* restart firmware once */  		mt7996_mcu_restart(&dev->mt76); -		ret = mt7996_firmware_state(dev, false); +		ret = mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD);  		if (ret) {  			dev_err(dev->mt76.dev,  				"Firmware is not ready for download\n"); @@ -2985,7 +3214,8 @@ static int mt7996_load_firmware(struct mt7996_dev *dev)  	if (ret)  		return ret; -	ret = mt7996_firmware_state(dev, true); +	fw_state = mt7996_has_wa(dev) ? FW_STATE_RDY : FW_STATE_NORMAL_TRX; +	ret = mt7996_firmware_state(dev, fw_state);  	if (ret)  		return ret; @@ -3123,13 +3353,15 @@ int mt7996_mcu_init_firmware(struct mt7996_dev *dev)  	if (ret)  		return ret; -	ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); -	if (ret) -		return ret; +	if (mt7996_has_wa(dev)) { +		ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); +		if (ret) +			return ret; -	ret = mt7996_mcu_set_mwds(dev, 1); -	if (ret) -		return ret; +		ret = mt7996_mcu_set_mwds(dev, 1); +		if (ret) +			return ret; +	}  	ret = mt7996_mcu_init_rx_airtime(dev);  	if (ret) @@ -3155,7 +3387,7 @@ int mt7996_mcu_init(struct mt7996_dev *dev)  void mt7996_mcu_exit(struct mt7996_dev *dev)  {  	mt7996_mcu_restart(&dev->mt76); -	if (mt7996_firmware_state(dev, false)) { +	if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) {  		dev_err(dev->mt76.dev, "Failed to exit mcu\n");  		goto out;  	} @@ -3172,7 +3404,7 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans)  {  	struct {  		u8 __rsv[4]; -	} __packed hdr; +	} __packed hdr = {};  	struct hdr_trans_blacklist *req_blacklist;  	struct hdr_trans_en *req_en;  	struct sk_buff *skb; @@ -3442,11 +3674,10 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,  				     struct cfg80211_chan_def *chandef)  {  	struct mt7996_dev *dev = phy->dev; -	int err, region; +	int err, region, rdd_idx = mt7996_get_rdd_idx(phy, true);  	if (!chandef) { /* disable offchain */ -		err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, -					 0, 0); +		err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0);  		if (err)  			return err; @@ -3472,8 +3703,7 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,  		break;  	} -	return mt7996_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, -				  0, region); +	return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);  }  int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) @@ -4095,12 +4325,12 @@ mt7996_mcu_set_obss_spr_pd(struct mt7996_phy *phy,  }  static int -mt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy, struct ieee80211_vif *vif, +mt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy, +			     struct mt7996_vif_link *link,  			     struct ieee80211_he_obss_pd *he_obss_pd)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_dev *dev = phy->dev; -	u8 omac = mvif->deflink.mt76.omac_idx; +	u8 omac = link->mt76.omac_idx;  	struct {  		u8 band_idx;  		u8 __rsv[3]; @@ -4172,7 +4402,8 @@ mt7996_mcu_set_obss_spr_bitmap(struct mt7996_phy *phy,  				 sizeof(req), true);  } -int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif, +int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, +			    struct mt7996_vif_link *link,  			    struct ieee80211_he_obss_pd *he_obss_pd)  {  	int ret; @@ -4206,7 +4437,7 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,  		return ret;  	/* Set SR prohibit */ -	ret = mt7996_mcu_set_obss_spr_siga(phy, vif, he_obss_pd); +	ret = mt7996_mcu_set_obss_spr_siga(phy, link, he_obss_pd);  	if (ret)  		return ret; @@ -4242,7 +4473,7 @@ int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,  #define TWT_AGRT_PROTECT	BIT(2)  int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, -			       struct mt7996_vif *mvif, +			       struct mt7996_vif_link *link,  			       struct mt7996_twt_flow *flow,  			       int cmd)  { @@ -4273,12 +4504,12 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,  		.len = cpu_to_le16(sizeof(req) - 4),  		.tbl_idx = flow->table_id,  		.cmd = cmd, -		.own_mac_idx = mvif->deflink.mt76.omac_idx, +		.own_mac_idx = link->mt76.omac_idx,  		.flowid = flow->id,  		.peer_id = cpu_to_le16(flow->wcid),  		.duration = flow->duration, -		.bss = mvif->deflink.mt76.idx, -		.bss_idx = mvif->deflink.mt76.idx, +		.bss = link->mt76.idx, +		.bss_idx = link->mt76.idx,  		.start_tsf = cpu_to_le64(flow->tsf),  		.mantissa = flow->mantissa,  		.exponent = flow->exp, @@ -4339,8 +4570,7 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)  				 &req, sizeof(req), true);  } -int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, -		       u8 rx_sel, u8 val) +int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val)  {  	struct {  		u8 _rsv[4]; @@ -4357,8 +4587,7 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,  		.tag = cpu_to_le16(UNI_RDD_CTRL_PARM),  		.len = cpu_to_le16(sizeof(req) - 4),  		.ctrl = cmd, -		.rdd_idx = index, -		.rdd_rx_sel = rx_sel, +		.rdd_idx = rdd_idx,  		.val = val,  	}; @@ -4368,22 +4597,19 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,  int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,  				     struct ieee80211_vif *vif, -				     struct ieee80211_sta *sta) +				     struct mt7996_vif_link *link, +				     struct mt7996_sta_link *msta_link)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_sta *msta;  	struct sk_buff *skb; -	msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->deflink.sta; - -	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, -					      &msta->wcid, +	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, +					      &msta_link->wcid,  					      MT7996_STA_UPDATE_MAX_SIZE);  	if (IS_ERR(skb))  		return PTR_ERR(skb);  	/* starec hdr trans */ -	mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta->wcid); +	mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta_link->wcid);  	return mt76_mcu_skb_send_msg(&dev->mt76, skb,  				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);  } @@ -4606,7 +4832,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)  	struct sk_buff *skb;  	int i, tx_power; -	tx_power = mt7996_get_power_bound(phy, phy->txpower); +	tx_power = mt76_get_power_bound(mphy, phy->txpower);  	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,  					      &la, tx_power);  	mphy->txpower_cur = tx_power; @@ -4651,7 +4877,26 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode)  	    mode > mt76_connac_lmac_mapping(IEEE80211_AC_VO))  		return -EINVAL; +	if (!mt7996_has_wa(dev)) { +		struct { +			u8 _rsv[4]; + +			__le16 tag; +			__le16 len; +			u8 cp_mode; +			u8 rsv[3]; +		} __packed req = { +			.tag = cpu_to_le16(UNI_CMD_SDO_CP_MODE), +			.len = cpu_to_le16(sizeof(req) - 4), +			.cp_mode = mode, +		}; + +		return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO), +					 &req, sizeof(req), false); +	} +  	cp_mode = cpu_to_le32(mode); +  	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT),  				 &cp_mode, sizeof(cp_mode), true);  } | 
