diff options
Diffstat (limited to 'sys/contrib/dev/mediatek/mt76/mt7996/main.c')
| -rw-r--r-- | sys/contrib/dev/mediatek/mt76/mt7996/main.c | 1028 | 
1 files changed, 765 insertions, 263 deletions
| diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/main.c b/sys/contrib/dev/mediatek/mt76/mt7996/main.c index 69dd565d8319..84f731b387d2 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/main.c @@ -68,11 +68,13 @@ static int mt7996_start(struct ieee80211_hw *hw)  static void mt7996_stop_phy(struct mt7996_phy *phy)  { -	struct mt7996_dev *dev = phy->dev; +	struct mt7996_dev *dev;  	if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state))  		return; +	dev = phy->dev; +  	cancel_delayed_work_sync(&phy->mt76->mac_work);  	mutex_lock(&dev->mt76.mutex); @@ -158,58 +160,101 @@ mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlin  static int  mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		  struct ieee80211_vif *vif, struct ieee80211_sta *sta, -		  struct mt7996_vif_link *mlink, struct ieee80211_key_conf *key) +		  struct ieee80211_key_conf *key)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : -				  &mlink->sta; -	struct mt76_wcid *wcid = &msta->wcid; -	u8 *wcid_keyidx = &wcid->hw_key_idx; -	struct mt7996_phy *phy;  	int idx = key->keyidx; +	unsigned int link_id; +	unsigned long links; + +	if (key->link_id >= 0) +		links = BIT(key->link_id); +	else if (sta && sta->valid_links) +		links = sta->valid_links; +	else if (vif->valid_links) +		links = vif->valid_links; +	else +		links = BIT(0); -	phy = mt7996_vif_link_phy(mlink); -	if (!phy) -		return -EINVAL; +	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { +		struct mt7996_sta_link *msta_link; +		struct mt7996_vif_link *link; +		u8 *wcid_keyidx; +		int err; -	if (sta && !wcid->sta) -		return -EOPNOTSUPP; +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; -	switch (key->cipher) { -	case WLAN_CIPHER_SUITE_AES_CMAC: -	case WLAN_CIPHER_SUITE_BIP_CMAC_256: -	case WLAN_CIPHER_SUITE_BIP_GMAC_128: -	case WLAN_CIPHER_SUITE_BIP_GMAC_256: -		if (key->keyidx == 6 || key->keyidx == 7) { -			wcid_keyidx = &wcid->hw_key_idx2; -			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; +		if (sta) { +			struct mt7996_sta *msta; + +			msta = (struct mt7996_sta *)sta->drv_priv; +			msta_link = mt76_dereference(msta->link[link_id], +						     &dev->mt76); +			if (!msta_link) +				continue; + +			if (!msta_link->wcid.sta) +				return -EOPNOTSUPP; +		} else { +			msta_link = &link->msta_link; +		} +		wcid_keyidx = &msta_link->wcid.hw_key_idx; + +		switch (key->cipher) { +		case WLAN_CIPHER_SUITE_AES_CMAC: +		case WLAN_CIPHER_SUITE_BIP_CMAC_256: +		case WLAN_CIPHER_SUITE_BIP_GMAC_128: +		case WLAN_CIPHER_SUITE_BIP_GMAC_256: +			if (key->keyidx == 6 || key->keyidx == 7) { +				wcid_keyidx = &msta_link->wcid.hw_key_idx2; +				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; +			} +			break; +		default: +			break;  		} -		break; -	default: -		break; -	} -	if (cmd == SET_KEY && !sta && !mlink->mt76.cipher) { -		mlink->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); -		mt7996_mcu_add_bss_info(phy, vif, &vif->bss_conf, &mlink->mt76, true); -	} +		if (cmd == SET_KEY && !sta && !link->mt76.cipher) { +			struct ieee80211_bss_conf *link_conf; -	if (cmd == SET_KEY) { -		*wcid_keyidx = idx; -	} else { -		if (idx == *wcid_keyidx) -			*wcid_keyidx = -1; -		return 0; -	} +			link_conf = link_conf_dereference_protected(vif, +								    link_id); +			if (!link_conf) +				link_conf = &vif->bss_conf; -	mt76_wcid_key_setup(&dev->mt76, wcid, key); +			link->mt76.cipher = +				mt76_connac_mcu_get_cipher(key->cipher); +			mt7996_mcu_add_bss_info(link->phy, vif, link_conf, +						&link->mt76, msta_link, true); +		} -	if (key->keyidx == 6 || key->keyidx == 7) -		return mt7996_mcu_bcn_prot_enable(dev, vif, key); +		if (cmd == SET_KEY) { +			*wcid_keyidx = idx; +		} else { +			if (idx == *wcid_keyidx) +				*wcid_keyidx = -1; +			continue; +		} + +		mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key); + +		if (key->keyidx == 6 || key->keyidx == 7) { +			err = mt7996_mcu_bcn_prot_enable(dev, link, +							 msta_link, key); +			if (err) +				return err; +		} + +		err = mt7996_mcu_add_key(&dev->mt76, vif, key, +					 MCU_WMWA_UNI_CMD(STA_REC_UPDATE), +					 &msta_link->wcid, cmd); +		if (err) +			return err; +	} -	return mt7996_mcu_add_key(&dev->mt76, vif, key, -				  MCU_WMWA_UNI_CMD(STA_REC_UPDATE), -				  &msta->wcid, cmd); +	return 0;  }  static void @@ -217,12 +262,10 @@ mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  		struct ieee80211_sta *sta, struct ieee80211_key_conf *key,  		void *data)  { -	struct mt7996_vif_link *mlink = data; -  	if (sta)  		return; -	WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, mlink, key)); +	WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, key));  }  int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, @@ -230,6 +273,8 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,  			struct mt76_vif_link *mlink)  {  	struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); +	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +	struct mt7996_sta_link *msta_link = &link->msta_link;  	struct mt7996_phy *phy = mphy->priv;  	struct mt7996_dev *dev = phy->dev;  	u8 band_idx = phy->mt76->band_idx; @@ -248,7 +293,8 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,  	mlink->omac_idx = idx;  	mlink->band_idx = band_idx;  	mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; -	mlink->wcid = &link->sta.wcid; +	mlink->wcid = &msta_link->wcid; +	mlink->wcid->offchannel = mlink->offchannel;  	ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true);  	if (ret) @@ -259,10 +305,11 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,  	idx = MT7996_WTBL_RESERVED - mlink->idx; -	INIT_LIST_HEAD(&link->sta.rc_list); -	link->sta.wcid.idx = idx; -	link->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; -	mt76_wcid_init(&link->sta.wcid, band_idx); +	INIT_LIST_HEAD(&msta_link->rc_list); +	msta_link->wcid.idx = idx; +	msta_link->wcid.link_id = link_conf->link_id; +	msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; +	mt76_wcid_init(&msta_link->wcid, band_idx);  	mt7996_mac_wtbl_update(dev, idx,  			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -283,15 +330,19 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,  	mt7996_init_bitrate_mask(vif, link); -	mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, true); +	mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, true);  	/* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA  	 * interface, since firmware only records BSSID when the entry is new  	 */  	if (vif->type != NL80211_IFTYPE_STATION) -		mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_PORT_SECURE, true); -	rcu_assign_pointer(dev->mt76.wcid[idx], &link->sta.wcid); +		mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, +				   CONN_STATE_PORT_SECURE, true); +	rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid); -	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, link); +	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, NULL); + +	if (mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) +		mvif->mt76.deflink_id = link_conf->link_id;  	return 0;  } @@ -301,29 +352,42 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,  			    struct mt76_vif_link *mlink)  {  	struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); +	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +	struct mt7996_sta_link *msta_link = &link->msta_link;  	struct mt7996_phy *phy = mphy->priv;  	struct mt7996_dev *dev = phy->dev; -	struct mt7996_sta *msta; -	int idx; +	int idx = msta_link->wcid.idx; -	msta = &link->sta; -	idx = msta->wcid.idx; -	mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_DISCONNECT, false); -	mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, false); +	mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, +			   CONN_STATE_DISCONNECT, false); +	mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false);  	mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false);  	rcu_assign_pointer(dev->mt76.wcid[idx], NULL); +	if (mvif->mt76.deflink_id == link_conf->link_id) { +		struct ieee80211_bss_conf *iter; +		unsigned int link_id; + +		mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; +		for_each_vif_active_link(vif, iter, link_id) { +			if (link_id != IEEE80211_LINK_UNSPECIFIED) { +				mvif->mt76.deflink_id = link_id; +				break; +			} +		} +	} +  	dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx);  	phy->omac_mask &= ~BIT_ULL(mlink->omac_idx);  	spin_lock_bh(&dev->mt76.sta_poll_lock); -	if (!list_empty(&msta->wcid.poll_list)) -		list_del_init(&msta->wcid.poll_list); +	if (!list_empty(&msta_link->wcid.poll_list)) +		list_del_init(&msta_link->wcid.poll_list);  	spin_unlock_bh(&dev->mt76.sta_poll_lock); -	mt76_wcid_cleanup(&dev->mt76, &msta->wcid); +	mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid);  }  static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) @@ -352,11 +416,13 @@ static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy)  static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled)  { -	struct mt7996_dev *dev = phy->dev; +	struct mt7996_dev *dev;  	if (!phy)  		return; +	dev = phy->dev; +  	if (enabled == !(phy->rxfilter & MT_WF_RFCR_DROP_OTHER_UC))  		return; @@ -399,6 +465,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,  	mt76_vif_init(vif, &mvif->mt76);  	vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; +	mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED;  out:  	mutex_unlock(&dev->mt76.mutex); @@ -449,6 +516,9 @@ int mt7996_set_channel(struct mt76_phy *mphy)  	struct mt7996_phy *phy = mphy->priv;  	int ret; +	if (mphy->offchannel) +		mt7996_mac_update_beacons(phy); +  	ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);  	if (ret)  		goto out; @@ -466,6 +536,8 @@ int mt7996_set_channel(struct mt76_phy *mphy)  	mt7996_mac_reset_counters(phy);  	phy->noise = 0; +	if (!mphy->offchannel) +		mt7996_mac_update_beacons(phy);  out:  	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, @@ -480,7 +552,6 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_vif_link *mlink = &mvif->deflink;  	int err;  	/* The hardware does not support per-STA RX GTK, fallback @@ -515,17 +586,17 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		return -EOPNOTSUPP;  	} -	if (!mt7996_vif_link_phy(mlink)) -	    return 0; /* defer until after link add */ +	if (!mt7996_vif_link_phy(&mvif->deflink)) +		return 0; /* defer until after link add */  	mutex_lock(&dev->mt76.mutex); -	err = mt7996_set_hw_key(hw, cmd, vif, sta, mlink, key); +	err = mt7996_set_hw_key(hw, cmd, vif, sta, key);  	mutex_unlock(&dev->mt76.mutex);  	return err;  } -static int mt7996_config(struct ieee80211_hw *hw, u32 changed) +static int mt7996_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)  {  	return 0;  } @@ -601,6 +672,33 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,  	mutex_unlock(&dev->mt76.mutex);  } +static int +mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		   unsigned int link_id, int *dbm) +{ +	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	struct wireless_dev *wdev; +	int n_chains, delta, i; + +	if (!phy) { +		wdev = ieee80211_vif_to_wdev(vif); +		for (i = 0; i < hw->wiphy->n_radio; i++) +			if (wdev->radio_mask & BIT(i)) +				phy = dev->radio_phy[i]; + +		if (!phy) +			return -EINVAL; +	} + +	n_chains = hweight16(phy->mt76->chainmask); +	delta = mt76_tx_power_path_delta(n_chains); +	*dbm = DIV_ROUND_UP(phy->mt76->txpower_cur + delta, 2); + +	return 0; +} +  static u8  mt7996_get_rates_table(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,  		       bool beacon, bool mcast) @@ -630,12 +728,11 @@ mt7996_get_rates_table(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,  }  static void -mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +mt7996_update_mu_group(struct ieee80211_hw *hw, struct mt7996_vif_link *link,  		       struct ieee80211_bss_conf *info)  { -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	u8 band = mvif->deflink.mt76.band_idx; +	u8 band = link->mt76.band_idx;  	u32 *mu;  	mu = (u32 *)info->mu_group.membership; @@ -649,23 +746,56 @@ mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]);  } -static void mt7996_bss_info_changed(struct ieee80211_hw *hw, -				    struct ieee80211_vif *vif, -				    struct ieee80211_bss_conf *info, -				    u64 changed) +static void +mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		       u64 changed)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt76_vif_link *mvif; + +	mutex_lock(&dev->mt76.mutex); + +	if ((changed & BSS_CHANGED_ASSOC) && vif->cfg.assoc) { +		struct ieee80211_bss_conf *link_conf; +		unsigned long link_id; + +		for_each_vif_active_link(vif, link_conf, link_id) { +			struct mt7996_vif_link *link; + +			link = mt7996_vif_link(dev, vif, link_id); +			if (!link) +				continue; + +			if (!link->phy) +				continue; + +			mt7996_mcu_add_bss_info(link->phy, vif, link_conf, +						&link->mt76, &link->msta_link, +						true); +			mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, +					   CONN_STATE_PORT_SECURE, +					   !!(changed & BSS_CHANGED_BSSID)); +		} +	} + +	mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			 struct ieee80211_bss_conf *info, u64 changed) +{ +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	struct mt7996_vif_link *link;  	struct mt7996_phy *phy;  	struct mt76_phy *mphy;  	mutex_lock(&dev->mt76.mutex); -	mvif = mt76_vif_conf_link(&dev->mt76, vif, info); -	if (!mvif) +	link = mt7996_vif_conf_link(dev, vif, info); +	if (!link)  		goto out; -	mphy = mt76_vif_link_phy(mvif); +	mphy = mt76_vif_link_phy(&link->mt76);  	if (!mphy)  		goto out; @@ -675,16 +805,14 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,  	 * and then peer references bss_info_rfch to set bandwidth cap.  	 */  	if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) || -	    (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||  	    (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) { -		mt7996_mcu_add_bss_info(phy, vif, info, mvif, true); -		mt7996_mcu_add_sta(dev, vif, mvif, NULL, CONN_STATE_PORT_SECURE, +		mt7996_mcu_add_bss_info(phy, vif, info, &link->mt76, +					&link->msta_link, true); +		mt7996_mcu_add_sta(dev, info, NULL, link, NULL, +				   CONN_STATE_PORT_SECURE,  				   !!(changed & BSS_CHANGED_BSSID));  	} -	if (changed & BSS_CHANGED_ERP_CTS_PROT) -		mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); -  	if (changed & BSS_CHANGED_ERP_SLOT) {  		int slottime = info->use_short_slot ? 9 : 20; @@ -695,11 +823,11 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,  	}  	if (changed & BSS_CHANGED_MCAST_RATE) -		mvif->mcast_rates_idx = +		link->mt76.mcast_rates_idx =  			mt7996_get_rates_table(phy, info, false, true);  	if (changed & BSS_CHANGED_BASIC_RATES) -		mvif->basic_rates_idx = +		link->mt76.basic_rates_idx =  			mt7996_get_rates_table(phy, info, false, false);  	/* ensure that enable txcmd_mode after bss_info */ @@ -707,19 +835,19 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,  		mt7996_mcu_set_tx(dev, vif, info);  	if (changed & BSS_CHANGED_HE_OBSS_PD) -		mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); +		mt7996_mcu_add_obss_spr(phy, link, &info->he_obss_pd);  	if (changed & BSS_CHANGED_HE_BSS_COLOR) {  		if ((vif->type == NL80211_IFTYPE_AP && -		    mvif->omac_idx <= HW_BSSID_MAX) || +		    link->mt76.omac_idx <= HW_BSSID_MAX) ||  		   vif->type == NL80211_IFTYPE_STATION) -			mt7996_mcu_update_bss_color(dev, mvif, +			mt7996_mcu_update_bss_color(dev, &link->mt76,  						    &info->he_bss_color);  	}  	if (changed & (BSS_CHANGED_BEACON |  		       BSS_CHANGED_BEACON_ENABLED)) { -		mvif->beacon_rates_idx = +		link->mt76.beacon_rates_idx =  			mt7996_get_rates_table(phy, info, true, false);  		mt7996_mcu_add_beacon(hw, vif, info); @@ -727,10 +855,10 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,  	if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |  		       BSS_CHANGED_FILS_DISCOVERY)) -		mt7996_mcu_beacon_inband_discov(dev, vif, changed); +		mt7996_mcu_beacon_inband_discov(dev, info, link, changed);  	if (changed & BSS_CHANGED_MU_GROUPS) -		mt7996_update_mu_group(hw, vif, info); +		mt7996_update_mu_group(hw, link, info);  	if (changed & BSS_CHANGED_TXPOWER &&  	    info->txpower != phy->txpower) { @@ -754,96 +882,332 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,  	mutex_unlock(&dev->mt76.mutex);  } -int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, -		       struct ieee80211_sta *sta) +static int +mt7996_mac_sta_init_link(struct mt7996_dev *dev, +			 struct ieee80211_bss_conf *link_conf, +			 struct ieee80211_link_sta *link_sta, +			 struct mt7996_vif_link *link, unsigned int link_id)  { -	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); +	struct ieee80211_sta *sta = link_sta->sta;  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_vif_link *link = &mvif->deflink; -	u8 band_idx = link->phy->mt76->band_idx; +	struct mt7996_phy *phy = link->phy; +	struct mt7996_sta_link *msta_link;  	int idx;  	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);  	if (idx < 0)  		return -ENOSPC; -	INIT_LIST_HEAD(&msta->rc_list); -	INIT_LIST_HEAD(&msta->wcid.poll_list); -	msta->vif = mvif; -	msta->wcid.sta = 1; -	msta->wcid.idx = idx; -	msta->wcid.phy_idx = band_idx; +	if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { +		int i; -	ewma_avg_signal_init(&msta->avg_ack_signal); +		msta_link = &msta->deflink; +		msta->deflink_id = link_id; -	mt7996_mac_wtbl_update(dev, idx, +		for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { +			struct mt76_txq *mtxq; + +			if (!sta->txq[i]) +				continue; + +			mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; +			mtxq->wcid = idx; +		} +	} else { +		msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL); +		if (!msta_link) +			return -ENOMEM; +	} + +	INIT_LIST_HEAD(&msta_link->rc_list); +	INIT_LIST_HEAD(&msta_link->wcid.poll_list); +	msta_link->sta = msta; +	msta_link->wcid.sta = 1; +	msta_link->wcid.idx = idx; +	msta_link->wcid.link_id = link_id; + +	ewma_avg_signal_init(&msta_link->avg_ack_signal); +	ewma_signal_init(&msta_link->wcid.rssi); + +	rcu_assign_pointer(msta->link[link_id], msta_link); + +	mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); +	mt7996_mcu_add_sta(dev, link_conf, link_sta, link, msta_link, +			   CONN_STATE_DISCONNECT, true); + +	rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid); +	mt76_wcid_init(&msta_link->wcid, phy->mt76->band_idx); + +	return 0; +} + +static void +mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, +			   struct mt7996_sta_link *msta_link) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(msta_link->wcid.aggr); i++) +		mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, i); + +	mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,  			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR); -	mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, CONN_STATE_DISCONNECT, -			   true); + +	spin_lock_bh(&dev->mt76.sta_poll_lock); +	if (!list_empty(&msta_link->wcid.poll_list)) +		list_del_init(&msta_link->wcid.poll_list); +	if (!list_empty(&msta_link->rc_list)) +		list_del_init(&msta_link->rc_list); +	spin_unlock_bh(&dev->mt76.sta_poll_lock); + +	mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); +	mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); +} + +static void +mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, +			    struct ieee80211_sta *sta, unsigned long links) +{ +	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt76_dev *mdev = &dev->mt76; +	unsigned int link_id; + +	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { +		struct mt7996_sta_link *msta_link = NULL; +		struct mt7996_vif_link *link; +		struct mt76_phy *mphy; + +		msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, +						lockdep_is_held(&mdev->mutex)); +		if (!msta_link) +			continue; + +		mt7996_mac_sta_deinit_link(dev, msta_link); +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; + +		mphy = mt76_vif_link_phy(&link->mt76); +		if (!mphy) +			continue; + +		mphy->num_sta--; +		if (msta->deflink_id == link_id) { +			msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +			continue; +		} + +		kfree_rcu(msta_link, rcu_head); +	} +} + +static int +mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, +			 struct ieee80211_sta *sta, unsigned long new_links) +{ +	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	unsigned int link_id; +	int err = 0; + +	for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { +		struct ieee80211_bss_conf *link_conf; +		struct ieee80211_link_sta *link_sta; +		struct mt7996_vif_link *link; +		struct mt76_phy *mphy; + +		if (rcu_access_pointer(msta->link[link_id])) +			continue; + +		link_conf = link_conf_dereference_protected(vif, link_id); +		if (!link_conf) { +			err = -EINVAL; +			goto error_unlink; +		} + +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) { +			err = -EINVAL; +			goto error_unlink; +		} + +		link_sta = link_sta_dereference_protected(sta, link_id); +		if (!link_sta) { +			err = -EINVAL; +			goto error_unlink; +		} + +		err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link, +					       link_id); +		if (err) +			goto error_unlink; + +		mphy = mt76_vif_link_phy(&link->mt76); +		if (!mphy) { +			err = -EINVAL; +			goto error_unlink; +		} +		mphy->num_sta++; +	}  	return 0; + +error_unlink: +	mt7996_mac_sta_remove_links(dev, vif, sta, new_links); + +	return err;  } -int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, -			 struct ieee80211_sta *sta, enum mt76_sta_event ev) +static int +mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			    struct ieee80211_sta *sta, u16 old_links, +			    u16 new_links) +{ +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	unsigned long add = new_links & ~old_links; +	unsigned long rem = old_links & ~new_links; +	int ret; + +	mutex_lock(&dev->mt76.mutex); + +	mt7996_mac_sta_remove_links(dev, vif, sta, rem); +	ret = mt7996_mac_sta_add_links(dev, vif, sta, add); + +	mutex_unlock(&dev->mt76.mutex); + +	return ret; +} + +static int +mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, +		   struct ieee80211_sta *sta)  { -	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	struct mt7996_vif_link *link = &mvif->deflink; -	int i, ret; +	unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); +	int err; -	switch (ev) { -	case MT76_STA_EVENT_ASSOC: -		ret = mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, -					 CONN_STATE_CONNECT, true); -		if (ret) -			return ret; +	mutex_lock(&dev->mt76.mutex); -		ret = mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); -		if (ret) -			return ret; +	msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +	msta->vif = mvif; +	err = mt7996_mac_sta_add_links(dev, vif, sta, links); -		msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; -		msta->wcid.sta = 1; +	mutex_unlock(&dev->mt76.mutex); -		return 0; +	return err; +} -	case MT76_STA_EVENT_AUTHORIZE: -		return mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, -					  CONN_STATE_PORT_SECURE, false); +static int +mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, +		     struct ieee80211_sta *sta, enum mt76_sta_event ev) +{ +	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	unsigned long links = sta->valid_links; +	struct ieee80211_link_sta *link_sta; +	unsigned int link_id; + +	for_each_sta_active_link(vif, sta, link_sta, link_id) { +		struct ieee80211_bss_conf *link_conf; +		struct mt7996_sta_link *msta_link; +		struct mt7996_vif_link *link; +		int i, err; + +		link_conf = link_conf_dereference_protected(vif, link_id); +		if (!link_conf) +			continue; -	case MT76_STA_EVENT_DISASSOC: -		for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) -			mt7996_mac_twt_teardown_flow(dev, msta, i); +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; -		mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, -				   CONN_STATE_DISCONNECT, false); -		msta->wcid.sta_disabled = 1; -		msta->wcid.sta = 0; +		msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); +		if (!msta_link) +			continue; -		return 0; +		switch (ev) { +		case MT76_STA_EVENT_ASSOC: +			err = mt7996_mcu_add_sta(dev, link_conf, link_sta, +						 link, msta_link, +						 CONN_STATE_CONNECT, true); +			if (err) +				return err; + +			err = mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif, +						       link_id, false); +			if (err) +				return err; + +			msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; +			break; +		case MT76_STA_EVENT_AUTHORIZE: +			err = mt7996_mcu_add_sta(dev, link_conf, link_sta, +						 link, msta_link, +						 CONN_STATE_PORT_SECURE, false); +			if (err) +				return err; +			break; +		case MT76_STA_EVENT_DISASSOC: +			for (i = 0; i < ARRAY_SIZE(msta_link->twt.flow); i++) +				mt7996_mac_twt_teardown_flow(dev, link, +							     msta_link, i); + +			if (sta->mlo && links == BIT(link_id)) /* last link */ +				mt7996_mcu_teardown_mld_sta(dev, link, +							    msta_link); +			else +				mt7996_mcu_add_sta(dev, link_conf, link_sta, +						   link, msta_link, +						   CONN_STATE_DISCONNECT, false); +			msta_link->wcid.sta_disabled = 1; +			msta_link->wcid.sta = 0; +			links = links & ~BIT(link_id); +			break; +		}  	}  	return 0;  } -void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, -			   struct ieee80211_sta *sta) +static void +mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, +		      struct ieee80211_sta *sta)  { -	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); -	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); -	mt7996_mac_wtbl_update(dev, msta->wcid.idx, -			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR); +	mutex_lock(&dev->mt76.mutex); +	mt7996_mac_sta_remove_links(dev, vif, sta, links); +	mutex_unlock(&dev->mt76.mutex); +} + +static int +mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +		 struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, +		 enum ieee80211_sta_state new_state) +{ +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	enum mt76_sta_event ev; + +	if (old_state == IEEE80211_STA_NOTEXIST && +	    new_state == IEEE80211_STA_NONE) +		return mt7996_mac_sta_add(dev, vif, sta); + +	if (old_state == IEEE80211_STA_NONE && +	    new_state == IEEE80211_STA_NOTEXIST) +		mt7996_mac_sta_remove(dev, vif, sta); + +	if (old_state == IEEE80211_STA_AUTH && +	    new_state == IEEE80211_STA_ASSOC) +		ev = MT76_STA_EVENT_ASSOC; +	else if (old_state == IEEE80211_STA_ASSOC && +		 new_state == IEEE80211_STA_AUTHORIZED) +		ev = MT76_STA_EVENT_AUTHORIZE; +	else if (old_state == IEEE80211_STA_ASSOC && +		 new_state == IEEE80211_STA_AUTH) +		ev = MT76_STA_EVENT_DISASSOC; +	else +		return 0; -	spin_lock_bh(&mdev->sta_poll_lock); -	if (!list_empty(&msta->wcid.poll_list)) -		list_del_init(&msta->wcid.poll_list); -	if (!list_empty(&msta->rc_list)) -		list_del_init(&msta->rc_list); -	spin_unlock_bh(&mdev->sta_poll_lock); +	return mt7996_mac_sta_event(dev, vif, sta, ev);  }  static void mt7996_tx(struct ieee80211_hw *hw, @@ -855,12 +1219,25 @@ static void mt7996_tx(struct ieee80211_hw *hw,  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct ieee80211_vif *vif = info->control.vif;  	struct mt76_wcid *wcid = &dev->mt76.global_wcid; +	u8 link_id = u32_get_bits(info->control.flags, +				  IEEE80211_TX_CTRL_MLO_LINK); + +	rcu_read_lock();  	if (vif) { -		struct mt7996_vif *mvif; +		struct mt7996_vif *mvif = (void *)vif->drv_priv; +		struct mt76_vif_link *mlink = &mvif->deflink.mt76; -		mvif = (struct mt7996_vif *)vif->drv_priv; -		wcid = &mvif->deflink.sta.wcid; +		if (link_id < IEEE80211_LINK_UNSPECIFIED) +			mlink = rcu_dereference(mvif->mt76.link[link_id]); + +		if (!mlink) { +			ieee80211_free_txskb(hw, skb); +			goto unlock; +		} + +		if (mlink->wcid) +			wcid = mlink->wcid;  		if (mvif->mt76.roc_phy &&  		    (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) { @@ -868,29 +1245,33 @@ static void mt7996_tx(struct ieee80211_hw *hw,  			if (mphy->roc_link)  				wcid = mphy->roc_link->wcid;  		} else { -			mphy = mt76_vif_link_phy(&mvif->deflink.mt76); +			mphy = mt76_vif_link_phy(mlink);  		}  	} -	if (control->sta) { -		struct mt7996_sta *sta; - -		sta = (struct mt7996_sta *)control->sta->drv_priv; -		wcid = &sta->wcid; -	} -  	if (!mphy) {  		ieee80211_free_txskb(hw, skb); -		return; +		goto unlock;  	} +	if (control->sta && link_id < IEEE80211_LINK_UNSPECIFIED) { +		struct mt7996_sta *msta = (void *)control->sta->drv_priv; +		struct mt7996_sta_link *msta_link; + +		msta_link = rcu_dereference(msta->link[link_id]); +		if (msta_link) +			wcid = &msta_link->wcid; +	}  	mt76_tx(mphy, control->sta, wcid, skb); +unlock: +	rcu_read_unlock();  } -static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, +				    u32 val)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	int i, ret; +	int i, ret = 0;  	mutex_lock(&dev->mt76.mutex); @@ -914,11 +1295,13 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	enum ieee80211_ampdu_mlme_action action = params->action;  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct ieee80211_sta *sta = params->sta; -	struct ieee80211_txq *txq = sta->txq[params->tid];  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct ieee80211_txq *txq = sta->txq[params->tid]; +	struct ieee80211_link_sta *link_sta;  	u16 tid = params->tid;  	u16 ssn = params->ssn;  	struct mt76_txq *mtxq; +	unsigned int link_id;  	int ret = 0;  	if (!txq) @@ -927,38 +1310,61 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	mtxq = (struct mt76_txq *)txq->drv_priv;  	mutex_lock(&dev->mt76.mutex); -	switch (action) { -	case IEEE80211_AMPDU_RX_START: -		mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, -				   params->buf_size); -		ret = mt7996_mcu_add_rx_ba(dev, params, true); -		break; -	case IEEE80211_AMPDU_RX_STOP: -		mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); -		ret = mt7996_mcu_add_rx_ba(dev, params, false); -		break; -	case IEEE80211_AMPDU_TX_OPERATIONAL: -		mtxq->aggr = true; -		mtxq->send_bar = false; -		ret = mt7996_mcu_add_tx_ba(dev, params, true); -		break; -	case IEEE80211_AMPDU_TX_STOP_FLUSH: -	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: -		mtxq->aggr = false; -		clear_bit(tid, &msta->wcid.ampdu_state); -		ret = mt7996_mcu_add_tx_ba(dev, params, false); -		break; -	case IEEE80211_AMPDU_TX_START: -		set_bit(tid, &msta->wcid.ampdu_state); -		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; -		break; -	case IEEE80211_AMPDU_TX_STOP_CONT: -		mtxq->aggr = false; -		clear_bit(tid, &msta->wcid.ampdu_state); -		ret = mt7996_mcu_add_tx_ba(dev, params, false); -		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); -		break; + +	for_each_sta_active_link(vif, sta, link_sta, link_id) { +		struct mt7996_sta_link *msta_link; +		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; + +		switch (action) { +		case IEEE80211_AMPDU_RX_START: +			mt76_rx_aggr_start(&dev->mt76, &msta_link->wcid, tid, +					   ssn, params->buf_size); +			ret = mt7996_mcu_add_rx_ba(dev, params, link, true); +			break; +		case IEEE80211_AMPDU_RX_STOP: +			mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, tid); +			ret = mt7996_mcu_add_rx_ba(dev, params, link, false); +			break; +		case IEEE80211_AMPDU_TX_OPERATIONAL: +			mtxq->aggr = true; +			mtxq->send_bar = false; +			ret = mt7996_mcu_add_tx_ba(dev, params, link, +						   msta_link, true); +			break; +		case IEEE80211_AMPDU_TX_STOP_FLUSH: +		case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: +			mtxq->aggr = false; +			clear_bit(tid, &msta_link->wcid.ampdu_state); +			ret = mt7996_mcu_add_tx_ba(dev, params, link, +						   msta_link, false); +			break; +		case IEEE80211_AMPDU_TX_START: +			set_bit(tid, &msta_link->wcid.ampdu_state); +			ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; +			break; +		case IEEE80211_AMPDU_TX_STOP_CONT: +			mtxq->aggr = false; +			clear_bit(tid, &msta_link->wcid.ampdu_state); +			ret = mt7996_mcu_add_tx_ba(dev, params, link, +						   msta_link, false); +			break; +		} + +		if (ret) +			break;  	} + +	if (action == IEEE80211_AMPDU_TX_STOP_CONT) +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +  	mutex_unlock(&dev->mt76.mutex);  	return ret; @@ -989,10 +1395,10 @@ mt7996_get_stats(struct ieee80211_hw *hw,  	return 0;  } -u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) +u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); +	struct mt7996_phy *phy = link->phy;  	union {  		u64 t64;  		u32 t32[2]; @@ -1004,8 +1410,8 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif)  	lockdep_assert_held(&dev->mt76.mutex); -	n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 -					       : mvif->deflink.mt76.omac_idx; +	n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 +					       : link->mt76.omac_idx;  	/* TSF software read */  	mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE,  		 MT_LPON_TCR_SW_READ); @@ -1023,7 +1429,7 @@ mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  	u64 ret;  	mutex_lock(&dev->mt76.mutex); -	ret = __mt7996_get_tsf(hw, mvif); +	ret = __mt7996_get_tsf(hw, &mvif->deflink);  	mutex_unlock(&dev->mt76.mutex);  	return ret; @@ -1035,26 +1441,33 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  {  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); +	struct mt7996_vif_link *link; +	struct mt7996_phy *phy;  	union {  		u64 t64;  		u32 t32[2];  	} tsf = { .t64 = timestamp, };  	u16 n; -	if (!phy) -		return; -  	mutex_lock(&dev->mt76.mutex); -	n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 -					       : mvif->deflink.mt76.omac_idx; +	link = mt7996_vif_link(dev, vif, mvif->mt76.deflink_id); +	if (!link) +		goto unlock; + +	n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 +					       : link->mt76.omac_idx; +	phy = link->phy; +	if (!phy) +		goto unlock; +  	mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);  	mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]);  	/* TSF software overwrite */  	mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE,  		 MT_LPON_TCR_SW_WRITE); +unlock:  	mutex_unlock(&dev->mt76.mutex);  } @@ -1064,31 +1477,39 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  {  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_dev *dev = mt7996_hw_dev(hw); -	struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); +	struct mt7996_vif_link *link; +	struct mt7996_phy *phy;  	union {  		u64 t64;  		u32 t32[2];  	} tsf = { .t64 = timestamp, };  	u16 n; -	if (!phy) -		return; -  	mutex_lock(&dev->mt76.mutex); -	n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 -					       : mvif->deflink.mt76.omac_idx; +	link = mt7996_vif_link(dev, vif, mvif->mt76.deflink_id); +	if (!link) +		goto unlock; + +	phy = link->phy; +	if (!phy) +		goto unlock; + +	n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 +					       : link->mt76.omac_idx;  	mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);  	mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]);  	/* TSF software adjust*/  	mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE,  		 MT_LPON_TCR_SW_ADJUST); +unlock:  	mutex_unlock(&dev->mt76.mutex);  }  static void -mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +mt7996_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, +			  s16 coverage_class)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mt7996_phy *phy; @@ -1102,7 +1523,8 @@ mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)  }  static int -mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7996_set_antenna(struct ieee80211_hw *hw, int radio_idx, +		   u32 tx_ant, u32 rx_ant)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	int i; @@ -1125,7 +1547,8 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)  		u8 shift = dev->chainshift[band_idx];  		phy->mt76->chainmask = tx_ant & phy->orig_chainmask; -		phy->mt76->antenna_mask = phy->mt76->chainmask >> shift; +		phy->mt76->antenna_mask = (phy->mt76->chainmask >> shift) & +					  phy->orig_antenna_mask;  		mt76_set_stream_caps(phy->mt76, true);  		mt7996_set_stream_vht_txbf_caps(phy); @@ -1145,7 +1568,8 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; -	struct rate_info *txrate = &msta->wcid.rate; +	struct mt7996_sta_link *msta_link = &msta->deflink; +	struct rate_info *txrate = &msta_link->wcid.rate;  	if (txrate->legacy || txrate->flags) {  		if (txrate->legacy) { @@ -1165,55 +1589,67 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,  	sinfo->txrate.flags = txrate->flags;  	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); -	sinfo->tx_failed = msta->wcid.stats.tx_failed; +	sinfo->tx_failed = msta_link->wcid.stats.tx_failed;  	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); -	sinfo->tx_retries = msta->wcid.stats.tx_retries; +	sinfo->tx_retries = msta_link->wcid.stats.tx_retries;  	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); -	sinfo->ack_signal = (s8)msta->ack_signal; +	sinfo->ack_signal = (s8)msta_link->ack_signal;  	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); -	sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); +	sinfo->avg_ack_signal = +		-(s8)ewma_avg_signal_read(&msta_link->avg_ack_signal);  	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);  	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { -		sinfo->tx_bytes = msta->wcid.stats.tx_bytes; +		sinfo->tx_bytes = msta_link->wcid.stats.tx_bytes;  		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); -		sinfo->rx_bytes = msta->wcid.stats.rx_bytes; +		sinfo->rx_bytes = msta_link->wcid.stats.rx_bytes;  		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); -		sinfo->tx_packets = msta->wcid.stats.tx_packets; +		sinfo->tx_packets = msta_link->wcid.stats.tx_packets;  		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); -		sinfo->rx_packets = msta->wcid.stats.rx_packets; +		sinfo->rx_packets = msta_link->wcid.stats.rx_packets;  		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);  	}  } -static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) +static void mt7996_link_rate_ctrl_update(void *data, struct ieee80211_sta *sta)  {  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;  	struct mt7996_dev *dev = msta->vif->deflink.phy->dev; +	struct mt7996_sta_link *msta_link;  	u32 *changed = data; +	rcu_read_lock(); + +	msta_link = rcu_dereference(msta->link[msta->deflink_id]); +	if (!msta_link) +		goto out; +  	spin_lock_bh(&dev->mt76.sta_poll_lock); -	msta->changed |= *changed; -	if (list_empty(&msta->rc_list)) -		list_add_tail(&msta->rc_list, &dev->sta_rc_list); + +	msta_link->changed |= *changed; +	if (list_empty(&msta_link->rc_list)) +		list_add_tail(&msta_link->rc_list, &dev->sta_rc_list); +  	spin_unlock_bh(&dev->mt76.sta_poll_lock); +out: +	rcu_read_unlock();  } -static void mt7996_sta_rc_update(struct ieee80211_hw *hw, -				 struct ieee80211_vif *vif, -				 struct ieee80211_link_sta *link_sta, -				 u32 changed) +static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw, +				      struct ieee80211_vif *vif, +				      struct ieee80211_link_sta *link_sta, +				      u32 changed)  {  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct ieee80211_sta *sta = link_sta->sta; -	mt7996_sta_rc_work(&changed, sta); +	mt7996_link_rate_ctrl_update(&changed, sta);  	ieee80211_queue_work(hw, &dev->rc_work);  } @@ -1235,7 +1671,8 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	 * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT  	 * then multiple MCS setting (MCS 4,5,6) is not supported.  	 */ -	ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); +	ieee80211_iterate_stations_atomic(hw, mt7996_link_rate_ctrl_update, +					  &changed);  	ieee80211_queue_work(hw, &dev->rc_work);  	return 0; @@ -1246,18 +1683,37 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,  				 struct ieee80211_sta *sta,  				 bool enabled)  { -	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	struct ieee80211_link_sta *link_sta; +	unsigned int link_id; -	if (enabled) -		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); -	else -		clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); +	mutex_lock(&dev->mt76.mutex); -	if (!msta->wcid.sta) -		return; +	for_each_sta_active_link(vif, sta, link_sta, link_id) { +		struct mt7996_sta_link *msta_link; +		struct mt7996_vif_link *link; -	mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; + +		msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); +		if (!msta_link) +			continue; + +		if (enabled) +			set_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags); +		else +			clear_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags); + +		if (!msta_link->wcid.sta) +			continue; + +		mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, msta_link); +	} + +	mutex_unlock(&dev->mt76.mutex);  }  static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, @@ -1265,18 +1721,39 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,  					 struct ieee80211_sta *sta,  					 bool enabled)  { -	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt7996_dev *dev = mt7996_hw_dev(hw); +	struct ieee80211_link_sta *link_sta; +	unsigned int link_id; -	if (enabled) -		set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); -	else -		clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); +	mutex_lock(&dev->mt76.mutex); -	if (!msta->wcid.sta) -		return; +	for_each_sta_active_link(vif, sta, link_sta, link_id) { +		struct mt7996_sta_link *msta_link; +		struct mt7996_vif_link *link; + +		link = mt7996_vif_link(dev, vif, link_id); +		if (!link) +			continue; + +		msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); +		if (!msta_link) +			continue; -	mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); +		if (enabled) +			set_bit(MT_WCID_FLAG_HDR_TRANS, +				&msta_link->wcid.flags); +		else +			clear_bit(MT_WCID_FLAG_HDR_TRANS, +				  &msta_link->wcid.flags); + +		if (!msta_link->wcid.sta) +			continue; + +		mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, msta_link); +	} + +	mutex_unlock(&dev->mt76.mutex);  }  static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { @@ -1408,11 +1885,12 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)  {  	struct mt76_ethtool_worker_info *wi = wi_data;  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt7996_sta_link *msta_link = &msta->deflink;  	if (msta->vif->deflink.mt76.idx != wi->idx)  		return; -	mt76_ethtool_worker(wi, &msta->wcid.stats, true); +	mt76_ethtool_worker(wi, &msta_link->wcid.stats, true);  }  static @@ -1516,10 +1994,12 @@ mt7996_twt_teardown_request(struct ieee80211_hw *hw,  			    u8 flowid)  {  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; +	struct mt7996_sta_link *msta_link = &msta->deflink; +	struct mt7996_vif_link *link = &msta->vif->deflink;  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	mutex_lock(&dev->mt76.mutex); -	mt7996_mac_twt_teardown_flow(dev, msta, flowid); +	mt7996_mac_twt_teardown_flow(dev, link, msta_link, flowid);  	mutex_unlock(&dev->mt76.mutex);  } @@ -1589,12 +2069,26 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,  {  	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; -	struct mt7996_vif_link *mlink = &mvif->deflink;  	struct mt7996_dev *dev = mt7996_hw_dev(hw);  	struct mtk_wed_device *wed = &dev->mt76.mmio.wed; +	struct mt7996_sta_link *msta_link; +	struct mt7996_vif_link *link; +	struct mt76_vif_link *mlink;  	struct mt7996_phy *phy; -	phy = mt7996_vif_link_phy(mlink); +	mlink = rcu_dereference(mvif->mt76.link[msta->deflink_id]); +	if (!mlink) +		return -EIO; + +	msta_link = rcu_dereference(msta->link[msta->deflink_id]); +	if (!msta_link) +		return -EIO; + +	if (!msta_link->wcid.sta || msta_link->wcid.idx > MT7996_WTBL_STA) +		return -EIO; + +	link = (struct mt7996_vif_link *)mlink; +	phy = mt7996_vif_link_phy(link);  	if (!phy)  		return -ENODEV; @@ -1604,15 +2098,12 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,  	if (!mtk_wed_device_active(wed))  		return -ENODEV; -	if (!msta->wcid.sta || msta->wcid.idx > MT7996_WTBL_STA) -		return -EIO; -  	path->type = DEV_PATH_MTK_WDMA;  	path->dev = ctx->dev;  	path->mtk_wdma.wdma_idx = wed->wdma_idx; -	path->mtk_wdma.bss = mvif->deflink.mt76.idx; +	path->mtk_wdma.bss = mlink->idx;  	path->mtk_wdma.queue = 0; -	path->mtk_wdma.wcid = msta->wcid.idx; +	path->mtk_wdma.wcid = msta_link->wcid.idx;  	path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed);  	ctx->dev = NULL; @@ -1622,6 +2113,14 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,  #endif +static int +mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			u16 old_links, u16 new_links, +			struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) +{ +	return 0; +} +  const struct ieee80211_ops mt7996_ops = {  	.add_chanctx = mt76_add_chanctx,  	.remove_chanctx = mt76_remove_chanctx, @@ -1637,10 +2136,11 @@ const struct ieee80211_ops mt7996_ops = {  	.config = mt7996_config,  	.conf_tx = mt7996_conf_tx,  	.configure_filter = mt7996_configure_filter, -	.bss_info_changed = mt7996_bss_info_changed, -	.sta_state = mt76_sta_state, +	.vif_cfg_changed = mt7996_vif_cfg_changed, +	.link_info_changed = mt7996_link_info_changed, +	.sta_state = mt7996_sta_state,  	.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, -	.link_sta_rc_update = mt7996_sta_rc_update, +	.link_sta_rc_update = mt7996_link_sta_rc_update,  	.set_key = mt7996_set_key,  	.ampdu_action = mt7996_ampdu_action,  	.set_rts_threshold = mt7996_set_rts_threshold, @@ -1650,7 +2150,7 @@ const struct ieee80211_ops mt7996_ops = {  	.remain_on_channel = mt76_remain_on_channel,  	.cancel_remain_on_channel = mt76_cancel_remain_on_channel,  	.release_buffered_frames = mt76_release_buffered_frames, -	.get_txpower = mt76_get_txpower, +	.get_txpower = mt7996_get_txpower,  	.channel_switch_beacon = mt7996_channel_switch_beacon,  	.get_stats = mt7996_get_stats,  	.get_et_sset_count = mt7996_get_et_sset_count, @@ -1677,4 +2177,6 @@ const struct ieee80211_ops mt7996_ops = {  	.net_fill_forward_path = mt7996_net_fill_forward_path,  	.net_setup_tc = mt76_wed_net_setup_tc,  #endif +	.change_vif_links = mt7996_change_vif_links, +	.change_sta_links = mt7996_mac_sta_change_links,  }; | 
