diff options
Diffstat (limited to 'sys/contrib/dev/mediatek/mt76/mt7996/mac.c')
| -rw-r--r-- | sys/contrib/dev/mediatek/mt76/mt7996/mac.c | 492 | 
1 files changed, 303 insertions, 189 deletions
diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c index 3f1536f2bbe7..13ea5b55d619 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c @@ -56,26 +56,45 @@ static const struct mt7996_dfs_radar_spec jp_radar_specs = {  };  static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, -					    u16 idx, bool unicast) +					    u16 idx, u8 band_idx)  { -	struct mt7996_sta *sta; +	struct mt7996_sta_link *msta_link; +	struct mt7996_sta *msta; +	struct mt7996_vif *mvif;  	struct mt76_wcid *wcid; +	int i; + +	wcid = mt76_wcid_ptr(dev, idx); +	if (!wcid || !wcid->sta) +		return NULL; -	if (idx >= ARRAY_SIZE(dev->mt76.wcid)) +	if (!mt7996_band_valid(dev, band_idx))  		return NULL; -	wcid = rcu_dereference(dev->mt76.wcid[idx]); -	if (unicast || !wcid) +	if (wcid->phy_idx == band_idx)  		return wcid; -	if (!wcid->sta) +	msta_link = container_of(wcid, struct mt7996_sta_link, wcid); +	msta = msta_link->sta; +	if (!msta || !msta->vif)  		return NULL; -	sta = container_of(wcid, struct mt7996_sta, wcid); -	if (!sta->vif) -		return NULL; +	mvif = msta->vif; +	for (i = 0; i < ARRAY_SIZE(mvif->mt76.link); i++) { +		struct mt76_vif_link *mlink; + +		mlink = rcu_dereference(mvif->mt76.link[i]); +		if (!mlink) +			continue; + +		if (mlink->band_idx != band_idx) +			continue; + +		msta_link = rcu_dereference(msta->link[i]); +		break; +	} -	return &sta->vif->deflink.sta.wcid; +	return &msta_link->wcid;  }  bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask) @@ -103,10 +122,13 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)  		[IEEE80211_AC_VI] = 4,  		[IEEE80211_AC_VO] = 6  	}; +	struct mt7996_sta_link *msta_link; +	struct mt76_vif_link *mlink;  	struct ieee80211_sta *sta;  	struct mt7996_sta *msta;  	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];  	LIST_HEAD(sta_poll_list); +	struct mt76_wcid *wcid;  	int i;  	spin_lock_bh(&dev->mt76.sta_poll_lock); @@ -126,25 +148,28 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)  			spin_unlock_bh(&dev->mt76.sta_poll_lock);  			break;  		} -		msta = list_first_entry(&sta_poll_list, -					struct mt7996_sta, wcid.poll_list); -		list_del_init(&msta->wcid.poll_list); +		msta_link = list_first_entry(&sta_poll_list, +					     struct mt7996_sta_link, +					     wcid.poll_list); +		msta = msta_link->sta; +		wcid = &msta_link->wcid; +		list_del_init(&wcid->poll_list);  		spin_unlock_bh(&dev->mt76.sta_poll_lock); -		idx = msta->wcid.idx; +		idx = wcid->idx;  		/* refresh peer's airtime reporting */  		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);  		for (i = 0; i < IEEE80211_NUM_ACS; i++) { -			u32 tx_last = msta->airtime_ac[i]; -			u32 rx_last = msta->airtime_ac[i + 4]; +			u32 tx_last = msta_link->airtime_ac[i]; +			u32 rx_last = msta_link->airtime_ac[i + 4]; -			msta->airtime_ac[i] = mt76_rr(dev, addr); -			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); +			msta_link->airtime_ac[i] = mt76_rr(dev, addr); +			msta_link->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); -			tx_time[i] = msta->airtime_ac[i] - tx_last; -			rx_time[i] = msta->airtime_ac[i + 4] - rx_last; +			tx_time[i] = msta_link->airtime_ac[i] - tx_last; +			rx_time[i] = msta_link->airtime_ac[i + 4] - rx_last;  			if ((tx_last | rx_last) & BIT(30))  				clear = true; @@ -155,10 +180,11 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)  		if (clear) {  			mt7996_mac_wtbl_update(dev, idx,  					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR); -			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); +			memset(msta_link->airtime_ac, 0, +			       sizeof(msta_link->airtime_ac));  		} -		if (!msta->wcid.sta) +		if (!wcid->sta)  			continue;  		sta = container_of((void *)msta, struct ieee80211_sta, @@ -184,28 +210,23 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)  		rssi[2] = to_rssi(GENMASK(23, 16), val);  		rssi[3] = to_rssi(GENMASK(31, 14), val); -		msta->ack_signal = -			mt76_rx_signal(msta->vif->deflink.phy->mt76->antenna_mask, rssi); +		mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]); +		if (mlink) { +			struct mt76_phy *mphy = mt76_vif_link_phy(mlink); + +			if (mphy) +				msta_link->ack_signal = +					mt76_rx_signal(mphy->antenna_mask, +						       rssi); +		} -		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); +		ewma_avg_signal_add(&msta_link->avg_ack_signal, +				    -msta_link->ack_signal);  	}  	rcu_read_unlock();  } -void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, -			      struct ieee80211_vif *vif, bool enable) -{ -	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; -	u32 addr; - -	addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->deflink.sta.wcid.idx, 5); -	if (enable) -		mt76_set(dev, addr, BIT(5)); -	else -		mt76_clear(dev, addr, BIT(5)); -} -  /* The HW does not translate the mac header to 802.3 for mesh point */  static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)  { @@ -477,11 +498,15 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,  	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;  	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); -	status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); +	status->wcid = mt7996_rx_get_wcid(dev, idx, band_idx);  	if (status->wcid) { -		msta = container_of(status->wcid, struct mt7996_sta, wcid); -		mt76_wcid_add_poll(&dev->mt76, &msta->wcid); +		struct mt7996_sta_link *msta_link; + +		msta_link = container_of(status->wcid, struct mt7996_sta_link, +					 wcid); +		msta = msta_link->sta; +		mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);  	}  	status->freq = mphy->chandef.chan->center_freq; @@ -622,6 +647,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,  		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;  	} +	/* IEEE 802.11 fragmentation can only be applied to unicast frames. +	 * Hence, drop fragments with multicast/broadcast RA. +	 * This check fixes vulnerabilities, like CVE-2020-26145. +	 */ +	if ((ieee80211_has_morefrags(fc) || seq_ctrl & IEEE80211_SCTL_FRAG) && +	    FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) != MT_RXD3_NORMAL_U2M) +		return -EINVAL; +  	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;  	if (hdr_trans && ieee80211_has_morefrags(fc)) {  		if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap)) @@ -720,9 +753,8 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,  	u32 val;  	if (wcid->sta) { -		struct ieee80211_sta *sta; +		struct ieee80211_sta *sta = wcid_to_sta(wcid); -		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);  		wmm = sta->wme;  	} @@ -749,7 +781,9 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,  static void  mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, -			    struct sk_buff *skb, struct ieee80211_key_conf *key) +			    struct sk_buff *skb, +			    struct ieee80211_key_conf *key, +			    struct mt76_wcid *wcid)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; @@ -757,15 +791,19 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,  	bool multicast = is_multicast_ether_addr(hdr->addr1);  	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;  	__le16 fc = hdr->frame_control, sc = hdr->seq_ctrl; +	u16 seqno = le16_to_cpu(sc);  	u8 fc_type, fc_stype;  	u32 val;  	if (ieee80211_is_action(fc) &&  	    mgmt->u.action.category == WLAN_CATEGORY_BACK && -	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) +	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { +		if (is_mt7990(&dev->mt76)) +			txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TID_ADDBA, tid));  		tid = MT_TX_ADDBA; -	else if (ieee80211_is_mgmt(hdr->frame_control)) +	} else if (ieee80211_is_mgmt(hdr->frame_control)) {  		tid = MT_TX_NORMAL; +	}  	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |  	      FIELD_PREP(MT_TXD1_HDR_INFO, @@ -776,8 +814,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,  	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)  		val |= MT_TXD1_FIXED_RATE; -	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && -	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { +	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb)) {  		val |= MT_TXD1_BIP;  		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);  	} @@ -807,9 +844,13 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,  		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);  	} -	if (info->flags & IEEE80211_TX_CTL_INJECTED) { -		u16 seqno = le16_to_cpu(sc); +	if (multicast && ieee80211_vif_is_mld(info->control.vif)) { +		val = MT_TXD3_SN_VALID | +		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); +		txwi[3] |= cpu_to_le32(val); +	} +	if (info->flags & IEEE80211_TX_CTL_INJECTED) {  		if (ieee80211_is_back_req(hdr->frame_control)) {  			struct ieee80211_bar *bar; @@ -822,6 +863,19 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,  		txwi[3] |= cpu_to_le32(val);  		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);  	} + +	if (ieee80211_vif_is_mld(info->control.vif) && +	    (multicast || unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))) +		txwi[5] |= cpu_to_le32(MT_TXD5_FL); + +	if (ieee80211_is_nullfunc(fc) && ieee80211_has_a4(fc) && +	    ieee80211_vif_is_mld(info->control.vif)) { +		txwi[5] |= cpu_to_le32(MT_TXD5_FL); +		txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT); +	} + +	if (!wcid->sta && ieee80211_is_mgmt(fc)) +		txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT);  }  void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, @@ -835,7 +889,9 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,  	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;  	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;  	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; -	struct mt76_vif_link *mvif; +	struct mt76_vif_link *mlink = NULL; +	struct mt7996_vif *mvif; +	unsigned int link_id;  	u16 tx_count = 15;  	u32 val;  	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | @@ -843,11 +899,24 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,  	bool beacon = !!(changed & (BSS_CHANGED_BEACON |  				    BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); -	mvif = vif ? (struct mt76_vif_link *)vif->drv_priv : NULL; +	if (wcid != &dev->mt76.global_wcid) +		link_id = wcid->link_id; +	else +		link_id = u32_get_bits(info->control.flags, +				       IEEE80211_TX_CTRL_MLO_LINK); + +	mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;  	if (mvif) { -		omac_idx = mvif->omac_idx; -		wmm_idx = mvif->wmm_idx; -		band_idx = mvif->band_idx; +		if (wcid->offchannel) +			mlink = rcu_dereference(mvif->mt76.offchannel_link); +		if (!mlink) +			mlink = rcu_dereference(mvif->mt76.link[link_id]); +	} + +	if (mlink) { +		omac_idx = mlink->omac_idx; +		wmm_idx = mlink->wmm_idx; +		band_idx = mlink->band_idx;  	}  	if (inband_disc) { @@ -894,7 +963,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,  		val |= MT_TXD5_TX_STATUS_HOST;  	txwi[5] = cpu_to_le32(val); -	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS; +	val = MT_TXD6_DAS; +	if (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) +		val |= MT_TXD6_DIS_MAT; +  	if (is_mt7996(&dev->mt76))  		val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1);  	else if (is_8023 || !ieee80211_is_mgmt(hdr->frame_control)) @@ -906,34 +978,56 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,  	if (is_8023)  		mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);  	else -		mt7996_mac_write_txwi_80211(dev, txwi, skb, key); +		mt7996_mac_write_txwi_80211(dev, txwi, skb, key, wcid);  	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {  		bool mcast = ieee80211_is_data(hdr->frame_control) &&  			     is_multicast_ether_addr(hdr->addr1);  		u8 idx = MT7996_BASIC_RATES_TBL; -		if (mvif) { -			if (mcast && mvif->mcast_rates_idx) -				idx = mvif->mcast_rates_idx; -			else if (beacon && mvif->beacon_rates_idx) -				idx = mvif->beacon_rates_idx; +		if (mlink) { +			if (mcast && mlink->mcast_rates_idx) +				idx = mlink->mcast_rates_idx; +			else if (beacon && mlink->beacon_rates_idx) +				idx = mlink->beacon_rates_idx;  			else -				idx = mvif->basic_rates_idx; +				idx = mlink->basic_rates_idx;  		}  		val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW; +		if (mcast) +			val |= MT_TXD6_DIS_MAT;  		txwi[6] |= cpu_to_le32(val);  		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);  	}  } +static bool +mt7996_tx_use_mgmt(struct mt7996_dev *dev, struct sk_buff *skb) +{ +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + +	if (ieee80211_is_mgmt(hdr->frame_control)) +		return true; + +	/* for SDO to bypass specific data frame */ +	if (!mt7996_has_wa(dev)) { +		if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) +			return true; + +		if (ieee80211_has_a4(hdr->frame_control) && +		    !ieee80211_is_data_present(hdr->frame_control)) +			return true; +	} + +	return false; +} +  int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,  			  enum mt76_txq_id qid, struct mt76_wcid *wcid,  			  struct ieee80211_sta *sta,  			  struct mt76_tx_info *tx_info)  { -	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;  	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);  	struct ieee80211_key_conf *key = info->control.hw_key; @@ -958,8 +1052,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,  		return id;  	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); -	mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, -			      pid, qid, 0); +	memset(txwi_ptr, 0, MT_TXD_SIZE); +	/* Transmit non qos data by 802.11 header and need to fill txd by host*/ +	if (!is_8023 || pid >= MT_PACKET_ID_FIRST) +		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, +				      pid, qid, 0);  	txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);  	for (i = 0; i < nbuf; i++) { @@ -976,19 +1073,27 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,  	}  	txp->fw.nbuf = nbuf; -	txp->fw.flags = -		cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD); +	txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST); + +	if (!is_8023 || pid >= MT_PACKET_ID_FIRST) +		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);  	if (!key)  		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); -	if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control)) +	if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb))  		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);  	if (vif) {  		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +		struct mt76_vif_link *mlink = NULL; + +		if (wcid->offchannel) +			mlink = rcu_dereference(mvif->mt76.offchannel_link); +		if (!mlink) +			mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]); -		txp->fw.bss_idx = mvif->deflink.mt76.idx; +		txp->fw.bss_idx = mlink ? mlink->idx : mvif->deflink.mt76.idx;  	}  	txp->fw.token = cpu_to_le16(id); @@ -1032,14 +1137,14 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)  }  static void -mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) +mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, +		     struct mt76_wcid *wcid, struct sk_buff *skb)  { -	struct mt7996_sta *msta;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;  	u16 fc, tid; -	if (!sta || !(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;  	tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; @@ -1048,7 +1153,8 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)  	if (is_8023) {  		fc = IEEE80211_FTYPE_DATA | -		     (sta->wme ? IEEE80211_STYPE_QOS_DATA : IEEE80211_STYPE_DATA); +		     (link_sta->sta->wme ? IEEE80211_STYPE_QOS_DATA +					 : IEEE80211_STYPE_DATA);  	} else {  		/* No need to get precise TID for Action/Management Frame,  		 * since it will not meet the following Frame Control @@ -1064,17 +1170,16 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)  	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))  		return; -	msta = (struct mt7996_sta *)sta->drv_priv; -	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state)) -		ieee80211_start_tx_ba_session(sta, tid, 0); +	if (!test_and_set_bit(tid, &wcid->ampdu_state)) +		ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);  }  static void  mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, -		 struct ieee80211_sta *sta, struct list_head *free_list) +		 struct ieee80211_link_sta *link_sta, +		 struct mt76_wcid *wcid, struct list_head *free_list)  {  	struct mt76_dev *mdev = &dev->mt76; -	struct mt76_wcid *wcid;  	__le32 *txwi;  	u16 wcid_idx; @@ -1083,12 +1188,10 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,  		goto out;  	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); -	if (sta) { -		wcid = (struct mt76_wcid *)sta->drv_priv; +	if (link_sta) {  		wcid_idx = wcid->idx; -  		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) -			mt7996_tx_check_aggr(sta, t->skb); +			mt7996_tx_check_aggr(link_sta, wcid, t->skb);  	} else {  		wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);  	} @@ -1107,8 +1210,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)  	struct mt76_dev *mdev = &dev->mt76;  	struct mt76_phy *phy2 = mdev->phys[MT_BAND1];  	struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; +	struct ieee80211_link_sta *link_sta = NULL;  	struct mt76_txwi_cache *txwi; -	struct ieee80211_sta *sta = NULL;  	struct mt76_wcid *wcid = NULL;  	LIST_HEAD(free_list);  	struct sk_buff *skb, *tmp; @@ -1119,6 +1222,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)  #endif  	bool wake = false;  	u16 total, count = 0; +	u8 ver;  	/* clean DMA queues and unmap buffers first */  	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); @@ -1132,7 +1236,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)  		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);  	} -	if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 5)) +	ver = le32_get_bits(tx_free[1], MT_TXFREE1_VER); +	if (WARN_ON_ONCE(ver < 5))  		return;  	total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT); @@ -1147,17 +1252,27 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)  		 */  		info = le32_to_cpu(*cur_info);  		if (info & MT_TXFREE_INFO_PAIR) { -			struct mt7996_sta *msta; +			struct ieee80211_sta *sta;  			u16 idx;  			idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); -			wcid = rcu_dereference(dev->mt76.wcid[idx]); +			wcid = mt76_wcid_ptr(dev, idx);  			sta = wcid_to_sta(wcid); -			if (!sta) -				continue; +			if (!sta) { +				link_sta = NULL; +				goto next; +			} -			msta = container_of(wcid, struct mt7996_sta, wcid); -			mt76_wcid_add_poll(&dev->mt76, &msta->wcid); +			link_sta = rcu_dereference(sta->link[wcid->link_id]); +			if (!link_sta) +				goto next; + +			mt76_wcid_add_poll(&dev->mt76, wcid); +next: +			/* ver 7 has a new DW with pair = 1, skip it */ +			if (ver == 7 && ((void *)(cur_info + 1) < end) && +			    (le32_to_cpu(*(cur_info + 1)) & MT_TXFREE_INFO_PAIR)) +				cur_info++;  			continue;  		} else if (info & MT_TXFREE_INFO_HEADER) {  			u32 tx_retries = 0, tx_failed = 0; @@ -1185,7 +1300,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)  			if (!txwi)  				continue; -			mt7996_txwi_free(dev, txwi, sta, &free_list); +			mt7996_txwi_free(dev, txwi, link_sta, wcid, +					 &free_list);  		}  	} @@ -1241,7 +1357,7 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,  		struct ieee80211_sta *sta;  		u8 tid; -		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); +		sta = wcid_to_sta(wcid);  		tid = FIELD_GET(MT_TXS0_TID, txs);  		ieee80211_refresh_tx_agg_session_timer(sta, tid);  	} @@ -1355,7 +1471,7 @@ out:  static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)  { -	struct mt7996_sta *msta = NULL; +	struct mt7996_sta_link *msta_link;  	struct mt76_wcid *wcid;  	__le32 *txs_data = data;  	u16 wcidx; @@ -1367,23 +1483,19 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)  	if (pid < MT_PACKET_ID_NO_SKB)  		return; -	if (wcidx >= mt7996_wtbl_size(dev)) -		return; -  	rcu_read_lock(); -	wcid = rcu_dereference(dev->mt76.wcid[wcidx]); +	wcid = mt76_wcid_ptr(dev, wcidx);  	if (!wcid)  		goto out; -	msta = container_of(wcid, struct mt7996_sta, wcid); -  	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);  	if (!wcid->sta)  		goto out; -	mt76_wcid_add_poll(&dev->mt76, &msta->wcid); +	msta_link = container_of(wcid, struct mt7996_sta_link, wcid); +	mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);  out:  	rcu_read_unlock(); @@ -1410,7 +1522,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)  		mt7996_mac_tx_free(dev, data, len);  		return false;  	case PKT_TYPE_TXS: -		for (rxd += 4; rxd + 8 <= end; rxd += 8) +		for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)  			mt7996_mac_add_txs(dev, rxd);  		return false;  	case PKT_TYPE_RX_FW_MONITOR: @@ -1455,7 +1567,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,  		mt7996_mcu_rx_event(dev, skb);  		break;  	case PKT_TYPE_TXS: -		for (rxd += 4; rxd + 8 <= end; rxd += 8) +		for (rxd += MT_TXS_HDR_SIZE; rxd + MT_TXS_SIZE <= end; rxd += MT_TXS_SIZE)  			mt7996_mac_add_txs(dev, rxd);  		dev_kfree_skb(skb);  		break; @@ -1603,43 +1715,53 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)  static void  mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)  { -	struct ieee80211_hw *hw = priv; +	struct ieee80211_bss_conf *link_conf; +	struct mt7996_phy *phy = priv; +	struct mt7996_dev *dev = phy->dev; +	unsigned int link_id; +  	switch (vif->type) {  	case NL80211_IFTYPE_MESH_POINT:  	case NL80211_IFTYPE_ADHOC:  	case NL80211_IFTYPE_AP: -		mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf);  		break;  	default: -		break; +		return; +	} + +	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 || link->phy != phy) +			continue; + +		mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf);  	}  } +void mt7996_mac_update_beacons(struct mt7996_phy *phy) +{ +	ieee80211_iterate_active_interfaces(phy->mt76->hw, +					    IEEE80211_IFACE_ITER_RESUME_ALL, +					    mt7996_update_vif_beacon, phy); +} +  static void  mt7996_update_beacons(struct mt7996_dev *dev)  {  	struct mt76_phy *phy2, *phy3; -	ieee80211_iterate_active_interfaces(dev->mt76.hw, -					    IEEE80211_IFACE_ITER_RESUME_ALL, -					    mt7996_update_vif_beacon, dev->mt76.hw); +	mt7996_mac_update_beacons(&dev->phy);  	phy2 = dev->mt76.phys[MT_BAND1]; -	if (!phy2) -		return; - -	ieee80211_iterate_active_interfaces(phy2->hw, -					    IEEE80211_IFACE_ITER_RESUME_ALL, -					    mt7996_update_vif_beacon, phy2->hw); +	if (phy2) +		mt7996_mac_update_beacons(phy2->priv);  	phy3 = dev->mt76.phys[MT_BAND2]; -	if (!phy3) -		return; - -	ieee80211_iterate_active_interfaces(phy3->hw, -					    IEEE80211_IFACE_ITER_RESUME_ALL, -					    mt7996_update_vif_beacon, phy3->hw); +	if (phy3) +		mt7996_mac_update_beacons(phy3->priv);  }  void mt7996_tx_token_put(struct mt7996_dev *dev) @@ -1649,7 +1771,7 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)  	spin_lock_bh(&dev->mt76.token_lock);  	idr_for_each_entry(&dev->mt76.token, txwi, id) { -		mt7996_txwi_free(dev, txwi, NULL, NULL); +		mt7996_txwi_free(dev, txwi, NULL, NULL, NULL);  		dev->mt76.token_count--;  	}  	spin_unlock_bh(&dev->mt76.token_lock); @@ -2254,32 +2376,38 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)  void mt7996_mac_sta_rc_work(struct work_struct *work)  {  	struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work); -	struct ieee80211_sta *sta; +	struct mt7996_sta_link *msta_link;  	struct ieee80211_vif *vif; -	struct mt7996_sta *msta; -	u32 changed; +	struct mt7996_vif *mvif;  	LIST_HEAD(list); +	u32 changed;  	spin_lock_bh(&dev->mt76.sta_poll_lock);  	list_splice_init(&dev->sta_rc_list, &list);  	while (!list_empty(&list)) { -		msta = list_first_entry(&list, struct mt7996_sta, rc_list); -		list_del_init(&msta->rc_list); -		changed = msta->changed; -		msta->changed = 0; -		spin_unlock_bh(&dev->mt76.sta_poll_lock); +		msta_link = list_first_entry(&list, struct mt7996_sta_link, +					     rc_list); +		list_del_init(&msta_link->rc_list); + +		changed = msta_link->changed; +		msta_link->changed = 0; +		mvif = msta_link->sta->vif; +		vif = container_of((void *)mvif, struct ieee80211_vif, +				   drv_priv); -		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); -		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); +		spin_unlock_bh(&dev->mt76.sta_poll_lock);  		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |  			       IEEE80211_RC_NSS_CHANGED |  			       IEEE80211_RC_BW_CHANGED)) -			mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); +			mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif, +						 msta_link->wcid.link_id, +						 true);  		if (changed & IEEE80211_RC_SMPS_CHANGED) -			mt7996_mcu_set_fixed_field(dev, vif, sta, NULL, +			mt7996_mcu_set_fixed_field(dev, msta_link->sta, NULL, +						   msta_link->wcid.link_id,  						   RATE_PARAM_MMPS_UPDATE);  		spin_lock_bh(&dev->mt76.sta_poll_lock); @@ -2323,16 +2451,15 @@ void mt7996_mac_work(struct work_struct *work)  static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)  {  	struct mt7996_dev *dev = phy->dev; +	int rdd_idx = mt7996_get_rdd_idx(phy, false); -	if (phy->rdd_state & BIT(0)) -		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0, -				   MT_RX_SEL0, 0); -	if (phy->rdd_state & BIT(1)) -		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1, -				   MT_RX_SEL0, 0); +	if (rdd_idx < 0) +		return; + +	mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0);  } -static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain) +static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx)  {  	int err, region; @@ -2349,44 +2476,30 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)  		break;  	} -	err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain, -				 MT_RX_SEL0, region); +	err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region);  	if (err < 0)  		return err; -	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, -				 MT_RX_SEL0, 1); +	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1);  }  static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)  { -	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;  	struct mt7996_dev *dev = phy->dev; -	u8 band_idx = phy->mt76->band_idx; -	int err; +	int err, rdd_idx; -	/* start CAC */ -	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx, -				 MT_RX_SEL0, 0); -	if (err < 0) -		return err; +	rdd_idx = mt7996_get_rdd_idx(phy, false); +	if (rdd_idx < 0) +		return -EINVAL; -	err = mt7996_dfs_start_rdd(dev, band_idx); +	/* start CAC */ +	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, rdd_idx, 0);  	if (err < 0)  		return err; -	phy->rdd_state |= BIT(band_idx); +	err = mt7996_dfs_start_rdd(dev, rdd_idx); -	if (chandef->width == NL80211_CHAN_WIDTH_160 || -	    chandef->width == NL80211_CHAN_WIDTH_80P80) { -		err = mt7996_dfs_start_rdd(dev, 1); -		if (err < 0) -			return err; - -		phy->rdd_state |= BIT(1); -	} - -	return 0; +	return err;  }  static int @@ -2427,12 +2540,12 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)  {  	struct mt7996_dev *dev = phy->dev;  	enum mt76_dfs_state dfs_state, prev_state; -	int err; +	int err, rdd_idx = mt7996_get_rdd_idx(phy, false);  	prev_state = phy->mt76->dfs_state;  	dfs_state = mt76_phy_dfs_state(phy->mt76); -	if (prev_state == dfs_state) +	if (prev_state == dfs_state || rdd_idx < 0)  		return 0;  	if (prev_state == MT_DFS_STATE_UNKNOWN) @@ -2456,8 +2569,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)  	if (dfs_state == MT_DFS_STATE_CAC)  		return 0; -	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, -				 phy->mt76->band_idx, MT_RX_SEL0, 0); +	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, rdd_idx, 0);  	if (err < 0) {  		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;  		return err; @@ -2467,8 +2579,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)  	return 0;  stop: -	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, -				 phy->mt76->band_idx, MT_RX_SEL0, 0); +	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, rdd_idx, 0);  	if (err < 0)  		return err; @@ -2553,7 +2664,7 @@ static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)  }  static bool -mt7996_mac_twt_param_equal(struct mt7996_sta *msta, +mt7996_mac_twt_param_equal(struct mt7996_sta_link *msta_link,  			   struct ieee80211_twt_params *twt_agrt)  {  	u16 type = le16_to_cpu(twt_agrt->req_type); @@ -2564,10 +2675,10 @@ mt7996_mac_twt_param_equal(struct mt7996_sta *msta,  	for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) {  		struct mt7996_twt_flow *f; -		if (!(msta->twt.flowid_mask & BIT(i))) +		if (!(msta_link->twt.flowid_mask & BIT(i)))  			continue; -		f = &msta->twt.flow[i]; +		f = &msta_link->twt.flow[i];  		if (f->duration == twt_agrt->min_twt_dur &&  		    f->mantissa == twt_agrt->mantissa &&  		    f->exp == exp && @@ -2587,6 +2698,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;  	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;  	struct ieee80211_twt_params *twt_agrt = (void *)twt->params; +	struct mt7996_sta_link *msta_link = &msta->deflink;  	u16 req_type = le16_to_cpu(twt_agrt->req_type);  	enum ieee80211_twt_setup_cmd sta_setup_cmd;  	struct mt7996_dev *dev = mt7996_hw_dev(hw); @@ -2601,7 +2713,8 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  	if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)  		goto unlock; -	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) +	if (hweight8(msta_link->twt.flowid_mask) == +	    ARRAY_SIZE(msta_link->twt.flow))  		goto unlock;  	if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) { @@ -2610,10 +2723,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  		goto unlock;  	} -	if (mt7996_mac_twt_param_equal(msta, twt_agrt)) +	if (mt7996_mac_twt_param_equal(msta_link, twt_agrt))  		goto unlock; -	flowid = ffs(~msta->twt.flowid_mask) - 1; +	flowid = ffs(~msta_link->twt.flowid_mask) - 1;  	twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);  	twt_agrt->req_type |= le16_encode_bits(flowid,  					       IEEE80211_TWT_REQTYPE_FLOWID); @@ -2622,10 +2735,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);  	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type); -	flow = &msta->twt.flow[flowid]; +	flow = &msta_link->twt.flow[flowid];  	memset(flow, 0, sizeof(*flow));  	INIT_LIST_HEAD(&flow->list); -	flow->wcid = msta->wcid.idx; +	flow->wcid = msta_link->wcid.idx;  	flow->table_id = table_id;  	flow->id = flowid;  	flow->duration = twt_agrt->min_twt_dur; @@ -2643,7 +2756,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  		flow->sched = true;  		flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow); -		curr_tsf = __mt7996_get_tsf(hw, msta->vif); +		curr_tsf = __mt7996_get_tsf(hw, &msta->vif->deflink);  		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);  		flow_tsf = curr_tsf + interval - rem;  		twt_agrt->twt = cpu_to_le64(flow_tsf); @@ -2652,12 +2765,13 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,  	}  	flow->tsf = le64_to_cpu(twt_agrt->twt); -	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) +	if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow, +				       MCU_TWT_AGRT_ADD))  		goto unlock;  	setup_cmd = TWT_SETUP_CMD_ACCEPT;  	dev->twt.table_mask |= BIT(table_id); -	msta->twt.flowid_mask |= BIT(flowid); +	msta_link->twt.flowid_mask |= BIT(flowid);  	dev->twt.n_agrt++;  unlock: @@ -2670,26 +2784,26 @@ out:  }  void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, -				  struct mt7996_sta *msta, +				  struct mt7996_vif_link *link, +				  struct mt7996_sta_link *msta_link,  				  u8 flowid)  {  	struct mt7996_twt_flow *flow;  	lockdep_assert_held(&dev->mt76.mutex); -	if (flowid >= ARRAY_SIZE(msta->twt.flow)) +	if (flowid >= ARRAY_SIZE(msta_link->twt.flow))  		return; -	if (!(msta->twt.flowid_mask & BIT(flowid))) +	if (!(msta_link->twt.flowid_mask & BIT(flowid)))  		return; -	flow = &msta->twt.flow[flowid]; -	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, -				       MCU_TWT_AGRT_DELETE)) +	flow = &msta_link->twt.flow[flowid]; +	if (mt7996_mcu_twt_agrt_update(dev, link, flow, MCU_TWT_AGRT_DELETE))  		return;  	list_del_init(&flow->list); -	msta->twt.flowid_mask &= ~BIT(flowid); +	msta_link->twt.flowid_mask &= ~BIT(flowid);  	dev->twt.table_mask &= ~BIT(flow->table_id);  	dev->twt.n_agrt--;  }  | 
