11755f6adSLorenzo Bianconi // SPDX-License-Identifier: ISC
21755f6adSLorenzo Bianconi /* Copyright (C) 2020 MediaTek Inc. */
31755f6adSLorenzo Bianconi 
41755f6adSLorenzo Bianconi #include "mt76_connac.h"
5182071cdSLorenzo Bianconi #include "mt76_connac2_mac.h"
60a178a60SLorenzo Bianconi #include "dma.h"
71755f6adSLorenzo Bianconi 
8f71662deSLorenzo Bianconi #define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
9f71662deSLorenzo Bianconi #define HE_PREP(f, m, v)	le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
10f71662deSLorenzo Bianconi 						 IEEE80211_RADIOTAP_HE_##f)
11f71662deSLorenzo Bianconi 
mt76_connac_gen_ppe_thresh(u8 * he_ppet,int nss)126a8b899dSLorenzo Bianconi void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss)
136a8b899dSLorenzo Bianconi {
146a8b899dSLorenzo Bianconi 	static const u8 ppet16_ppet8_ru3_ru0[] = { 0x1c, 0xc7, 0x71 };
156a8b899dSLorenzo Bianconi 	u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
166a8b899dSLorenzo Bianconi 
176a8b899dSLorenzo Bianconi 	he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
186a8b899dSLorenzo Bianconi 		     FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
196a8b899dSLorenzo Bianconi 				ru_bit_mask);
206a8b899dSLorenzo Bianconi 
216a8b899dSLorenzo Bianconi 	ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
226a8b899dSLorenzo Bianconi 		    nss * hweight8(ru_bit_mask) * 2;
236a8b899dSLorenzo Bianconi 	ppet_size = DIV_ROUND_UP(ppet_bits, 8);
246a8b899dSLorenzo Bianconi 
256a8b899dSLorenzo Bianconi 	for (i = 0; i < ppet_size - 1; i++)
266a8b899dSLorenzo Bianconi 		he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
276a8b899dSLorenzo Bianconi 
286a8b899dSLorenzo Bianconi 	he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
296a8b899dSLorenzo Bianconi 			 (0xff >> (8 - (ppet_bits - 1) % 8));
306a8b899dSLorenzo Bianconi }
316a8b899dSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_gen_ppe_thresh);
326a8b899dSLorenzo Bianconi 
mt76_connac_pm_wake(struct mt76_phy * phy,struct mt76_connac_pm * pm)331755f6adSLorenzo Bianconi int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
341755f6adSLorenzo Bianconi {
351755f6adSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
361755f6adSLorenzo Bianconi 
378aff2d91SLorenzo Bianconi 	if (mt76_is_usb(dev))
381755f6adSLorenzo Bianconi 		return 0;
391755f6adSLorenzo Bianconi 
404f9b3aebSLorenzo Bianconi 	cancel_delayed_work_sync(&pm->ps_work);
411755f6adSLorenzo Bianconi 	if (!test_bit(MT76_STATE_PM, &phy->state))
421755f6adSLorenzo Bianconi 		return 0;
431755f6adSLorenzo Bianconi 
44f86625aeSSean Wang 	if (pm->suspended)
45f86625aeSSean Wang 		return 0;
46f86625aeSSean Wang 
47e5f35576SLorenzo Bianconi 	queue_work(dev->wq, &pm->wake_work);
48e5f35576SLorenzo Bianconi 	if (!wait_event_timeout(pm->wait,
49e5f35576SLorenzo Bianconi 				!test_bit(MT76_STATE_PM, &phy->state),
50e5f35576SLorenzo Bianconi 				3 * HZ)) {
511755f6adSLorenzo Bianconi 		ieee80211_wake_queues(phy->hw);
521755f6adSLorenzo Bianconi 		return -ETIMEDOUT;
531755f6adSLorenzo Bianconi 	}
541755f6adSLorenzo Bianconi 
551755f6adSLorenzo Bianconi 	return 0;
561755f6adSLorenzo Bianconi }
571755f6adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_pm_wake);
581755f6adSLorenzo Bianconi 
mt76_connac_power_save_sched(struct mt76_phy * phy,struct mt76_connac_pm * pm)591755f6adSLorenzo Bianconi void mt76_connac_power_save_sched(struct mt76_phy *phy,
601755f6adSLorenzo Bianconi 				  struct mt76_connac_pm *pm)
611755f6adSLorenzo Bianconi {
621755f6adSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
631755f6adSLorenzo Bianconi 
648aff2d91SLorenzo Bianconi 	if (mt76_is_usb(dev))
651755f6adSLorenzo Bianconi 		return;
661755f6adSLorenzo Bianconi 
67081b37aeSSean Wang 	if (!pm->enable)
681755f6adSLorenzo Bianconi 		return;
691755f6adSLorenzo Bianconi 
70f86625aeSSean Wang 	if (pm->suspended)
71f86625aeSSean Wang 		return;
72f86625aeSSean Wang 
731755f6adSLorenzo Bianconi 	pm->last_activity = jiffies;
741755f6adSLorenzo Bianconi 
75b1bd7bb8SLorenzo Bianconi 	if (!test_bit(MT76_STATE_PM, &phy->state)) {
76b1bd7bb8SLorenzo Bianconi 		cancel_delayed_work(&phy->mac_work);
771755f6adSLorenzo Bianconi 		queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout);
781755f6adSLorenzo Bianconi 	}
79b1bd7bb8SLorenzo Bianconi }
801755f6adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched);
811755f6adSLorenzo Bianconi 
mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm * pm,struct mt76_wcid * wcid)821755f6adSLorenzo Bianconi void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm,
831755f6adSLorenzo Bianconi 				      struct mt76_wcid *wcid)
841755f6adSLorenzo Bianconi {
851755f6adSLorenzo Bianconi 	int i;
861755f6adSLorenzo Bianconi 
871755f6adSLorenzo Bianconi 	spin_lock_bh(&pm->txq_lock);
881755f6adSLorenzo Bianconi 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
891755f6adSLorenzo Bianconi 		if (wcid && pm->tx_q[i].wcid != wcid)
901755f6adSLorenzo Bianconi 			continue;
911755f6adSLorenzo Bianconi 
921755f6adSLorenzo Bianconi 		dev_kfree_skb(pm->tx_q[i].skb);
931755f6adSLorenzo Bianconi 		pm->tx_q[i].skb = NULL;
941755f6adSLorenzo Bianconi 	}
951755f6adSLorenzo Bianconi 	spin_unlock_bh(&pm->txq_lock);
961755f6adSLorenzo Bianconi }
971755f6adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs);
981755f6adSLorenzo Bianconi 
mt76_connac_pm_queue_skb(struct ieee80211_hw * hw,struct mt76_connac_pm * pm,struct mt76_wcid * wcid,struct sk_buff * skb)991755f6adSLorenzo Bianconi void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw,
1001755f6adSLorenzo Bianconi 			      struct mt76_connac_pm *pm,
1011755f6adSLorenzo Bianconi 			      struct mt76_wcid *wcid,
1021755f6adSLorenzo Bianconi 			      struct sk_buff *skb)
1031755f6adSLorenzo Bianconi {
1041755f6adSLorenzo Bianconi 	int qid = skb_get_queue_mapping(skb);
1051755f6adSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1061755f6adSLorenzo Bianconi 
1071755f6adSLorenzo Bianconi 	spin_lock_bh(&pm->txq_lock);
1081755f6adSLorenzo Bianconi 	if (!pm->tx_q[qid].skb) {
1091755f6adSLorenzo Bianconi 		ieee80211_stop_queues(hw);
1101755f6adSLorenzo Bianconi 		pm->tx_q[qid].wcid = wcid;
1111755f6adSLorenzo Bianconi 		pm->tx_q[qid].skb = skb;
1121755f6adSLorenzo Bianconi 		queue_work(phy->dev->wq, &pm->wake_work);
1131755f6adSLorenzo Bianconi 	} else {
1141755f6adSLorenzo Bianconi 		dev_kfree_skb(skb);
1151755f6adSLorenzo Bianconi 	}
1161755f6adSLorenzo Bianconi 	spin_unlock_bh(&pm->txq_lock);
1171755f6adSLorenzo Bianconi }
1181755f6adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb);
1191755f6adSLorenzo Bianconi 
mt76_connac_pm_dequeue_skbs(struct mt76_phy * phy,struct mt76_connac_pm * pm)1201755f6adSLorenzo Bianconi void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy,
1211755f6adSLorenzo Bianconi 				 struct mt76_connac_pm *pm)
1221755f6adSLorenzo Bianconi {
1231755f6adSLorenzo Bianconi 	int i;
1241755f6adSLorenzo Bianconi 
1251755f6adSLorenzo Bianconi 	spin_lock_bh(&pm->txq_lock);
1261755f6adSLorenzo Bianconi 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
1271755f6adSLorenzo Bianconi 		struct mt76_wcid *wcid = pm->tx_q[i].wcid;
1281755f6adSLorenzo Bianconi 		struct ieee80211_sta *sta = NULL;
1291755f6adSLorenzo Bianconi 
1301755f6adSLorenzo Bianconi 		if (!pm->tx_q[i].skb)
1311755f6adSLorenzo Bianconi 			continue;
1321755f6adSLorenzo Bianconi 
1331755f6adSLorenzo Bianconi 		if (wcid && wcid->sta)
1341755f6adSLorenzo Bianconi 			sta = container_of((void *)wcid, struct ieee80211_sta,
1351755f6adSLorenzo Bianconi 					   drv_priv);
1361755f6adSLorenzo Bianconi 
1371755f6adSLorenzo Bianconi 		mt76_tx(phy, sta, wcid, pm->tx_q[i].skb);
1381755f6adSLorenzo Bianconi 		pm->tx_q[i].skb = NULL;
1391755f6adSLorenzo Bianconi 	}
1401755f6adSLorenzo Bianconi 	spin_unlock_bh(&pm->txq_lock);
1411755f6adSLorenzo Bianconi 
1421755f6adSLorenzo Bianconi 	mt76_worker_schedule(&phy->dev->tx_worker);
1431755f6adSLorenzo Bianconi }
1441755f6adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs);
145182071cdSLorenzo Bianconi 
mt76_connac_tx_complete_skb(struct mt76_dev * mdev,struct mt76_queue_entry * e)1460a178a60SLorenzo Bianconi void mt76_connac_tx_complete_skb(struct mt76_dev *mdev,
1470a178a60SLorenzo Bianconi 				 struct mt76_queue_entry *e)
1480a178a60SLorenzo Bianconi {
1490a178a60SLorenzo Bianconi 	if (!e->txwi) {
1500a178a60SLorenzo Bianconi 		dev_kfree_skb_any(e->skb);
1510a178a60SLorenzo Bianconi 		return;
1520a178a60SLorenzo Bianconi 	}
1530a178a60SLorenzo Bianconi 
1540a178a60SLorenzo Bianconi 	if (e->skb)
1550a178a60SLorenzo Bianconi 		mt76_tx_complete_skb(mdev, e->wcid, e->skb);
1560a178a60SLorenzo Bianconi }
1570a178a60SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_tx_complete_skb);
1580a178a60SLorenzo Bianconi 
mt76_connac_write_hw_txp(struct mt76_dev * dev,struct mt76_tx_info * tx_info,void * txp_ptr,u32 id)1595e610f8eSLorenzo Bianconi void mt76_connac_write_hw_txp(struct mt76_dev *dev,
1605e610f8eSLorenzo Bianconi 			      struct mt76_tx_info *tx_info,
1615e610f8eSLorenzo Bianconi 			      void *txp_ptr, u32 id)
1625e610f8eSLorenzo Bianconi {
1635e610f8eSLorenzo Bianconi 	struct mt76_connac_hw_txp *txp = txp_ptr;
1645e610f8eSLorenzo Bianconi 	struct mt76_connac_txp_ptr *ptr = &txp->ptr[0];
1655e610f8eSLorenzo Bianconi 	int i, nbuf = tx_info->nbuf - 1;
1665e610f8eSLorenzo Bianconi 	u32 last_mask;
1675e610f8eSLorenzo Bianconi 
1685e610f8eSLorenzo Bianconi 	tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
1695e610f8eSLorenzo Bianconi 	tx_info->nbuf = 1;
1705e610f8eSLorenzo Bianconi 
1715e610f8eSLorenzo Bianconi 	txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
1725e610f8eSLorenzo Bianconi 
1735e610f8eSLorenzo Bianconi 	if (is_mt7663(dev) || is_mt7921(dev))
1745e610f8eSLorenzo Bianconi 		last_mask = MT_TXD_LEN_LAST;
1755e610f8eSLorenzo Bianconi 	else
1765e610f8eSLorenzo Bianconi 		last_mask = MT_TXD_LEN_AMSDU_LAST |
1775e610f8eSLorenzo Bianconi 			    MT_TXD_LEN_MSDU_LAST;
1785e610f8eSLorenzo Bianconi 
1795e610f8eSLorenzo Bianconi 	for (i = 0; i < nbuf; i++) {
1805e610f8eSLorenzo Bianconi 		u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK;
1815e610f8eSLorenzo Bianconi 		u32 addr = tx_info->buf[i + 1].addr;
1825e610f8eSLorenzo Bianconi 
1835e610f8eSLorenzo Bianconi 		if (i == nbuf - 1)
1845e610f8eSLorenzo Bianconi 			len |= last_mask;
1855e610f8eSLorenzo Bianconi 
1865e610f8eSLorenzo Bianconi 		if (i & 1) {
1875e610f8eSLorenzo Bianconi 			ptr->buf1 = cpu_to_le32(addr);
1885e610f8eSLorenzo Bianconi 			ptr->len1 = cpu_to_le16(len);
1895e610f8eSLorenzo Bianconi 			ptr++;
1905e610f8eSLorenzo Bianconi 		} else {
1915e610f8eSLorenzo Bianconi 			ptr->buf0 = cpu_to_le32(addr);
1925e610f8eSLorenzo Bianconi 			ptr->len0 = cpu_to_le16(len);
1935e610f8eSLorenzo Bianconi 		}
1945e610f8eSLorenzo Bianconi 	}
1955e610f8eSLorenzo Bianconi }
1965e610f8eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_write_hw_txp);
1975e610f8eSLorenzo Bianconi 
1982b25b855SLorenzo Bianconi static void
mt76_connac_txp_skb_unmap_fw(struct mt76_dev * mdev,struct mt76_connac_fw_txp * txp)1992b25b855SLorenzo Bianconi mt76_connac_txp_skb_unmap_fw(struct mt76_dev *mdev,
2002b25b855SLorenzo Bianconi 			     struct mt76_connac_fw_txp *txp)
2012b25b855SLorenzo Bianconi {
2022b25b855SLorenzo Bianconi 	struct device *dev = is_connac_v1(mdev) ? mdev->dev : mdev->dma_dev;
2032b25b855SLorenzo Bianconi 	int i;
2042b25b855SLorenzo Bianconi 
2052b25b855SLorenzo Bianconi 	for (i = 0; i < txp->nbuf; i++)
2062b25b855SLorenzo Bianconi 		dma_unmap_single(dev, le32_to_cpu(txp->buf[i]),
2072b25b855SLorenzo Bianconi 				 le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
2082b25b855SLorenzo Bianconi }
2092b25b855SLorenzo Bianconi 
2102b25b855SLorenzo Bianconi static void
mt76_connac_txp_skb_unmap_hw(struct mt76_dev * dev,struct mt76_connac_hw_txp * txp)2112b25b855SLorenzo Bianconi mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev,
2122b25b855SLorenzo Bianconi 			     struct mt76_connac_hw_txp *txp)
2132b25b855SLorenzo Bianconi {
2142b25b855SLorenzo Bianconi 	u32 last_mask;
2152b25b855SLorenzo Bianconi 	int i;
2162b25b855SLorenzo Bianconi 
2172b25b855SLorenzo Bianconi 	if (is_mt7663(dev) || is_mt7921(dev))
2182b25b855SLorenzo Bianconi 		last_mask = MT_TXD_LEN_LAST;
2192b25b855SLorenzo Bianconi 	else
2202b25b855SLorenzo Bianconi 		last_mask = MT_TXD_LEN_MSDU_LAST;
2212b25b855SLorenzo Bianconi 
2222b25b855SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) {
2232b25b855SLorenzo Bianconi 		struct mt76_connac_txp_ptr *ptr = &txp->ptr[i];
2242b25b855SLorenzo Bianconi 		bool last;
2252b25b855SLorenzo Bianconi 		u16 len;
2262b25b855SLorenzo Bianconi 
2272b25b855SLorenzo Bianconi 		len = le16_to_cpu(ptr->len0);
2282b25b855SLorenzo Bianconi 		last = len & last_mask;
2292b25b855SLorenzo Bianconi 		len &= MT_TXD_LEN_MASK;
2302b25b855SLorenzo Bianconi 		dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,
2312b25b855SLorenzo Bianconi 				 DMA_TO_DEVICE);
2322b25b855SLorenzo Bianconi 		if (last)
2332b25b855SLorenzo Bianconi 			break;
2342b25b855SLorenzo Bianconi 
2352b25b855SLorenzo Bianconi 		len = le16_to_cpu(ptr->len1);
2362b25b855SLorenzo Bianconi 		last = len & last_mask;
2372b25b855SLorenzo Bianconi 		len &= MT_TXD_LEN_MASK;
2382b25b855SLorenzo Bianconi 		dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,
2392b25b855SLorenzo Bianconi 				 DMA_TO_DEVICE);
2402b25b855SLorenzo Bianconi 		if (last)
2412b25b855SLorenzo Bianconi 			break;
2422b25b855SLorenzo Bianconi 	}
2432b25b855SLorenzo Bianconi }
2442b25b855SLorenzo Bianconi 
mt76_connac_txp_skb_unmap(struct mt76_dev * dev,struct mt76_txwi_cache * t)2452b25b855SLorenzo Bianconi void mt76_connac_txp_skb_unmap(struct mt76_dev *dev,
2462b25b855SLorenzo Bianconi 			       struct mt76_txwi_cache *t)
2472b25b855SLorenzo Bianconi {
2482b25b855SLorenzo Bianconi 	struct mt76_connac_txp_common *txp;
2492b25b855SLorenzo Bianconi 
2502b25b855SLorenzo Bianconi 	txp = mt76_connac_txwi_to_txp(dev, t);
2512b25b855SLorenzo Bianconi 	if (is_mt76_fw_txp(dev))
2522b25b855SLorenzo Bianconi 		mt76_connac_txp_skb_unmap_fw(dev, &txp->fw);
2532b25b855SLorenzo Bianconi 	else
2542b25b855SLorenzo Bianconi 		mt76_connac_txp_skb_unmap_hw(dev, &txp->hw);
2552b25b855SLorenzo Bianconi }
2562b25b855SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap);
2572b25b855SLorenzo Bianconi 
mt76_connac_init_tx_queues(struct mt76_phy * phy,int idx,int n_desc,int ring_base,u32 flags)2589dfb28e9SLorenzo Bianconi int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
2599dfb28e9SLorenzo Bianconi 			       int ring_base, u32 flags)
2609dfb28e9SLorenzo Bianconi {
2619dfb28e9SLorenzo Bianconi 	int i, err;
2629dfb28e9SLorenzo Bianconi 
2639dfb28e9SLorenzo Bianconi 	err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags);
2649dfb28e9SLorenzo Bianconi 	if (err < 0)
2659dfb28e9SLorenzo Bianconi 		return err;
2669dfb28e9SLorenzo Bianconi 
2679dfb28e9SLorenzo Bianconi 	for (i = 1; i <= MT_TXQ_PSD; i++)
2689dfb28e9SLorenzo Bianconi 		phy->q_tx[i] = phy->q_tx[0];
2699dfb28e9SLorenzo Bianconi 
2709dfb28e9SLorenzo Bianconi 	return 0;
2719dfb28e9SLorenzo Bianconi }
2729dfb28e9SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);
2739dfb28e9SLorenzo Bianconi 
2749c54548bSRyder Lee #define __bitrate_mask_check(_mcs, _mode)				\
2759c54548bSRyder Lee ({									\
2769c54548bSRyder Lee 	u8 i = 0;							\
2779c54548bSRyder Lee 	for (nss = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {	\
2789c54548bSRyder Lee 		if (!mask->control[band]._mcs[i])			\
2799c54548bSRyder Lee 			continue;					\
2809c54548bSRyder Lee 		if (hweight16(mask->control[band]._mcs[i]) == 1) {	\
2819c54548bSRyder Lee 			mode = MT_PHY_TYPE_##_mode;			\
2829c54548bSRyder Lee 			rateidx = ffs(mask->control[band]._mcs[i]) - 1;	\
2839c54548bSRyder Lee 			if (mode == MT_PHY_TYPE_HT)			\
2849c54548bSRyder Lee 				rateidx += 8 * i;			\
2859c54548bSRyder Lee 			else						\
2869c54548bSRyder Lee 				nss = i + 1;				\
2879c54548bSRyder Lee 			goto out;					\
2889c54548bSRyder Lee 		}							\
2899c54548bSRyder Lee 	}								\
2909c54548bSRyder Lee })
2919c54548bSRyder Lee 
mt76_connac2_mac_tx_rate_val(struct mt76_phy * mphy,struct ieee80211_vif * vif,bool beacon,bool mcast)2920b8e2d69SLorenzo Bianconi u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
2930b8e2d69SLorenzo Bianconi 				 struct ieee80211_vif *vif,
294182071cdSLorenzo Bianconi 				 bool beacon, bool mcast)
295182071cdSLorenzo Bianconi {
296*e1d9e0e7SSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
297*e1d9e0e7SSean Wang 	struct cfg80211_chan_def *chandef = mvif->ctx ?
298*e1d9e0e7SSean Wang 					    &mvif->ctx->def : &mphy->chandef;
299*e1d9e0e7SSean Wang 	u8 nss = 0, mode = 0, band = chandef->chan->band;
300182071cdSLorenzo Bianconi 	int rateidx = 0, mcast_rate;
301182071cdSLorenzo Bianconi 
302182071cdSLorenzo Bianconi 	if (!vif)
303182071cdSLorenzo Bianconi 		goto legacy;
304182071cdSLorenzo Bianconi 
305182071cdSLorenzo Bianconi 	if (is_mt7921(mphy->dev)) {
306182071cdSLorenzo Bianconi 		rateidx = ffs(vif->bss_conf.basic_rates) - 1;
307182071cdSLorenzo Bianconi 		goto legacy;
308182071cdSLorenzo Bianconi 	}
309182071cdSLorenzo Bianconi 
310182071cdSLorenzo Bianconi 	if (beacon) {
311182071cdSLorenzo Bianconi 		struct cfg80211_bitrate_mask *mask;
312182071cdSLorenzo Bianconi 
313182071cdSLorenzo Bianconi 		mask = &vif->bss_conf.beacon_tx_rate;
3149c54548bSRyder Lee 
3159c54548bSRyder Lee 		__bitrate_mask_check(he_mcs, HE_SU);
3169c54548bSRyder Lee 		__bitrate_mask_check(vht_mcs, VHT);
3179c54548bSRyder Lee 		__bitrate_mask_check(ht_mcs, HT);
3189c54548bSRyder Lee 
3199c54548bSRyder Lee 		if (hweight32(mask->control[band].legacy) == 1) {
320182071cdSLorenzo Bianconi 			rateidx = ffs(mask->control[band].legacy) - 1;
321182071cdSLorenzo Bianconi 			goto legacy;
322182071cdSLorenzo Bianconi 		}
323182071cdSLorenzo Bianconi 	}
324182071cdSLorenzo Bianconi 
325182071cdSLorenzo Bianconi 	mcast_rate = vif->bss_conf.mcast_rate[band];
326182071cdSLorenzo Bianconi 	if (mcast && mcast_rate > 0)
327182071cdSLorenzo Bianconi 		rateidx = mcast_rate - 1;
328182071cdSLorenzo Bianconi 	else
329182071cdSLorenzo Bianconi 		rateidx = ffs(vif->bss_conf.basic_rates) - 1;
330182071cdSLorenzo Bianconi 
331182071cdSLorenzo Bianconi legacy:
332*e1d9e0e7SSean Wang 	rateidx = mt76_calculate_default_rate(mphy, vif, rateidx);
333182071cdSLorenzo Bianconi 	mode = rateidx >> 8;
334182071cdSLorenzo Bianconi 	rateidx &= GENMASK(7, 0);
335182071cdSLorenzo Bianconi out:
3369c54548bSRyder Lee 	return FIELD_PREP(MT_TX_RATE_NSS, nss) |
3379c54548bSRyder Lee 	       FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
338182071cdSLorenzo Bianconi 	       FIELD_PREP(MT_TX_RATE_MODE, mode);
339182071cdSLorenzo Bianconi }
3400b8e2d69SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val);
341182071cdSLorenzo Bianconi 
342182071cdSLorenzo Bianconi static void
mt76_connac2_mac_write_txwi_8023(__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid)343182071cdSLorenzo Bianconi mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,
344182071cdSLorenzo Bianconi 				 struct mt76_wcid *wcid)
345182071cdSLorenzo Bianconi {
346182071cdSLorenzo Bianconi 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
347182071cdSLorenzo Bianconi 	u8 fc_type, fc_stype;
348182071cdSLorenzo Bianconi 	u16 ethertype;
349182071cdSLorenzo Bianconi 	bool wmm = false;
350182071cdSLorenzo Bianconi 	u32 val;
351182071cdSLorenzo Bianconi 
352182071cdSLorenzo Bianconi 	if (wcid->sta) {
353182071cdSLorenzo Bianconi 		struct ieee80211_sta *sta;
354182071cdSLorenzo Bianconi 
355182071cdSLorenzo Bianconi 		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
356182071cdSLorenzo Bianconi 		wmm = sta->wme;
357182071cdSLorenzo Bianconi 	}
358182071cdSLorenzo Bianconi 
359182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
360182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD1_TID, tid);
361182071cdSLorenzo Bianconi 
362182071cdSLorenzo Bianconi 	ethertype = get_unaligned_be16(&skb->data[12]);
363182071cdSLorenzo Bianconi 	if (ethertype >= ETH_P_802_3_MIN)
364182071cdSLorenzo Bianconi 		val |= MT_TXD1_ETH_802_3;
365182071cdSLorenzo Bianconi 
366182071cdSLorenzo Bianconi 	txwi[1] |= cpu_to_le32(val);
367182071cdSLorenzo Bianconi 
368182071cdSLorenzo Bianconi 	fc_type = IEEE80211_FTYPE_DATA >> 2;
369182071cdSLorenzo Bianconi 	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
370182071cdSLorenzo Bianconi 
371182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
372182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
373182071cdSLorenzo Bianconi 
374182071cdSLorenzo Bianconi 	txwi[2] |= cpu_to_le32(val);
375182071cdSLorenzo Bianconi 
376182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
377182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
378182071cdSLorenzo Bianconi 
379182071cdSLorenzo Bianconi 	txwi[7] |= cpu_to_le32(val);
380182071cdSLorenzo Bianconi }
381182071cdSLorenzo Bianconi 
382182071cdSLorenzo Bianconi static void
mt76_connac2_mac_write_txwi_80211(struct mt76_dev * dev,__le32 * txwi,struct sk_buff * skb,struct ieee80211_key_conf * key)383182071cdSLorenzo Bianconi mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
384182071cdSLorenzo Bianconi 				  struct sk_buff *skb,
385182071cdSLorenzo Bianconi 				  struct ieee80211_key_conf *key)
386182071cdSLorenzo Bianconi {
387182071cdSLorenzo Bianconi 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
388182071cdSLorenzo Bianconi 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
389182071cdSLorenzo Bianconi 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
390182071cdSLorenzo Bianconi 	bool multicast = is_multicast_ether_addr(hdr->addr1);
391182071cdSLorenzo Bianconi 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
392182071cdSLorenzo Bianconi 	__le16 fc = hdr->frame_control;
393182071cdSLorenzo Bianconi 	u8 fc_type, fc_stype;
394182071cdSLorenzo Bianconi 	u32 val;
395182071cdSLorenzo Bianconi 
396182071cdSLorenzo Bianconi 	if (ieee80211_is_action(fc) &&
397182071cdSLorenzo Bianconi 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
398182071cdSLorenzo Bianconi 	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
399182071cdSLorenzo Bianconi 		u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
400182071cdSLorenzo Bianconi 
401182071cdSLorenzo Bianconi 		txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
402182071cdSLorenzo Bianconi 		tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;
403182071cdSLorenzo Bianconi 	} else if (ieee80211_is_back_req(hdr->frame_control)) {
404182071cdSLorenzo Bianconi 		struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
405182071cdSLorenzo Bianconi 		u16 control = le16_to_cpu(bar->control);
406182071cdSLorenzo Bianconi 
407182071cdSLorenzo Bianconi 		tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
408182071cdSLorenzo Bianconi 	}
409182071cdSLorenzo Bianconi 
410182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
411182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD1_HDR_INFO,
412182071cdSLorenzo Bianconi 			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
413182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD1_TID, tid);
414182071cdSLorenzo Bianconi 
415182071cdSLorenzo Bianconi 	txwi[1] |= cpu_to_le32(val);
416182071cdSLorenzo Bianconi 
417182071cdSLorenzo Bianconi 	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
418182071cdSLorenzo Bianconi 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
419182071cdSLorenzo Bianconi 
420182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
421182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
422182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD2_MULTICAST, multicast);
423182071cdSLorenzo Bianconi 
424182071cdSLorenzo Bianconi 	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
425182071cdSLorenzo Bianconi 	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
426182071cdSLorenzo Bianconi 		val |= MT_TXD2_BIP;
427182071cdSLorenzo Bianconi 		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
428182071cdSLorenzo Bianconi 	}
429182071cdSLorenzo Bianconi 
430182071cdSLorenzo Bianconi 	if (!ieee80211_is_data(fc) || multicast ||
431182071cdSLorenzo Bianconi 	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
432182071cdSLorenzo Bianconi 		val |= MT_TXD2_FIX_RATE;
433182071cdSLorenzo Bianconi 
434182071cdSLorenzo Bianconi 	txwi[2] |= cpu_to_le32(val);
435182071cdSLorenzo Bianconi 
436182071cdSLorenzo Bianconi 	if (ieee80211_is_beacon(fc)) {
437182071cdSLorenzo Bianconi 		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
438182071cdSLorenzo Bianconi 		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
439182071cdSLorenzo Bianconi 	}
440182071cdSLorenzo Bianconi 
441182071cdSLorenzo Bianconi 	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
442182071cdSLorenzo Bianconi 		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
443182071cdSLorenzo Bianconi 
444182071cdSLorenzo Bianconi 		if (ieee80211_is_back_req(hdr->frame_control)) {
445182071cdSLorenzo Bianconi 			struct ieee80211_bar *bar;
446182071cdSLorenzo Bianconi 
447182071cdSLorenzo Bianconi 			bar = (struct ieee80211_bar *)skb->data;
448182071cdSLorenzo Bianconi 			seqno = le16_to_cpu(bar->start_seq_num);
449182071cdSLorenzo Bianconi 		}
450182071cdSLorenzo Bianconi 
451182071cdSLorenzo Bianconi 		val = MT_TXD3_SN_VALID |
452182071cdSLorenzo Bianconi 		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
453182071cdSLorenzo Bianconi 		txwi[3] |= cpu_to_le32(val);
454182071cdSLorenzo Bianconi 		txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);
455182071cdSLorenzo Bianconi 	}
456182071cdSLorenzo Bianconi 
457182071cdSLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
458182071cdSLorenzo Bianconi 		val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
459182071cdSLorenzo Bianconi 		      FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
460182071cdSLorenzo Bianconi 		txwi[7] |= cpu_to_le32(val);
461182071cdSLorenzo Bianconi 	} else {
462182071cdSLorenzo Bianconi 		val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
463182071cdSLorenzo Bianconi 		      FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
464182071cdSLorenzo Bianconi 		txwi[8] |= cpu_to_le32(val);
465182071cdSLorenzo Bianconi 	}
466182071cdSLorenzo Bianconi }
467182071cdSLorenzo Bianconi 
mt76_connac2_mac_write_txwi(struct mt76_dev * dev,__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid,struct ieee80211_key_conf * key,int pid,enum mt76_txq_id qid,u32 changed)468182071cdSLorenzo Bianconi void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
469182071cdSLorenzo Bianconi 				 struct sk_buff *skb, struct mt76_wcid *wcid,
470182071cdSLorenzo Bianconi 				 struct ieee80211_key_conf *key, int pid,
4711d5af0acSFelix Fietkau 				 enum mt76_txq_id qid, u32 changed)
472182071cdSLorenzo Bianconi {
473182071cdSLorenzo Bianconi 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
474a062f001SLorenzo Bianconi 	u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
475182071cdSLorenzo Bianconi 	struct ieee80211_vif *vif = info->control.vif;
476182071cdSLorenzo Bianconi 	struct mt76_phy *mphy = &dev->phy;
477182071cdSLorenzo Bianconi 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0;
478182071cdSLorenzo Bianconi 	u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;
479182071cdSLorenzo Bianconi 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
480182071cdSLorenzo Bianconi 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
481182071cdSLorenzo Bianconi 				    BSS_CHANGED_BEACON_ENABLED));
482182071cdSLorenzo Bianconi 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
483182071cdSLorenzo Bianconi 					 BSS_CHANGED_FILS_DISCOVERY));
484b642f4c5SDeren Wu 	bool amsdu_en = wcid->amsdu;
485182071cdSLorenzo Bianconi 
486182071cdSLorenzo Bianconi 	if (vif) {
487182071cdSLorenzo Bianconi 		struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
488182071cdSLorenzo Bianconi 
489182071cdSLorenzo Bianconi 		omac_idx = mvif->omac_idx;
490182071cdSLorenzo Bianconi 		wmm_idx = mvif->wmm_idx;
491182071cdSLorenzo Bianconi 		band_idx = mvif->band_idx;
492182071cdSLorenzo Bianconi 	}
493182071cdSLorenzo Bianconi 
494a062f001SLorenzo Bianconi 	if (phy_idx && dev->phys[MT_BAND1])
495dc44c45cSLorenzo Bianconi 		mphy = dev->phys[MT_BAND1];
496182071cdSLorenzo Bianconi 
497182071cdSLorenzo Bianconi 	if (inband_disc) {
498182071cdSLorenzo Bianconi 		p_fmt = MT_TX_TYPE_FW;
499182071cdSLorenzo Bianconi 		q_idx = MT_LMAC_ALTX0;
500182071cdSLorenzo Bianconi 	} else if (beacon) {
501182071cdSLorenzo Bianconi 		p_fmt = MT_TX_TYPE_FW;
502182071cdSLorenzo Bianconi 		q_idx = MT_LMAC_BCN0;
5031d5af0acSFelix Fietkau 	} else if (qid >= MT_TXQ_PSD) {
504182071cdSLorenzo Bianconi 		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
505182071cdSLorenzo Bianconi 		q_idx = MT_LMAC_ALTX0;
506182071cdSLorenzo Bianconi 	} else {
507182071cdSLorenzo Bianconi 		p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
508182071cdSLorenzo Bianconi 		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
509182071cdSLorenzo Bianconi 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
51043eaa368SRyder Lee 
511161a7528SPeter Chiu 		/* mt7915 WA only counts WED path */
512161a7528SPeter Chiu 		if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed))
51343eaa368SRyder Lee 			wcid->stats.tx_packets++;
514182071cdSLorenzo Bianconi 	}
515182071cdSLorenzo Bianconi 
516182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
517182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
518182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
519182071cdSLorenzo Bianconi 	txwi[0] = cpu_to_le32(val);
520182071cdSLorenzo Bianconi 
521182071cdSLorenzo Bianconi 	val = MT_TXD1_LONG_FORMAT |
522182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
523182071cdSLorenzo Bianconi 	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
524182071cdSLorenzo Bianconi 	if (!is_mt7921(dev))
525182071cdSLorenzo Bianconi 		val |= MT_TXD1_VTA;
526a062f001SLorenzo Bianconi 	if (phy_idx || band_idx)
527182071cdSLorenzo Bianconi 		val |= MT_TXD1_TGID;
528182071cdSLorenzo Bianconi 
529182071cdSLorenzo Bianconi 	txwi[1] = cpu_to_le32(val);
530182071cdSLorenzo Bianconi 	txwi[2] = 0;
531182071cdSLorenzo Bianconi 
532182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15);
533182071cdSLorenzo Bianconi 	if (!is_mt7921(dev))
534182071cdSLorenzo Bianconi 		val |= MT_TXD3_SW_POWER_MGMT;
535182071cdSLorenzo Bianconi 	if (key)
536182071cdSLorenzo Bianconi 		val |= MT_TXD3_PROTECT_FRAME;
537182071cdSLorenzo Bianconi 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
538182071cdSLorenzo Bianconi 		val |= MT_TXD3_NO_ACK;
539182071cdSLorenzo Bianconi 
540182071cdSLorenzo Bianconi 	txwi[3] = cpu_to_le32(val);
541182071cdSLorenzo Bianconi 	txwi[4] = 0;
542182071cdSLorenzo Bianconi 
543182071cdSLorenzo Bianconi 	val = FIELD_PREP(MT_TXD5_PID, pid);
544b642f4c5SDeren Wu 	if (pid >= MT_PACKET_ID_FIRST) {
545182071cdSLorenzo Bianconi 		val |= MT_TXD5_TX_STATUS_HOST;
546b642f4c5SDeren Wu 		amsdu_en = amsdu_en && !is_mt7921(dev);
547b642f4c5SDeren Wu 	}
548182071cdSLorenzo Bianconi 
549182071cdSLorenzo Bianconi 	txwi[5] = cpu_to_le32(val);
550182071cdSLorenzo Bianconi 	txwi[6] = 0;
551b642f4c5SDeren Wu 	txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
552182071cdSLorenzo Bianconi 
553182071cdSLorenzo Bianconi 	if (is_8023)
554182071cdSLorenzo Bianconi 		mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid);
555182071cdSLorenzo Bianconi 	else
556182071cdSLorenzo Bianconi 		mt76_connac2_mac_write_txwi_80211(dev, txwi, skb, key);
557182071cdSLorenzo Bianconi 
558182071cdSLorenzo Bianconi 	if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
559182071cdSLorenzo Bianconi 		/* Fixed rata is available just for 802.11 txd */
560182071cdSLorenzo Bianconi 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
5613d2892e0SRyder Lee 		bool multicast = ieee80211_is_data(hdr->frame_control) &&
5623d2892e0SRyder Lee 				 is_multicast_ether_addr(hdr->addr1);
563182071cdSLorenzo Bianconi 		u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
564182071cdSLorenzo Bianconi 							multicast);
565182071cdSLorenzo Bianconi 		u32 val = MT_TXD6_FIXED_BW;
566182071cdSLorenzo Bianconi 
567182071cdSLorenzo Bianconi 		/* hardware won't add HTC for mgmt/ctrl frame */
568182071cdSLorenzo Bianconi 		txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
569182071cdSLorenzo Bianconi 
570182071cdSLorenzo Bianconi 		val |= FIELD_PREP(MT_TXD6_TX_RATE, rate);
571182071cdSLorenzo Bianconi 		txwi[6] |= cpu_to_le32(val);
572182071cdSLorenzo Bianconi 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
573faf2e7b5SShayne Chen 
574faf2e7b5SShayne Chen 		if (!is_mt7921(dev)) {
575faf2e7b5SShayne Chen 			u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
576faf2e7b5SShayne Chen 
577faf2e7b5SShayne Chen 			if (!spe_idx)
578faf2e7b5SShayne Chen 				spe_idx = 24 + phy_idx;
579faf2e7b5SShayne Chen 			txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));
580faf2e7b5SShayne Chen 		}
581182071cdSLorenzo Bianconi 	}
582182071cdSLorenzo Bianconi }
583182071cdSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi);
584b932425bSLorenzo Bianconi 
mt76_connac2_mac_fill_txs(struct mt76_dev * dev,struct mt76_wcid * wcid,__le32 * txs_data)58543eaa368SRyder Lee bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
58643eaa368SRyder Lee 			       __le32 *txs_data)
587b932425bSLorenzo Bianconi {
588dc877523SRyder Lee 	struct mt76_sta_stats *stats = &wcid->stats;
589b932425bSLorenzo Bianconi 	struct ieee80211_supported_band *sband;
590b932425bSLorenzo Bianconi 	struct mt76_phy *mphy;
591b932425bSLorenzo Bianconi 	struct rate_info rate = {};
592b932425bSLorenzo Bianconi 	bool cck = false;
593fa67120bSEvelyn Tsai 	u32 txrate, txs, mode, stbc;
594b932425bSLorenzo Bianconi 
595b932425bSLorenzo Bianconi 	txs = le32_to_cpu(txs_data[0]);
596b932425bSLorenzo Bianconi 
59743eaa368SRyder Lee 	/* PPDU based reporting */
598161a7528SPeter Chiu 	if (mtk_wed_device_active(&dev->mmio.wed) &&
599161a7528SPeter Chiu 	    FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
60043eaa368SRyder Lee 		stats->tx_bytes +=
601c7ab7a29SRyder Lee 			le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) -
602c7ab7a29SRyder Lee 			le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE);
60343eaa368SRyder Lee 		stats->tx_failed +=
60443eaa368SRyder Lee 			le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
60543eaa368SRyder Lee 		stats->tx_retries +=
60643eaa368SRyder Lee 			le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT);
6071a1ff6c3SRyder Lee 
6081a1ff6c3SRyder Lee 		if (wcid->sta) {
6091a1ff6c3SRyder Lee 			struct ieee80211_sta *sta;
6101a1ff6c3SRyder Lee 			u8 tid;
6111a1ff6c3SRyder Lee 
6121a1ff6c3SRyder Lee 			sta = container_of((void *)wcid, struct ieee80211_sta,
6131a1ff6c3SRyder Lee 					   drv_priv);
6141a1ff6c3SRyder Lee 			tid = FIELD_GET(MT_TXS0_TID, txs);
6151a1ff6c3SRyder Lee 
6161a1ff6c3SRyder Lee 			ieee80211_refresh_tx_agg_session_timer(sta, tid);
6171a1ff6c3SRyder Lee 		}
61843eaa368SRyder Lee 	}
619b932425bSLorenzo Bianconi 
620b932425bSLorenzo Bianconi 	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
621b932425bSLorenzo Bianconi 
622b932425bSLorenzo Bianconi 	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
623b932425bSLorenzo Bianconi 	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
624fa67120bSEvelyn Tsai 	stbc = FIELD_GET(MT_TX_RATE_STBC, txrate);
625fa67120bSEvelyn Tsai 
626fa67120bSEvelyn Tsai 	if (stbc && rate.nss > 1)
627fa67120bSEvelyn Tsai 		rate.nss >>= 1;
628b932425bSLorenzo Bianconi 
629b932425bSLorenzo Bianconi 	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
630b932425bSLorenzo Bianconi 		stats->tx_nss[rate.nss - 1]++;
631b932425bSLorenzo Bianconi 	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
632b932425bSLorenzo Bianconi 		stats->tx_mcs[rate.mcs]++;
633b932425bSLorenzo Bianconi 
634b932425bSLorenzo Bianconi 	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
635b932425bSLorenzo Bianconi 	switch (mode) {
636b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_CCK:
637b932425bSLorenzo Bianconi 		cck = true;
638b932425bSLorenzo Bianconi 		fallthrough;
639b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_OFDM:
640b932425bSLorenzo Bianconi 		mphy = &dev->phy;
641a1a99d7bSLorenzo Bianconi 		if (wcid->phy_idx == MT_BAND1 && dev->phys[MT_BAND1])
642dc44c45cSLorenzo Bianconi 			mphy = dev->phys[MT_BAND1];
643b932425bSLorenzo Bianconi 
644b932425bSLorenzo Bianconi 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
645b932425bSLorenzo Bianconi 			sband = &mphy->sband_5g.sband;
646b932425bSLorenzo Bianconi 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
647b932425bSLorenzo Bianconi 			sband = &mphy->sband_6g.sband;
648b932425bSLorenzo Bianconi 		else
649b932425bSLorenzo Bianconi 			sband = &mphy->sband_2g.sband;
650b932425bSLorenzo Bianconi 
651b932425bSLorenzo Bianconi 		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
652b932425bSLorenzo Bianconi 		rate.legacy = sband->bitrates[rate.mcs].bitrate;
653b932425bSLorenzo Bianconi 		break;
654b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HT:
655b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HT_GF:
656b932425bSLorenzo Bianconi 		if (rate.mcs > 31)
65743eaa368SRyder Lee 			return false;
658b932425bSLorenzo Bianconi 
659b932425bSLorenzo Bianconi 		rate.flags = RATE_INFO_FLAGS_MCS;
660b932425bSLorenzo Bianconi 		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
661b932425bSLorenzo Bianconi 			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
662b932425bSLorenzo Bianconi 		break;
663b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_VHT:
664b932425bSLorenzo Bianconi 		if (rate.mcs > 9)
66543eaa368SRyder Lee 			return false;
666b932425bSLorenzo Bianconi 
667b932425bSLorenzo Bianconi 		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
668b932425bSLorenzo Bianconi 		break;
669b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HE_SU:
670b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HE_EXT_SU:
671b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HE_TB:
672b932425bSLorenzo Bianconi 	case MT_PHY_TYPE_HE_MU:
673b932425bSLorenzo Bianconi 		if (rate.mcs > 11)
67443eaa368SRyder Lee 			return false;
675b932425bSLorenzo Bianconi 
676b932425bSLorenzo Bianconi 		rate.he_gi = wcid->rate.he_gi;
677b932425bSLorenzo Bianconi 		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
678b932425bSLorenzo Bianconi 		rate.flags = RATE_INFO_FLAGS_HE_MCS;
679b932425bSLorenzo Bianconi 		break;
680b932425bSLorenzo Bianconi 	default:
68143eaa368SRyder Lee 		return false;
682b932425bSLorenzo Bianconi 	}
683b932425bSLorenzo Bianconi 
684b932425bSLorenzo Bianconi 	stats->tx_mode[mode]++;
685b932425bSLorenzo Bianconi 
686b932425bSLorenzo Bianconi 	switch (FIELD_GET(MT_TXS0_BW, txs)) {
687b932425bSLorenzo Bianconi 	case IEEE80211_STA_RX_BW_160:
688b932425bSLorenzo Bianconi 		rate.bw = RATE_INFO_BW_160;
689b932425bSLorenzo Bianconi 		stats->tx_bw[3]++;
690b932425bSLorenzo Bianconi 		break;
691b932425bSLorenzo Bianconi 	case IEEE80211_STA_RX_BW_80:
692b932425bSLorenzo Bianconi 		rate.bw = RATE_INFO_BW_80;
693b932425bSLorenzo Bianconi 		stats->tx_bw[2]++;
694b932425bSLorenzo Bianconi 		break;
695b932425bSLorenzo Bianconi 	case IEEE80211_STA_RX_BW_40:
696b932425bSLorenzo Bianconi 		rate.bw = RATE_INFO_BW_40;
697b932425bSLorenzo Bianconi 		stats->tx_bw[1]++;
698b932425bSLorenzo Bianconi 		break;
699b932425bSLorenzo Bianconi 	default:
700b932425bSLorenzo Bianconi 		rate.bw = RATE_INFO_BW_20;
701b932425bSLorenzo Bianconi 		stats->tx_bw[0]++;
702b932425bSLorenzo Bianconi 		break;
703b932425bSLorenzo Bianconi 	}
704b932425bSLorenzo Bianconi 	wcid->rate = rate;
705b932425bSLorenzo Bianconi 
70643eaa368SRyder Lee 	return true;
70743eaa368SRyder Lee }
70843eaa368SRyder Lee EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_txs);
709b932425bSLorenzo Bianconi 
mt76_connac2_mac_add_txs_skb(struct mt76_dev * dev,struct mt76_wcid * wcid,int pid,__le32 * txs_data)71043eaa368SRyder Lee bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
71143eaa368SRyder Lee 				  int pid, __le32 *txs_data)
71243eaa368SRyder Lee {
71343eaa368SRyder Lee 	struct sk_buff_head list;
71443eaa368SRyder Lee 	struct sk_buff *skb;
71543eaa368SRyder Lee 
71643eaa368SRyder Lee 	mt76_tx_status_lock(dev, &list);
71743eaa368SRyder Lee 	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
71843eaa368SRyder Lee 	if (skb) {
71943eaa368SRyder Lee 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
72043eaa368SRyder Lee 
72143eaa368SRyder Lee 		if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK))
72243eaa368SRyder Lee 			info->flags |= IEEE80211_TX_STAT_ACK;
72343eaa368SRyder Lee 
72443eaa368SRyder Lee 		info->status.ampdu_len = 1;
725943e4fb9SRyder Lee 		info->status.ampdu_ack_len =
726943e4fb9SRyder Lee 			!!(info->flags & IEEE80211_TX_STAT_ACK);
72743eaa368SRyder Lee 		info->status.rates[0].idx = -1;
72843eaa368SRyder Lee 
72943eaa368SRyder Lee 		mt76_connac2_mac_fill_txs(dev, wcid, txs_data);
73043eaa368SRyder Lee 		mt76_tx_status_skb_done(dev, skb, &list);
73143eaa368SRyder Lee 	}
732b932425bSLorenzo Bianconi 	mt76_tx_status_unlock(dev, &list);
733b932425bSLorenzo Bianconi 
734b932425bSLorenzo Bianconi 	return !!skb;
735b932425bSLorenzo Bianconi }
736b932425bSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb);
737f71662deSLorenzo Bianconi 
738f71662deSLorenzo Bianconi static void
mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status * status,struct ieee80211_radiotap_he * he,__le32 * rxv)739f71662deSLorenzo Bianconi mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
740f71662deSLorenzo Bianconi 				       struct ieee80211_radiotap_he *he,
741f71662deSLorenzo Bianconi 				       __le32 *rxv)
742f71662deSLorenzo Bianconi {
743f71662deSLorenzo Bianconi 	u32 ru_h, ru_l;
744f71662deSLorenzo Bianconi 	u8 ru, offs = 0;
745f71662deSLorenzo Bianconi 
746f71662deSLorenzo Bianconi 	ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);
747f71662deSLorenzo Bianconi 	ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);
748f71662deSLorenzo Bianconi 	ru = (u8)(ru_l | ru_h << 4);
749f71662deSLorenzo Bianconi 
750f71662deSLorenzo Bianconi 	status->bw = RATE_INFO_BW_HE_RU;
751f71662deSLorenzo Bianconi 
752f71662deSLorenzo Bianconi 	switch (ru) {
753f71662deSLorenzo Bianconi 	case 0 ... 36:
754f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
755f71662deSLorenzo Bianconi 		offs = ru;
756f71662deSLorenzo Bianconi 		break;
757f71662deSLorenzo Bianconi 	case 37 ... 52:
758f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
759f71662deSLorenzo Bianconi 		offs = ru - 37;
760f71662deSLorenzo Bianconi 		break;
761f71662deSLorenzo Bianconi 	case 53 ... 60:
762f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
763f71662deSLorenzo Bianconi 		offs = ru - 53;
764f71662deSLorenzo Bianconi 		break;
765f71662deSLorenzo Bianconi 	case 61 ... 64:
766f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
767f71662deSLorenzo Bianconi 		offs = ru - 61;
768f71662deSLorenzo Bianconi 		break;
769f71662deSLorenzo Bianconi 	case 65 ... 66:
770f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
771f71662deSLorenzo Bianconi 		offs = ru - 65;
772f71662deSLorenzo Bianconi 		break;
773f71662deSLorenzo Bianconi 	case 67:
774f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
775f71662deSLorenzo Bianconi 		break;
776f71662deSLorenzo Bianconi 	case 68:
777f71662deSLorenzo Bianconi 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
778f71662deSLorenzo Bianconi 		break;
779f71662deSLorenzo Bianconi 	}
780f71662deSLorenzo Bianconi 
781f71662deSLorenzo Bianconi 	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
782f71662deSLorenzo Bianconi 	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
783f71662deSLorenzo Bianconi 		     le16_encode_bits(offs,
784f71662deSLorenzo Bianconi 				      IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
785f71662deSLorenzo Bianconi }
786f71662deSLorenzo Bianconi 
787f71662deSLorenzo Bianconi static void
mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev * dev,struct sk_buff * skb,__le32 * rxv)788f71662deSLorenzo Bianconi mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb,
789f71662deSLorenzo Bianconi 				       __le32 *rxv)
790f71662deSLorenzo Bianconi {
791f71662deSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
792f71662deSLorenzo Bianconi 	static struct ieee80211_radiotap_he_mu mu_known = {
793f71662deSLorenzo Bianconi 		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
794f71662deSLorenzo Bianconi 			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
795f71662deSLorenzo Bianconi 			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
796f71662deSLorenzo Bianconi 			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
797f71662deSLorenzo Bianconi 		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
798f71662deSLorenzo Bianconi 	};
799f71662deSLorenzo Bianconi 	struct ieee80211_radiotap_he_mu *he_mu;
800f71662deSLorenzo Bianconi 
801f71662deSLorenzo Bianconi 	if (is_mt7921(dev)) {
802f71662deSLorenzo Bianconi 		mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN);
803f71662deSLorenzo Bianconi 		mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN);
804f71662deSLorenzo Bianconi 	}
805f71662deSLorenzo Bianconi 
806f71662deSLorenzo Bianconi 	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
807f71662deSLorenzo Bianconi 
808f71662deSLorenzo Bianconi 	he_mu = skb_push(skb, sizeof(mu_known));
809f71662deSLorenzo Bianconi 	memcpy(he_mu, &mu_known, sizeof(mu_known));
810f71662deSLorenzo Bianconi 
811f71662deSLorenzo Bianconi #define MU_PREP(f, v)	le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
812f71662deSLorenzo Bianconi 
813f71662deSLorenzo Bianconi 	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
814f71662deSLorenzo Bianconi 	if (status->he_dcm)
815f71662deSLorenzo Bianconi 		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
816f71662deSLorenzo Bianconi 
817f71662deSLorenzo Bianconi 	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
818f71662deSLorenzo Bianconi 			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
819f71662deSLorenzo Bianconi 				 le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
820f71662deSLorenzo Bianconi 
821f71662deSLorenzo Bianconi 	he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
822f71662deSLorenzo Bianconi 
823f71662deSLorenzo Bianconi 	if (status->bw >= RATE_INFO_BW_40) {
824f71662deSLorenzo Bianconi 		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
825f71662deSLorenzo Bianconi 		he_mu->ru_ch2[0] =
826f71662deSLorenzo Bianconi 			le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
827f71662deSLorenzo Bianconi 	}
828f71662deSLorenzo Bianconi 
829f71662deSLorenzo Bianconi 	if (status->bw >= RATE_INFO_BW_80) {
830f71662deSLorenzo Bianconi 		he_mu->ru_ch1[1] =
831f71662deSLorenzo Bianconi 			le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
832f71662deSLorenzo Bianconi 		he_mu->ru_ch2[1] =
833f71662deSLorenzo Bianconi 			le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
834f71662deSLorenzo Bianconi 	}
835f71662deSLorenzo Bianconi }
836f71662deSLorenzo Bianconi 
mt76_connac2_mac_decode_he_radiotap(struct mt76_dev * dev,struct sk_buff * skb,__le32 * rxv,u32 mode)837f71662deSLorenzo Bianconi void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
838f71662deSLorenzo Bianconi 					 struct sk_buff *skb,
839f71662deSLorenzo Bianconi 					 __le32 *rxv, u32 mode)
840f71662deSLorenzo Bianconi {
841f71662deSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
842f71662deSLorenzo Bianconi 	static const struct ieee80211_radiotap_he known = {
843f71662deSLorenzo Bianconi 		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
844f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
845f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_STBC_KNOWN) |
846f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_CODING_KNOWN) |
847f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
848f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_DOPPLER_KNOWN) |
849f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
850f71662deSLorenzo Bianconi 			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
851f71662deSLorenzo Bianconi 		.data2 = HE_BITS(DATA2_GI_KNOWN) |
852f71662deSLorenzo Bianconi 			 HE_BITS(DATA2_TXBF_KNOWN) |
853f71662deSLorenzo Bianconi 			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
854f71662deSLorenzo Bianconi 			 HE_BITS(DATA2_TXOP_KNOWN),
855f71662deSLorenzo Bianconi 	};
856f71662deSLorenzo Bianconi 	u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
857f71662deSLorenzo Bianconi 	struct ieee80211_radiotap_he *he;
858f71662deSLorenzo Bianconi 
859f71662deSLorenzo Bianconi 	status->flag |= RX_FLAG_RADIOTAP_HE;
860f71662deSLorenzo Bianconi 
861f71662deSLorenzo Bianconi 	he = skb_push(skb, sizeof(known));
862f71662deSLorenzo Bianconi 	memcpy(he, &known, sizeof(known));
863f71662deSLorenzo Bianconi 
864f71662deSLorenzo Bianconi 	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
865f71662deSLorenzo Bianconi 		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
866f71662deSLorenzo Bianconi 	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
867f71662deSLorenzo Bianconi 	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
868f71662deSLorenzo Bianconi 		    le16_encode_bits(ltf_size,
869f71662deSLorenzo Bianconi 				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
870f71662deSLorenzo Bianconi 	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
871f71662deSLorenzo Bianconi 		he->data5 |= HE_BITS(DATA5_TXBF);
872f71662deSLorenzo Bianconi 	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
873f71662deSLorenzo Bianconi 		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
874f71662deSLorenzo Bianconi 
875f71662deSLorenzo Bianconi 	switch (mode) {
876f71662deSLorenzo Bianconi 	case MT_PHY_TYPE_HE_SU:
877f71662deSLorenzo Bianconi 		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
878f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_UL_DL_KNOWN) |
879f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
880f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
881f71662deSLorenzo Bianconi 
882f71662deSLorenzo Bianconi 		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
883f71662deSLorenzo Bianconi 			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
884f71662deSLorenzo Bianconi 		break;
885f71662deSLorenzo Bianconi 	case MT_PHY_TYPE_HE_EXT_SU:
886f71662deSLorenzo Bianconi 		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
887f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_UL_DL_KNOWN) |
888f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
889f71662deSLorenzo Bianconi 
890f71662deSLorenzo Bianconi 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
891f71662deSLorenzo Bianconi 		break;
892f71662deSLorenzo Bianconi 	case MT_PHY_TYPE_HE_MU:
893f71662deSLorenzo Bianconi 		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
894f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_UL_DL_KNOWN);
895f71662deSLorenzo Bianconi 
896f71662deSLorenzo Bianconi 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
897f71662deSLorenzo Bianconi 		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
898f71662deSLorenzo Bianconi 
899f71662deSLorenzo Bianconi 		mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);
900f71662deSLorenzo Bianconi 		mt76_connac2_mac_decode_he_mu_radiotap(dev, skb, rxv);
901f71662deSLorenzo Bianconi 		break;
902f71662deSLorenzo Bianconi 	case MT_PHY_TYPE_HE_TB:
903f71662deSLorenzo Bianconi 		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
904f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
905f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
906f71662deSLorenzo Bianconi 			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
907f71662deSLorenzo Bianconi 
908f71662deSLorenzo Bianconi 		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
909f71662deSLorenzo Bianconi 			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
910f71662deSLorenzo Bianconi 			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
911f71662deSLorenzo Bianconi 			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
912f71662deSLorenzo Bianconi 
913f71662deSLorenzo Bianconi 		mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv);
914f71662deSLorenzo Bianconi 		break;
915f71662deSLorenzo Bianconi 	default:
916f71662deSLorenzo Bianconi 		break;
917f71662deSLorenzo Bianconi 	}
918f71662deSLorenzo Bianconi }
919f71662deSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap);
9200880d408SLorenzo Bianconi 
9210880d408SLorenzo Bianconi /* The HW does not translate the mac header to 802.3 for mesh point */
mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif * vif,struct sk_buff * skb,u16 hdr_offset)9220880d408SLorenzo Bianconi int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif,
9230880d408SLorenzo Bianconi 					 struct sk_buff *skb, u16 hdr_offset)
9240880d408SLorenzo Bianconi {
9250880d408SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9260880d408SLorenzo Bianconi 	struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_offset);
9270880d408SLorenzo Bianconi 	__le32 *rxd = (__le32 *)skb->data;
9280880d408SLorenzo Bianconi 	struct ieee80211_sta *sta;
9290880d408SLorenzo Bianconi 	struct ieee80211_hdr hdr;
9300880d408SLorenzo Bianconi 	u16 frame_control;
9310880d408SLorenzo Bianconi 
9320880d408SLorenzo Bianconi 	if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
9330880d408SLorenzo Bianconi 	    MT_RXD3_NORMAL_U2M)
9340880d408SLorenzo Bianconi 		return -EINVAL;
9350880d408SLorenzo Bianconi 
9360880d408SLorenzo Bianconi 	if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
9370880d408SLorenzo Bianconi 		return -EINVAL;
9380880d408SLorenzo Bianconi 
9390880d408SLorenzo Bianconi 	sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv);
9400880d408SLorenzo Bianconi 
9410880d408SLorenzo Bianconi 	/* store the info from RXD and ethhdr to avoid being overridden */
9420880d408SLorenzo Bianconi 	frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL);
9430880d408SLorenzo Bianconi 	hdr.frame_control = cpu_to_le16(frame_control);
9440880d408SLorenzo Bianconi 	hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL));
9450880d408SLorenzo Bianconi 	hdr.duration_id = 0;
9460880d408SLorenzo Bianconi 
9470880d408SLorenzo Bianconi 	ether_addr_copy(hdr.addr1, vif->addr);
9480880d408SLorenzo Bianconi 	ether_addr_copy(hdr.addr2, sta->addr);
9490880d408SLorenzo Bianconi 	switch (frame_control & (IEEE80211_FCTL_TODS |
9500880d408SLorenzo Bianconi 				 IEEE80211_FCTL_FROMDS)) {
9510880d408SLorenzo Bianconi 	case 0:
9520880d408SLorenzo Bianconi 		ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
9530880d408SLorenzo Bianconi 		break;
9540880d408SLorenzo Bianconi 	case IEEE80211_FCTL_FROMDS:
9550880d408SLorenzo Bianconi 		ether_addr_copy(hdr.addr3, eth_hdr->h_source);
9560880d408SLorenzo Bianconi 		break;
9570880d408SLorenzo Bianconi 	case IEEE80211_FCTL_TODS:
9580880d408SLorenzo Bianconi 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
9590880d408SLorenzo Bianconi 		break;
9600880d408SLorenzo Bianconi 	case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
9610880d408SLorenzo Bianconi 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
9620880d408SLorenzo Bianconi 		ether_addr_copy(hdr.addr4, eth_hdr->h_source);
9630880d408SLorenzo Bianconi 		break;
9640880d408SLorenzo Bianconi 	default:
9650ffcb2a6SDeren Wu 		return -EINVAL;
9660880d408SLorenzo Bianconi 	}
9670880d408SLorenzo Bianconi 
9680880d408SLorenzo Bianconi 	skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2);
9690880d408SLorenzo Bianconi 	if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
9700880d408SLorenzo Bianconi 	    eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
9710880d408SLorenzo Bianconi 		ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
9720880d408SLorenzo Bianconi 	else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
9730880d408SLorenzo Bianconi 		ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
9740880d408SLorenzo Bianconi 	else
9750880d408SLorenzo Bianconi 		skb_pull(skb, 2);
9760880d408SLorenzo Bianconi 
9770880d408SLorenzo Bianconi 	if (ieee80211_has_order(hdr.frame_control))
9780880d408SLorenzo Bianconi 		memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9],
9790880d408SLorenzo Bianconi 		       IEEE80211_HT_CTL_LEN);
9800880d408SLorenzo Bianconi 	if (ieee80211_is_data_qos(hdr.frame_control)) {
9810880d408SLorenzo Bianconi 		__le16 qos_ctrl;
9820880d408SLorenzo Bianconi 
9830880d408SLorenzo Bianconi 		qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL));
9840880d408SLorenzo Bianconi 		memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
9850880d408SLorenzo Bianconi 		       IEEE80211_QOS_CTL_LEN);
9860880d408SLorenzo Bianconi 	}
9870880d408SLorenzo Bianconi 
9880880d408SLorenzo Bianconi 	if (ieee80211_has_a4(hdr.frame_control))
9890880d408SLorenzo Bianconi 		memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
9900880d408SLorenzo Bianconi 	else
9910880d408SLorenzo Bianconi 		memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
9920880d408SLorenzo Bianconi 
9930880d408SLorenzo Bianconi 	return 0;
9940880d408SLorenzo Bianconi }
9950880d408SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans);
996d832f5e7SLorenzo Bianconi 
mt76_connac2_mac_fill_rx_rate(struct mt76_dev * dev,struct mt76_rx_status * status,struct ieee80211_supported_band * sband,__le32 * rxv,u8 * mode)997d832f5e7SLorenzo Bianconi int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
998d832f5e7SLorenzo Bianconi 				  struct mt76_rx_status *status,
999d832f5e7SLorenzo Bianconi 				  struct ieee80211_supported_band *sband,
1000d832f5e7SLorenzo Bianconi 				  __le32 *rxv, u8 *mode)
1001d832f5e7SLorenzo Bianconi {
1002d832f5e7SLorenzo Bianconi 	u32 v0, v2;
1003d832f5e7SLorenzo Bianconi 	u8 stbc, gi, bw, dcm, nss;
1004d832f5e7SLorenzo Bianconi 	int i, idx;
1005d832f5e7SLorenzo Bianconi 	bool cck = false;
1006d832f5e7SLorenzo Bianconi 
1007d832f5e7SLorenzo Bianconi 	v0 = le32_to_cpu(rxv[0]);
1008d832f5e7SLorenzo Bianconi 	v2 = le32_to_cpu(rxv[2]);
1009d832f5e7SLorenzo Bianconi 
1010d832f5e7SLorenzo Bianconi 	idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0);
1011d832f5e7SLorenzo Bianconi 	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
1012d832f5e7SLorenzo Bianconi 
1013d832f5e7SLorenzo Bianconi 	if (!is_mt7915(dev)) {
1014d832f5e7SLorenzo Bianconi 		stbc = FIELD_GET(MT_PRXV_HT_STBC, v0);
1015d832f5e7SLorenzo Bianconi 		gi = FIELD_GET(MT_PRXV_HT_SGI, v0);
1016d832f5e7SLorenzo Bianconi 		*mode = FIELD_GET(MT_PRXV_TX_MODE, v0);
1017d832f5e7SLorenzo Bianconi 		if (is_mt7921(dev))
1018d832f5e7SLorenzo Bianconi 			dcm = !!(idx & MT_PRXV_TX_DCM);
1019d832f5e7SLorenzo Bianconi 		else
1020d832f5e7SLorenzo Bianconi 			dcm = FIELD_GET(MT_PRXV_DCM, v0);
1021d832f5e7SLorenzo Bianconi 		bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0);
1022d832f5e7SLorenzo Bianconi 	} else {
1023d832f5e7SLorenzo Bianconi 		stbc = FIELD_GET(MT_CRXV_HT_STBC, v2);
1024d832f5e7SLorenzo Bianconi 		gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2);
1025d832f5e7SLorenzo Bianconi 		*mode = FIELD_GET(MT_CRXV_TX_MODE, v2);
1026d832f5e7SLorenzo Bianconi 		dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM);
1027d832f5e7SLorenzo Bianconi 		bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2);
1028d832f5e7SLorenzo Bianconi 	}
1029d832f5e7SLorenzo Bianconi 
1030d832f5e7SLorenzo Bianconi 	switch (*mode) {
1031d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_CCK:
1032d832f5e7SLorenzo Bianconi 		cck = true;
1033d832f5e7SLorenzo Bianconi 		fallthrough;
1034d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_OFDM:
1035d832f5e7SLorenzo Bianconi 		i = mt76_get_rate(dev, sband, i, cck);
1036d832f5e7SLorenzo Bianconi 		break;
1037d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HT_GF:
1038d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HT:
1039d832f5e7SLorenzo Bianconi 		status->encoding = RX_ENC_HT;
1040d832f5e7SLorenzo Bianconi 		if (gi)
1041d832f5e7SLorenzo Bianconi 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
1042d832f5e7SLorenzo Bianconi 		if (i > 31)
1043d832f5e7SLorenzo Bianconi 			return -EINVAL;
1044d832f5e7SLorenzo Bianconi 		break;
1045d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_VHT:
1046d832f5e7SLorenzo Bianconi 		status->nss = nss;
1047d832f5e7SLorenzo Bianconi 		status->encoding = RX_ENC_VHT;
1048d832f5e7SLorenzo Bianconi 		if (gi)
1049d832f5e7SLorenzo Bianconi 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
1050d832f5e7SLorenzo Bianconi 		if (i > 11)
1051d832f5e7SLorenzo Bianconi 			return -EINVAL;
1052d832f5e7SLorenzo Bianconi 		break;
1053d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HE_MU:
1054d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HE_SU:
1055d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HE_EXT_SU:
1056d832f5e7SLorenzo Bianconi 	case MT_PHY_TYPE_HE_TB:
1057d832f5e7SLorenzo Bianconi 		status->nss = nss;
1058d832f5e7SLorenzo Bianconi 		status->encoding = RX_ENC_HE;
1059d832f5e7SLorenzo Bianconi 		i &= GENMASK(3, 0);
1060d832f5e7SLorenzo Bianconi 
1061d832f5e7SLorenzo Bianconi 		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
1062d832f5e7SLorenzo Bianconi 			status->he_gi = gi;
1063d832f5e7SLorenzo Bianconi 
1064d832f5e7SLorenzo Bianconi 		status->he_dcm = dcm;
1065d832f5e7SLorenzo Bianconi 		break;
1066d832f5e7SLorenzo Bianconi 	default:
1067d832f5e7SLorenzo Bianconi 		return -EINVAL;
1068d832f5e7SLorenzo Bianconi 	}
1069d832f5e7SLorenzo Bianconi 	status->rate_idx = i;
1070d832f5e7SLorenzo Bianconi 
1071d832f5e7SLorenzo Bianconi 	switch (bw) {
1072d832f5e7SLorenzo Bianconi 	case IEEE80211_STA_RX_BW_20:
1073d832f5e7SLorenzo Bianconi 		break;
1074d832f5e7SLorenzo Bianconi 	case IEEE80211_STA_RX_BW_40:
1075d832f5e7SLorenzo Bianconi 		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
1076d832f5e7SLorenzo Bianconi 		    (idx & MT_PRXV_TX_ER_SU_106T)) {
1077d832f5e7SLorenzo Bianconi 			status->bw = RATE_INFO_BW_HE_RU;
1078d832f5e7SLorenzo Bianconi 			status->he_ru =
1079d832f5e7SLorenzo Bianconi 				NL80211_RATE_INFO_HE_RU_ALLOC_106;
1080d832f5e7SLorenzo Bianconi 		} else {
1081d832f5e7SLorenzo Bianconi 			status->bw = RATE_INFO_BW_40;
1082d832f5e7SLorenzo Bianconi 		}
1083d832f5e7SLorenzo Bianconi 		break;
1084d832f5e7SLorenzo Bianconi 	case IEEE80211_STA_RX_BW_80:
1085d832f5e7SLorenzo Bianconi 		status->bw = RATE_INFO_BW_80;
1086d832f5e7SLorenzo Bianconi 		break;
1087d832f5e7SLorenzo Bianconi 	case IEEE80211_STA_RX_BW_160:
1088d832f5e7SLorenzo Bianconi 		status->bw = RATE_INFO_BW_160;
1089d832f5e7SLorenzo Bianconi 		break;
1090d832f5e7SLorenzo Bianconi 	default:
1091d832f5e7SLorenzo Bianconi 		return -EINVAL;
1092d832f5e7SLorenzo Bianconi 	}
1093d832f5e7SLorenzo Bianconi 
1094d832f5e7SLorenzo Bianconi 	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
1095d832f5e7SLorenzo Bianconi 	if (*mode < MT_PHY_TYPE_HE_SU && gi)
1096d832f5e7SLorenzo Bianconi 		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
1097d832f5e7SLorenzo Bianconi 
1098d832f5e7SLorenzo Bianconi 	return 0;
1099d832f5e7SLorenzo Bianconi }
1100d832f5e7SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate);
1101c8e370feSLorenzo Bianconi 
mt76_connac2_tx_check_aggr(struct ieee80211_sta * sta,__le32 * txwi)1102c8e370feSLorenzo Bianconi void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
1103c8e370feSLorenzo Bianconi {
1104c8e370feSLorenzo Bianconi 	struct mt76_wcid *wcid;
1105c8e370feSLorenzo Bianconi 	u16 fc, tid;
1106c8e370feSLorenzo Bianconi 	u32 val;
1107c8e370feSLorenzo Bianconi 
1108c8e370feSLorenzo Bianconi 	if (!sta ||
1109c8e370feSLorenzo Bianconi 	    !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
1110c8e370feSLorenzo Bianconi 		return;
1111c8e370feSLorenzo Bianconi 
1112c8e370feSLorenzo Bianconi 	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
1113c8e370feSLorenzo Bianconi 	if (tid >= 6) /* skip VO queue */
1114c8e370feSLorenzo Bianconi 		return;
1115c8e370feSLorenzo Bianconi 
1116c8e370feSLorenzo Bianconi 	val = le32_to_cpu(txwi[2]);
1117c8e370feSLorenzo Bianconi 	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
1118c8e370feSLorenzo Bianconi 	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
1119c8e370feSLorenzo Bianconi 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
1120c8e370feSLorenzo Bianconi 		return;
1121c8e370feSLorenzo Bianconi 
1122c8e370feSLorenzo Bianconi 	wcid = (struct mt76_wcid *)sta->drv_priv;
1123c8e370feSLorenzo Bianconi 	if (!test_and_set_bit(tid, &wcid->ampdu_state))
1124c8e370feSLorenzo Bianconi 		ieee80211_start_tx_ba_session(sta, tid, 0);
1125c8e370feSLorenzo Bianconi }
1126c8e370feSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);
1127c8e370feSLorenzo Bianconi 
mt76_connac2_txwi_free(struct mt76_dev * dev,struct mt76_txwi_cache * t,struct ieee80211_sta * sta,struct list_head * free_list)1128c8e370feSLorenzo Bianconi void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
1129c8e370feSLorenzo Bianconi 			    struct ieee80211_sta *sta,
1130c8e370feSLorenzo Bianconi 			    struct list_head *free_list)
1131c8e370feSLorenzo Bianconi {
1132c8e370feSLorenzo Bianconi 	struct mt76_wcid *wcid;
1133c8e370feSLorenzo Bianconi 	__le32 *txwi;
1134c8e370feSLorenzo Bianconi 	u16 wcid_idx;
1135c8e370feSLorenzo Bianconi 
1136c8e370feSLorenzo Bianconi 	mt76_connac_txp_skb_unmap(dev, t);
1137c8e370feSLorenzo Bianconi 	if (!t->skb)
1138c8e370feSLorenzo Bianconi 		goto out;
1139c8e370feSLorenzo Bianconi 
1140c8e370feSLorenzo Bianconi 	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
1141c8e370feSLorenzo Bianconi 	if (sta) {
1142c8e370feSLorenzo Bianconi 		wcid = (struct mt76_wcid *)sta->drv_priv;
1143c8e370feSLorenzo Bianconi 		wcid_idx = wcid->idx;
1144c8e370feSLorenzo Bianconi 	} else {
1145c8e370feSLorenzo Bianconi 		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
1146c8e370feSLorenzo Bianconi 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
1147c8e370feSLorenzo Bianconi 
1148c8e370feSLorenzo Bianconi 		if (wcid && wcid->sta) {
1149c8e370feSLorenzo Bianconi 			sta = container_of((void *)wcid, struct ieee80211_sta,
1150c8e370feSLorenzo Bianconi 					   drv_priv);
1151c8e370feSLorenzo Bianconi 			spin_lock_bh(&dev->sta_poll_lock);
1152c8e370feSLorenzo Bianconi 			if (list_empty(&wcid->poll_list))
1153c8e370feSLorenzo Bianconi 				list_add_tail(&wcid->poll_list,
1154c8e370feSLorenzo Bianconi 					      &dev->sta_poll_list);
1155c8e370feSLorenzo Bianconi 			spin_unlock_bh(&dev->sta_poll_lock);
1156c8e370feSLorenzo Bianconi 		}
1157c8e370feSLorenzo Bianconi 	}
1158c8e370feSLorenzo Bianconi 
1159c8e370feSLorenzo Bianconi 	if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
1160c8e370feSLorenzo Bianconi 		mt76_connac2_tx_check_aggr(sta, txwi);
1161c8e370feSLorenzo Bianconi 
1162c8e370feSLorenzo Bianconi 	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
1163c8e370feSLorenzo Bianconi out:
1164c8e370feSLorenzo Bianconi 	t->skb = NULL;
1165c8e370feSLorenzo Bianconi 	mt76_put_txwi(dev, t);
1166c8e370feSLorenzo Bianconi }
1167c8e370feSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free);
1168c8e370feSLorenzo Bianconi 
mt76_connac2_tx_token_put(struct mt76_dev * dev)1169c8e370feSLorenzo Bianconi void mt76_connac2_tx_token_put(struct mt76_dev *dev)
1170c8e370feSLorenzo Bianconi {
1171c8e370feSLorenzo Bianconi 	struct mt76_txwi_cache *txwi;
1172c8e370feSLorenzo Bianconi 	int id;
1173c8e370feSLorenzo Bianconi 
1174c8e370feSLorenzo Bianconi 	spin_lock_bh(&dev->token_lock);
1175c8e370feSLorenzo Bianconi 	idr_for_each_entry(&dev->token, txwi, id) {
1176c8e370feSLorenzo Bianconi 		mt76_connac2_txwi_free(dev, txwi, NULL, NULL);
1177c8e370feSLorenzo Bianconi 		dev->token_count--;
1178c8e370feSLorenzo Bianconi 	}
1179c8e370feSLorenzo Bianconi 	spin_unlock_bh(&dev->token_lock);
1180c8e370feSLorenzo Bianconi 	idr_destroy(&dev->token);
1181c8e370feSLorenzo Bianconi }
1182c8e370feSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);
1183