xref: /freebsd/sys/contrib/dev/mediatek/mt76/tx.c (revision cbb3ec25)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /*
36c92544dSBjoern A. Zeeb  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
46c92544dSBjoern A. Zeeb  */
56c92544dSBjoern A. Zeeb 
66c92544dSBjoern A. Zeeb #include "mt76.h"
76c92544dSBjoern A. Zeeb 
86c92544dSBjoern A. Zeeb static int
mt76_txq_get_qid(struct ieee80211_txq * txq)96c92544dSBjoern A. Zeeb mt76_txq_get_qid(struct ieee80211_txq *txq)
106c92544dSBjoern A. Zeeb {
116c92544dSBjoern A. Zeeb 	if (!txq->sta)
126c92544dSBjoern A. Zeeb 		return MT_TXQ_BE;
136c92544dSBjoern A. Zeeb 
146c92544dSBjoern A. Zeeb 	return txq->ac;
156c92544dSBjoern A. Zeeb }
166c92544dSBjoern A. Zeeb 
176c92544dSBjoern A. Zeeb void
mt76_tx_check_agg_ssn(struct ieee80211_sta * sta,struct sk_buff * skb)186c92544dSBjoern A. Zeeb mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb)
196c92544dSBjoern A. Zeeb {
206c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
216c92544dSBjoern A. Zeeb 	struct ieee80211_txq *txq;
226c92544dSBjoern A. Zeeb 	struct mt76_txq *mtxq;
236c92544dSBjoern A. Zeeb 	u8 tid;
246c92544dSBjoern A. Zeeb 
256c92544dSBjoern A. Zeeb 	if (!sta || !ieee80211_is_data_qos(hdr->frame_control) ||
266c92544dSBjoern A. Zeeb 	    !ieee80211_is_data_present(hdr->frame_control))
276c92544dSBjoern A. Zeeb 		return;
286c92544dSBjoern A. Zeeb 
296c92544dSBjoern A. Zeeb 	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
306c92544dSBjoern A. Zeeb 	txq = sta->txq[tid];
316c92544dSBjoern A. Zeeb 	mtxq = (struct mt76_txq *)txq->drv_priv;
326c92544dSBjoern A. Zeeb 	if (!mtxq->aggr)
336c92544dSBjoern A. Zeeb 		return;
346c92544dSBjoern A. Zeeb 
356c92544dSBjoern A. Zeeb 	mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
366c92544dSBjoern A. Zeeb }
376c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
386c92544dSBjoern A. Zeeb 
396c92544dSBjoern A. Zeeb void
mt76_tx_status_lock(struct mt76_dev * dev,struct sk_buff_head * list)406c92544dSBjoern A. Zeeb mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
416c92544dSBjoern A. Zeeb 		   __acquires(&dev->status_lock)
426c92544dSBjoern A. Zeeb {
436c92544dSBjoern A. Zeeb 	__skb_queue_head_init(list);
446c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->status_lock);
456c92544dSBjoern A. Zeeb }
466c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_lock);
476c92544dSBjoern A. Zeeb 
486c92544dSBjoern A. Zeeb void
mt76_tx_status_unlock(struct mt76_dev * dev,struct sk_buff_head * list)496c92544dSBjoern A. Zeeb mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
506c92544dSBjoern A. Zeeb 		      __releases(&dev->status_lock)
516c92544dSBjoern A. Zeeb {
526c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
536c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
546c92544dSBjoern A. Zeeb 
556c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->status_lock);
566c92544dSBjoern A. Zeeb 
576c92544dSBjoern A. Zeeb 	rcu_read_lock();
586c92544dSBjoern A. Zeeb 	while ((skb = __skb_dequeue(list)) != NULL) {
596c92544dSBjoern A. Zeeb 		struct ieee80211_tx_status status = {
606c92544dSBjoern A. Zeeb 			.skb = skb,
616c92544dSBjoern A. Zeeb 			.info = IEEE80211_SKB_CB(skb),
626c92544dSBjoern A. Zeeb 		};
636c92544dSBjoern A. Zeeb 		struct ieee80211_rate_status rs = {};
646c92544dSBjoern A. Zeeb 		struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
656c92544dSBjoern A. Zeeb 		struct mt76_wcid *wcid;
666c92544dSBjoern A. Zeeb 
676c92544dSBjoern A. Zeeb 		wcid = rcu_dereference(dev->wcid[cb->wcid]);
686c92544dSBjoern A. Zeeb 		if (wcid) {
696c92544dSBjoern A. Zeeb 			status.sta = wcid_to_sta(wcid);
706c92544dSBjoern A. Zeeb 			if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
716c92544dSBjoern A. Zeeb 				rs.rate_idx = wcid->rate;
726c92544dSBjoern A. Zeeb 				status.rates = &rs;
736c92544dSBjoern A. Zeeb 				status.n_rates = 1;
746c92544dSBjoern A. Zeeb 			} else {
756c92544dSBjoern A. Zeeb 				status.n_rates = 0;
766c92544dSBjoern A. Zeeb 			}
776c92544dSBjoern A. Zeeb 		}
786c92544dSBjoern A. Zeeb 
796c92544dSBjoern A. Zeeb 		hw = mt76_tx_status_get_hw(dev, skb);
80cbb3ec25SBjoern A. Zeeb 		spin_lock_bh(&dev->rx_lock);
816c92544dSBjoern A. Zeeb 		ieee80211_tx_status_ext(hw, &status);
82cbb3ec25SBjoern A. Zeeb 		spin_unlock_bh(&dev->rx_lock);
836c92544dSBjoern A. Zeeb 	}
846c92544dSBjoern A. Zeeb 	rcu_read_unlock();
856c92544dSBjoern A. Zeeb }
866c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_unlock);
876c92544dSBjoern A. Zeeb 
886c92544dSBjoern A. Zeeb static void
__mt76_tx_status_skb_done(struct mt76_dev * dev,struct sk_buff * skb,u8 flags,struct sk_buff_head * list)896c92544dSBjoern A. Zeeb __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
906c92544dSBjoern A. Zeeb 			  struct sk_buff_head *list)
916c92544dSBjoern A. Zeeb {
926c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
936c92544dSBjoern A. Zeeb 	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
946c92544dSBjoern A. Zeeb 	u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE;
956c92544dSBjoern A. Zeeb 
966c92544dSBjoern A. Zeeb 	flags |= cb->flags;
976c92544dSBjoern A. Zeeb 	cb->flags = flags;
986c92544dSBjoern A. Zeeb 
996c92544dSBjoern A. Zeeb 	if ((flags & done) != done)
1006c92544dSBjoern A. Zeeb 		return;
1016c92544dSBjoern A. Zeeb 
1026c92544dSBjoern A. Zeeb 	/* Tx status can be unreliable. if it fails, mark the frame as ACKed */
1036c92544dSBjoern A. Zeeb 	if (flags & MT_TX_CB_TXS_FAILED) {
1046c92544dSBjoern A. Zeeb 		info->status.rates[0].count = 0;
1056c92544dSBjoern A. Zeeb 		info->status.rates[0].idx = -1;
1066c92544dSBjoern A. Zeeb 		info->flags |= IEEE80211_TX_STAT_ACK;
1076c92544dSBjoern A. Zeeb 	}
1086c92544dSBjoern A. Zeeb 
1096c92544dSBjoern A. Zeeb 	__skb_queue_tail(list, skb);
1106c92544dSBjoern A. Zeeb }
1116c92544dSBjoern A. Zeeb 
1126c92544dSBjoern A. Zeeb void
mt76_tx_status_skb_done(struct mt76_dev * dev,struct sk_buff * skb,struct sk_buff_head * list)1136c92544dSBjoern A. Zeeb mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
1146c92544dSBjoern A. Zeeb 			struct sk_buff_head *list)
1156c92544dSBjoern A. Zeeb {
1166c92544dSBjoern A. Zeeb 	__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list);
1176c92544dSBjoern A. Zeeb }
1186c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_skb_done);
1196c92544dSBjoern A. Zeeb 
1206c92544dSBjoern A. Zeeb int
mt76_tx_status_skb_add(struct mt76_dev * dev,struct mt76_wcid * wcid,struct sk_buff * skb)1216c92544dSBjoern A. Zeeb mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
1226c92544dSBjoern A. Zeeb 		       struct sk_buff *skb)
1236c92544dSBjoern A. Zeeb {
124cbb3ec25SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1256c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1266c92544dSBjoern A. Zeeb 	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
1276c92544dSBjoern A. Zeeb 	int pid;
1286c92544dSBjoern A. Zeeb 
1296c92544dSBjoern A. Zeeb 	memset(cb, 0, sizeof(*cb));
1306c92544dSBjoern A. Zeeb 
1316c92544dSBjoern A. Zeeb 	if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx]))
1326c92544dSBjoern A. Zeeb 		return MT_PACKET_ID_NO_ACK;
1336c92544dSBjoern A. Zeeb 
1346c92544dSBjoern A. Zeeb 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
1356c92544dSBjoern A. Zeeb 		return MT_PACKET_ID_NO_ACK;
1366c92544dSBjoern A. Zeeb 
1376c92544dSBjoern A. Zeeb 	if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
138cbb3ec25SBjoern A. Zeeb 			     IEEE80211_TX_CTL_RATE_CTRL_PROBE))) {
139cbb3ec25SBjoern A. Zeeb 		if (mtk_wed_device_active(&dev->mmio.wed) &&
140cbb3ec25SBjoern A. Zeeb 		    ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ||
141cbb3ec25SBjoern A. Zeeb 		     ieee80211_is_data(hdr->frame_control)))
142cbb3ec25SBjoern A. Zeeb 			return MT_PACKET_ID_WED;
143cbb3ec25SBjoern A. Zeeb 
1446c92544dSBjoern A. Zeeb 		return MT_PACKET_ID_NO_SKB;
145cbb3ec25SBjoern A. Zeeb 	}
1466c92544dSBjoern A. Zeeb 
1476c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->status_lock);
1486c92544dSBjoern A. Zeeb 
1496c92544dSBjoern A. Zeeb 	pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST,
1506c92544dSBjoern A. Zeeb 			MT_PACKET_ID_MASK, GFP_ATOMIC);
1516c92544dSBjoern A. Zeeb 	if (pid < 0) {
1526c92544dSBjoern A. Zeeb 		pid = MT_PACKET_ID_NO_SKB;
1536c92544dSBjoern A. Zeeb 		goto out;
1546c92544dSBjoern A. Zeeb 	}
1556c92544dSBjoern A. Zeeb 
1566c92544dSBjoern A. Zeeb 	cb->wcid = wcid->idx;
1576c92544dSBjoern A. Zeeb 	cb->pktid = pid;
1586c92544dSBjoern A. Zeeb 
1596c92544dSBjoern A. Zeeb 	if (list_empty(&wcid->list))
1606c92544dSBjoern A. Zeeb 		list_add_tail(&wcid->list, &dev->wcid_list);
1616c92544dSBjoern A. Zeeb 
1626c92544dSBjoern A. Zeeb out:
1636c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->status_lock);
1646c92544dSBjoern A. Zeeb 
1656c92544dSBjoern A. Zeeb 	return pid;
1666c92544dSBjoern A. Zeeb }
1676c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_skb_add);
1686c92544dSBjoern A. Zeeb 
1696c92544dSBjoern A. Zeeb struct sk_buff *
mt76_tx_status_skb_get(struct mt76_dev * dev,struct mt76_wcid * wcid,int pktid,struct sk_buff_head * list)1706c92544dSBjoern A. Zeeb mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid,
1716c92544dSBjoern A. Zeeb 		       struct sk_buff_head *list)
1726c92544dSBjoern A. Zeeb {
1736c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
1746c92544dSBjoern A. Zeeb 	int id;
1756c92544dSBjoern A. Zeeb 
1766c92544dSBjoern A. Zeeb 	lockdep_assert_held(&dev->status_lock);
1776c92544dSBjoern A. Zeeb 
1786c92544dSBjoern A. Zeeb 	skb = idr_remove(&wcid->pktid, pktid);
1796c92544dSBjoern A. Zeeb 	if (skb)
1806c92544dSBjoern A. Zeeb 		goto out;
1816c92544dSBjoern A. Zeeb 
1826c92544dSBjoern A. Zeeb 	/* look for stale entries in the wcid idr queue */
1836c92544dSBjoern A. Zeeb 	idr_for_each_entry(&wcid->pktid, skb, id) {
1846c92544dSBjoern A. Zeeb 		struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
1856c92544dSBjoern A. Zeeb 
1866c92544dSBjoern A. Zeeb 		if (pktid >= 0) {
1876c92544dSBjoern A. Zeeb 			if (!(cb->flags & MT_TX_CB_DMA_DONE))
1886c92544dSBjoern A. Zeeb 				continue;
1896c92544dSBjoern A. Zeeb 
1906c92544dSBjoern A. Zeeb 			if (time_is_after_jiffies(cb->jiffies +
1916c92544dSBjoern A. Zeeb 						   MT_TX_STATUS_SKB_TIMEOUT))
1926c92544dSBjoern A. Zeeb 				continue;
1936c92544dSBjoern A. Zeeb 		}
1946c92544dSBjoern A. Zeeb 
1956c92544dSBjoern A. Zeeb 		/* It has been too long since DMA_DONE, time out this packet
1966c92544dSBjoern A. Zeeb 		 * and stop waiting for TXS callback.
1976c92544dSBjoern A. Zeeb 		 */
1986c92544dSBjoern A. Zeeb 		idr_remove(&wcid->pktid, cb->pktid);
1996c92544dSBjoern A. Zeeb 		__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED |
2006c92544dSBjoern A. Zeeb 						    MT_TX_CB_TXS_DONE, list);
2016c92544dSBjoern A. Zeeb 	}
2026c92544dSBjoern A. Zeeb 
2036c92544dSBjoern A. Zeeb out:
2046c92544dSBjoern A. Zeeb 	if (idr_is_empty(&wcid->pktid))
2056c92544dSBjoern A. Zeeb 		list_del_init(&wcid->list);
2066c92544dSBjoern A. Zeeb 
2076c92544dSBjoern A. Zeeb 	return skb;
2086c92544dSBjoern A. Zeeb }
2096c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_skb_get);
2106c92544dSBjoern A. Zeeb 
2116c92544dSBjoern A. Zeeb void
mt76_tx_status_check(struct mt76_dev * dev,bool flush)2126c92544dSBjoern A. Zeeb mt76_tx_status_check(struct mt76_dev *dev, bool flush)
2136c92544dSBjoern A. Zeeb {
2146c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid, *tmp;
2156c92544dSBjoern A. Zeeb 	struct sk_buff_head list;
2166c92544dSBjoern A. Zeeb 
2176c92544dSBjoern A. Zeeb 	mt76_tx_status_lock(dev, &list);
2186c92544dSBjoern A. Zeeb 	list_for_each_entry_safe(wcid, tmp, &dev->wcid_list, list)
2196c92544dSBjoern A. Zeeb 		mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list);
2206c92544dSBjoern A. Zeeb 	mt76_tx_status_unlock(dev, &list);
2216c92544dSBjoern A. Zeeb }
2226c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_status_check);
2236c92544dSBjoern A. Zeeb 
2246c92544dSBjoern A. Zeeb static void
mt76_tx_check_non_aql(struct mt76_dev * dev,struct mt76_wcid * wcid,struct sk_buff * skb)2256c92544dSBjoern A. Zeeb mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
2266c92544dSBjoern A. Zeeb 		      struct sk_buff *skb)
2276c92544dSBjoern A. Zeeb {
2286c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2296c92544dSBjoern A. Zeeb 	int pending;
2306c92544dSBjoern A. Zeeb 
2316c92544dSBjoern A. Zeeb 	if (!wcid || info->tx_time_est)
2326c92544dSBjoern A. Zeeb 		return;
2336c92544dSBjoern A. Zeeb 
2346c92544dSBjoern A. Zeeb 	pending = atomic_dec_return(&wcid->non_aql_packets);
2356c92544dSBjoern A. Zeeb 	if (pending < 0)
2366c92544dSBjoern A. Zeeb 		atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
2376c92544dSBjoern A. Zeeb }
2386c92544dSBjoern A. Zeeb 
__mt76_tx_complete_skb(struct mt76_dev * dev,u16 wcid_idx,struct sk_buff * skb,struct list_head * free_list)2396c92544dSBjoern A. Zeeb void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb,
2406c92544dSBjoern A. Zeeb 			    struct list_head *free_list)
2416c92544dSBjoern A. Zeeb {
2426c92544dSBjoern A. Zeeb 	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
2436c92544dSBjoern A. Zeeb 	struct ieee80211_tx_status status = {
2446c92544dSBjoern A. Zeeb 		.skb = skb,
2456c92544dSBjoern A. Zeeb 		.free_list = free_list,
2466c92544dSBjoern A. Zeeb 	};
2476c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = NULL;
2486c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
2496c92544dSBjoern A. Zeeb 	struct sk_buff_head list;
2506c92544dSBjoern A. Zeeb 
2516c92544dSBjoern A. Zeeb 	rcu_read_lock();
2526c92544dSBjoern A. Zeeb 
2536c92544dSBjoern A. Zeeb 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
2546c92544dSBjoern A. Zeeb 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
2556c92544dSBjoern A. Zeeb 
2566c92544dSBjoern A. Zeeb 	mt76_tx_check_non_aql(dev, wcid, skb);
2576c92544dSBjoern A. Zeeb 
2586c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
2596c92544dSBjoern A. Zeeb 	if (mt76_is_testmode_skb(dev, skb, &hw)) {
2606c92544dSBjoern A. Zeeb 		struct mt76_phy *phy = hw->priv;
2616c92544dSBjoern A. Zeeb 
2626c92544dSBjoern A. Zeeb 		if (skb == phy->test.tx_skb)
2636c92544dSBjoern A. Zeeb 			phy->test.tx_done++;
2646c92544dSBjoern A. Zeeb 		if (phy->test.tx_queued == phy->test.tx_done)
2656c92544dSBjoern A. Zeeb 			wake_up(&dev->tx_wait);
2666c92544dSBjoern A. Zeeb 
2676c92544dSBjoern A. Zeeb 		dev_kfree_skb_any(skb);
2686c92544dSBjoern A. Zeeb 		goto out;
2696c92544dSBjoern A. Zeeb 	}
2706c92544dSBjoern A. Zeeb #endif
2716c92544dSBjoern A. Zeeb 
2726c92544dSBjoern A. Zeeb 	if (cb->pktid < MT_PACKET_ID_FIRST) {
273cbb3ec25SBjoern A. Zeeb 		struct ieee80211_rate_status rs = {};
274cbb3ec25SBjoern A. Zeeb 
2756c92544dSBjoern A. Zeeb 		hw = mt76_tx_status_get_hw(dev, skb);
2766c92544dSBjoern A. Zeeb 		status.sta = wcid_to_sta(wcid);
277cbb3ec25SBjoern A. Zeeb 		if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
278cbb3ec25SBjoern A. Zeeb 			rs.rate_idx = wcid->rate;
279cbb3ec25SBjoern A. Zeeb 			status.rates = &rs;
280cbb3ec25SBjoern A. Zeeb 			status.n_rates = 1;
281cbb3ec25SBjoern A. Zeeb 		}
282cbb3ec25SBjoern A. Zeeb 		spin_lock_bh(&dev->rx_lock);
2836c92544dSBjoern A. Zeeb 		ieee80211_tx_status_ext(hw, &status);
284cbb3ec25SBjoern A. Zeeb 		spin_unlock_bh(&dev->rx_lock);
2856c92544dSBjoern A. Zeeb 		goto out;
2866c92544dSBjoern A. Zeeb 	}
2876c92544dSBjoern A. Zeeb 
2886c92544dSBjoern A. Zeeb 	mt76_tx_status_lock(dev, &list);
2896c92544dSBjoern A. Zeeb 	cb->jiffies = jiffies;
2906c92544dSBjoern A. Zeeb 	__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list);
2916c92544dSBjoern A. Zeeb 	mt76_tx_status_unlock(dev, &list);
2926c92544dSBjoern A. Zeeb 
2936c92544dSBjoern A. Zeeb out:
2946c92544dSBjoern A. Zeeb 	rcu_read_unlock();
2956c92544dSBjoern A. Zeeb }
2966c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb);
2976c92544dSBjoern A. Zeeb 
2986c92544dSBjoern A. Zeeb static int
__mt76_tx_queue_skb(struct mt76_phy * phy,int qid,struct sk_buff * skb,struct mt76_wcid * wcid,struct ieee80211_sta * sta,bool * stop)2996c92544dSBjoern A. Zeeb __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
3006c92544dSBjoern A. Zeeb 		    struct mt76_wcid *wcid, struct ieee80211_sta *sta,
3016c92544dSBjoern A. Zeeb 		    bool *stop)
3026c92544dSBjoern A. Zeeb {
3036c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3046c92544dSBjoern A. Zeeb 	struct mt76_queue *q = phy->q_tx[qid];
3056c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
3066c92544dSBjoern A. Zeeb 	bool non_aql;
3076c92544dSBjoern A. Zeeb 	int pending;
3086c92544dSBjoern A. Zeeb 	int idx;
3096c92544dSBjoern A. Zeeb 
3106c92544dSBjoern A. Zeeb 	non_aql = !info->tx_time_est;
3116c92544dSBjoern A. Zeeb 	idx = dev->queue_ops->tx_queue_skb(dev, q, qid, skb, wcid, sta);
3126c92544dSBjoern A. Zeeb 	if (idx < 0 || !sta)
3136c92544dSBjoern A. Zeeb 		return idx;
3146c92544dSBjoern A. Zeeb 
3156c92544dSBjoern A. Zeeb 	wcid = (struct mt76_wcid *)sta->drv_priv;
3166c92544dSBjoern A. Zeeb 	q->entry[idx].wcid = wcid->idx;
3176c92544dSBjoern A. Zeeb 
3186c92544dSBjoern A. Zeeb 	if (!non_aql)
3196c92544dSBjoern A. Zeeb 		return idx;
3206c92544dSBjoern A. Zeeb 
3216c92544dSBjoern A. Zeeb 	pending = atomic_inc_return(&wcid->non_aql_packets);
3226c92544dSBjoern A. Zeeb 	if (stop && pending >= MT_MAX_NON_AQL_PKT)
3236c92544dSBjoern A. Zeeb 		*stop = true;
3246c92544dSBjoern A. Zeeb 
3256c92544dSBjoern A. Zeeb 	return idx;
3266c92544dSBjoern A. Zeeb }
3276c92544dSBjoern A. Zeeb 
3286c92544dSBjoern A. Zeeb void
mt76_tx(struct mt76_phy * phy,struct ieee80211_sta * sta,struct mt76_wcid * wcid,struct sk_buff * skb)3296c92544dSBjoern A. Zeeb mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
3306c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid, struct sk_buff *skb)
3316c92544dSBjoern A. Zeeb {
3326c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
3336c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3346c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
3356c92544dSBjoern A. Zeeb 	struct mt76_queue *q;
3366c92544dSBjoern A. Zeeb 	int qid = skb_get_queue_mapping(skb);
3376c92544dSBjoern A. Zeeb 
3386c92544dSBjoern A. Zeeb 	if (mt76_testmode_enabled(phy)) {
3396c92544dSBjoern A. Zeeb 		ieee80211_free_txskb(phy->hw, skb);
3406c92544dSBjoern A. Zeeb 		return;
3416c92544dSBjoern A. Zeeb 	}
3426c92544dSBjoern A. Zeeb 
3436c92544dSBjoern A. Zeeb 	if (WARN_ON(qid >= MT_TXQ_PSD)) {
3446c92544dSBjoern A. Zeeb 		qid = MT_TXQ_BE;
3456c92544dSBjoern A. Zeeb 		skb_set_queue_mapping(skb, qid);
3466c92544dSBjoern A. Zeeb 	}
3476c92544dSBjoern A. Zeeb 
3486c92544dSBjoern A. Zeeb 	if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
3496c92544dSBjoern A. Zeeb 	    !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
3506c92544dSBjoern A. Zeeb 	    !ieee80211_is_data(hdr->frame_control) &&
351cbb3ec25SBjoern A. Zeeb 	    !ieee80211_is_bufferable_mmpdu(skb)) {
3526c92544dSBjoern A. Zeeb 		qid = MT_TXQ_PSD;
3536c92544dSBjoern A. Zeeb 	}
3546c92544dSBjoern A. Zeeb 
3556c92544dSBjoern A. Zeeb 	if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET))
3566c92544dSBjoern A. Zeeb 		ieee80211_get_tx_rates(info->control.vif, sta, skb,
3576c92544dSBjoern A. Zeeb 				       info->control.rates, 1);
3586c92544dSBjoern A. Zeeb 
3596c92544dSBjoern A. Zeeb 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);
3606c92544dSBjoern A. Zeeb 	q = phy->q_tx[qid];
3616c92544dSBjoern A. Zeeb 
3626c92544dSBjoern A. Zeeb 	spin_lock_bh(&q->lock);
3636c92544dSBjoern A. Zeeb 	__mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL);
3646c92544dSBjoern A. Zeeb 	dev->queue_ops->kick(dev, q);
3656c92544dSBjoern A. Zeeb 	spin_unlock_bh(&q->lock);
3666c92544dSBjoern A. Zeeb }
3676c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx);
3686c92544dSBjoern A. Zeeb 
3696c92544dSBjoern A. Zeeb static struct sk_buff *
mt76_txq_dequeue(struct mt76_phy * phy,struct mt76_txq * mtxq)3706c92544dSBjoern A. Zeeb mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
3716c92544dSBjoern A. Zeeb {
3726c92544dSBjoern A. Zeeb 	struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
3736c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
3746c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
3756c92544dSBjoern A. Zeeb 
3766c92544dSBjoern A. Zeeb 	skb = ieee80211_tx_dequeue(phy->hw, txq);
3776c92544dSBjoern A. Zeeb 	if (!skb)
3786c92544dSBjoern A. Zeeb 		return NULL;
3796c92544dSBjoern A. Zeeb 
3806c92544dSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
3816c92544dSBjoern A. Zeeb 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);
3826c92544dSBjoern A. Zeeb 
3836c92544dSBjoern A. Zeeb 	return skb;
3846c92544dSBjoern A. Zeeb }
3856c92544dSBjoern A. Zeeb 
3866c92544dSBjoern A. Zeeb static void
mt76_queue_ps_skb(struct mt76_phy * phy,struct ieee80211_sta * sta,struct sk_buff * skb,bool last)3876c92544dSBjoern A. Zeeb mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta,
3886c92544dSBjoern A. Zeeb 		  struct sk_buff *skb, bool last)
3896c92544dSBjoern A. Zeeb {
3906c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
3916c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3926c92544dSBjoern A. Zeeb 
3936c92544dSBjoern A. Zeeb 	info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
3946c92544dSBjoern A. Zeeb 	if (last)
3956c92544dSBjoern A. Zeeb 		info->flags |= IEEE80211_TX_STATUS_EOSP |
3966c92544dSBjoern A. Zeeb 			       IEEE80211_TX_CTL_REQ_TX_STATUS;
3976c92544dSBjoern A. Zeeb 
3986c92544dSBjoern A. Zeeb 	mt76_skb_set_moredata(skb, !last);
3996c92544dSBjoern A. Zeeb 	__mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL);
4006c92544dSBjoern A. Zeeb }
4016c92544dSBjoern A. Zeeb 
4026c92544dSBjoern A. Zeeb void
mt76_release_buffered_frames(struct ieee80211_hw * hw,struct ieee80211_sta * sta,u16 tids,int nframes,enum ieee80211_frame_release_type reason,bool more_data)4036c92544dSBjoern A. Zeeb mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
4046c92544dSBjoern A. Zeeb 			     u16 tids, int nframes,
4056c92544dSBjoern A. Zeeb 			     enum ieee80211_frame_release_type reason,
4066c92544dSBjoern A. Zeeb 			     bool more_data)
4076c92544dSBjoern A. Zeeb {
4086c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
4096c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
4106c92544dSBjoern A. Zeeb 	struct sk_buff *last_skb = NULL;
4116c92544dSBjoern A. Zeeb 	struct mt76_queue *hwq = phy->q_tx[MT_TXQ_PSD];
4126c92544dSBjoern A. Zeeb 	int i;
4136c92544dSBjoern A. Zeeb 
4146c92544dSBjoern A. Zeeb 	spin_lock_bh(&hwq->lock);
4156c92544dSBjoern A. Zeeb 	for (i = 0; tids && nframes; i++, tids >>= 1) {
4166c92544dSBjoern A. Zeeb 		struct ieee80211_txq *txq = sta->txq[i];
4176c92544dSBjoern A. Zeeb 		struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
4186c92544dSBjoern A. Zeeb 		struct sk_buff *skb;
4196c92544dSBjoern A. Zeeb 
4206c92544dSBjoern A. Zeeb 		if (!(tids & 1))
4216c92544dSBjoern A. Zeeb 			continue;
4226c92544dSBjoern A. Zeeb 
4236c92544dSBjoern A. Zeeb 		do {
4246c92544dSBjoern A. Zeeb 			skb = mt76_txq_dequeue(phy, mtxq);
4256c92544dSBjoern A. Zeeb 			if (!skb)
4266c92544dSBjoern A. Zeeb 				break;
4276c92544dSBjoern A. Zeeb 
4286c92544dSBjoern A. Zeeb 			nframes--;
4296c92544dSBjoern A. Zeeb 			if (last_skb)
4306c92544dSBjoern A. Zeeb 				mt76_queue_ps_skb(phy, sta, last_skb, false);
4316c92544dSBjoern A. Zeeb 
4326c92544dSBjoern A. Zeeb 			last_skb = skb;
4336c92544dSBjoern A. Zeeb 		} while (nframes);
4346c92544dSBjoern A. Zeeb 	}
4356c92544dSBjoern A. Zeeb 
4366c92544dSBjoern A. Zeeb 	if (last_skb) {
4376c92544dSBjoern A. Zeeb 		mt76_queue_ps_skb(phy, sta, last_skb, true);
4386c92544dSBjoern A. Zeeb 		dev->queue_ops->kick(dev, hwq);
4396c92544dSBjoern A. Zeeb 	} else {
4406c92544dSBjoern A. Zeeb 		ieee80211_sta_eosp(sta);
4416c92544dSBjoern A. Zeeb 	}
4426c92544dSBjoern A. Zeeb 
4436c92544dSBjoern A. Zeeb 	spin_unlock_bh(&hwq->lock);
4446c92544dSBjoern A. Zeeb }
4456c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
4466c92544dSBjoern A. Zeeb 
4476c92544dSBjoern A. Zeeb static bool
mt76_txq_stopped(struct mt76_queue * q)4486c92544dSBjoern A. Zeeb mt76_txq_stopped(struct mt76_queue *q)
4496c92544dSBjoern A. Zeeb {
4506c92544dSBjoern A. Zeeb 	return q->stopped || q->blocked ||
4516c92544dSBjoern A. Zeeb 	       q->queued + MT_TXQ_FREE_THR >= q->ndesc;
4526c92544dSBjoern A. Zeeb }
4536c92544dSBjoern A. Zeeb 
4546c92544dSBjoern A. Zeeb static int
mt76_txq_send_burst(struct mt76_phy * phy,struct mt76_queue * q,struct mt76_txq * mtxq,struct mt76_wcid * wcid)4556c92544dSBjoern A. Zeeb mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
4566c92544dSBjoern A. Zeeb 		    struct mt76_txq *mtxq, struct mt76_wcid *wcid)
4576c92544dSBjoern A. Zeeb {
4586c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
4596c92544dSBjoern A. Zeeb 	struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
4606c92544dSBjoern A. Zeeb 	enum mt76_txq_id qid = mt76_txq_get_qid(txq);
4616c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
4626c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
4636c92544dSBjoern A. Zeeb 	int n_frames = 1;
4646c92544dSBjoern A. Zeeb 	bool stop = false;
4656c92544dSBjoern A. Zeeb 	int idx;
4666c92544dSBjoern A. Zeeb 
4676c92544dSBjoern A. Zeeb 	if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
4686c92544dSBjoern A. Zeeb 		return 0;
4696c92544dSBjoern A. Zeeb 
4706c92544dSBjoern A. Zeeb 	if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
4716c92544dSBjoern A. Zeeb 		return 0;
4726c92544dSBjoern A. Zeeb 
4736c92544dSBjoern A. Zeeb 	skb = mt76_txq_dequeue(phy, mtxq);
4746c92544dSBjoern A. Zeeb 	if (!skb)
4756c92544dSBjoern A. Zeeb 		return 0;
4766c92544dSBjoern A. Zeeb 
4776c92544dSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
4786c92544dSBjoern A. Zeeb 	if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
4796c92544dSBjoern A. Zeeb 		ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
4806c92544dSBjoern A. Zeeb 				       info->control.rates, 1);
4816c92544dSBjoern A. Zeeb 
4826c92544dSBjoern A. Zeeb 	spin_lock(&q->lock);
4836c92544dSBjoern A. Zeeb 	idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
4846c92544dSBjoern A. Zeeb 	spin_unlock(&q->lock);
4856c92544dSBjoern A. Zeeb 	if (idx < 0)
4866c92544dSBjoern A. Zeeb 		return idx;
4876c92544dSBjoern A. Zeeb 
4886c92544dSBjoern A. Zeeb 	do {
4896c92544dSBjoern A. Zeeb 		if (test_bit(MT76_RESET, &phy->state))
4906c92544dSBjoern A. Zeeb 			return -EBUSY;
4916c92544dSBjoern A. Zeeb 
4926c92544dSBjoern A. Zeeb 		if (stop || mt76_txq_stopped(q))
4936c92544dSBjoern A. Zeeb 			break;
4946c92544dSBjoern A. Zeeb 
4956c92544dSBjoern A. Zeeb 		skb = mt76_txq_dequeue(phy, mtxq);
4966c92544dSBjoern A. Zeeb 		if (!skb)
4976c92544dSBjoern A. Zeeb 			break;
4986c92544dSBjoern A. Zeeb 
4996c92544dSBjoern A. Zeeb 		info = IEEE80211_SKB_CB(skb);
5006c92544dSBjoern A. Zeeb 		if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
5016c92544dSBjoern A. Zeeb 			ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
5026c92544dSBjoern A. Zeeb 					       info->control.rates, 1);
5036c92544dSBjoern A. Zeeb 
5046c92544dSBjoern A. Zeeb 		spin_lock(&q->lock);
5056c92544dSBjoern A. Zeeb 		idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
5066c92544dSBjoern A. Zeeb 		spin_unlock(&q->lock);
5076c92544dSBjoern A. Zeeb 		if (idx < 0)
5086c92544dSBjoern A. Zeeb 			break;
5096c92544dSBjoern A. Zeeb 
5106c92544dSBjoern A. Zeeb 		n_frames++;
5116c92544dSBjoern A. Zeeb 	} while (1);
5126c92544dSBjoern A. Zeeb 
5136c92544dSBjoern A. Zeeb 	spin_lock(&q->lock);
5146c92544dSBjoern A. Zeeb 	dev->queue_ops->kick(dev, q);
5156c92544dSBjoern A. Zeeb 	spin_unlock(&q->lock);
5166c92544dSBjoern A. Zeeb 
5176c92544dSBjoern A. Zeeb 	return n_frames;
5186c92544dSBjoern A. Zeeb }
5196c92544dSBjoern A. Zeeb 
5206c92544dSBjoern A. Zeeb static int
mt76_txq_schedule_list(struct mt76_phy * phy,enum mt76_txq_id qid)5216c92544dSBjoern A. Zeeb mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
5226c92544dSBjoern A. Zeeb {
5236c92544dSBjoern A. Zeeb 	struct mt76_queue *q = phy->q_tx[qid];
5246c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
5256c92544dSBjoern A. Zeeb 	struct ieee80211_txq *txq;
5266c92544dSBjoern A. Zeeb 	struct mt76_txq *mtxq;
5276c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid;
5286c92544dSBjoern A. Zeeb 	int ret = 0;
5296c92544dSBjoern A. Zeeb 
5306c92544dSBjoern A. Zeeb 	while (1) {
5316c92544dSBjoern A. Zeeb 		int n_frames = 0;
5326c92544dSBjoern A. Zeeb 
5336c92544dSBjoern A. Zeeb 		if (test_bit(MT76_RESET, &phy->state))
5346c92544dSBjoern A. Zeeb 			return -EBUSY;
5356c92544dSBjoern A. Zeeb 
5366c92544dSBjoern A. Zeeb 		if (dev->queue_ops->tx_cleanup &&
5376c92544dSBjoern A. Zeeb 		    q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) {
5386c92544dSBjoern A. Zeeb 			dev->queue_ops->tx_cleanup(dev, q, false);
5396c92544dSBjoern A. Zeeb 		}
5406c92544dSBjoern A. Zeeb 
5416c92544dSBjoern A. Zeeb 		txq = ieee80211_next_txq(phy->hw, qid);
5426c92544dSBjoern A. Zeeb 		if (!txq)
5436c92544dSBjoern A. Zeeb 			break;
5446c92544dSBjoern A. Zeeb 
5456c92544dSBjoern A. Zeeb 		mtxq = (struct mt76_txq *)txq->drv_priv;
5466c92544dSBjoern A. Zeeb 		wcid = rcu_dereference(dev->wcid[mtxq->wcid]);
5476c92544dSBjoern A. Zeeb 		if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags))
5486c92544dSBjoern A. Zeeb 			continue;
5496c92544dSBjoern A. Zeeb 
5506c92544dSBjoern A. Zeeb 		if (mtxq->send_bar && mtxq->aggr) {
5516c92544dSBjoern A. Zeeb 			struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
5526c92544dSBjoern A. Zeeb 			struct ieee80211_sta *sta = txq->sta;
5536c92544dSBjoern A. Zeeb 			struct ieee80211_vif *vif = txq->vif;
5546c92544dSBjoern A. Zeeb 			u16 agg_ssn = mtxq->agg_ssn;
5556c92544dSBjoern A. Zeeb 			u8 tid = txq->tid;
5566c92544dSBjoern A. Zeeb 
5576c92544dSBjoern A. Zeeb 			mtxq->send_bar = false;
5586c92544dSBjoern A. Zeeb 			ieee80211_send_bar(vif, sta->addr, tid, agg_ssn);
5596c92544dSBjoern A. Zeeb 		}
5606c92544dSBjoern A. Zeeb 
5616c92544dSBjoern A. Zeeb 		if (!mt76_txq_stopped(q))
5626c92544dSBjoern A. Zeeb 			n_frames = mt76_txq_send_burst(phy, q, mtxq, wcid);
5636c92544dSBjoern A. Zeeb 
5646c92544dSBjoern A. Zeeb 		ieee80211_return_txq(phy->hw, txq, false);
5656c92544dSBjoern A. Zeeb 
5666c92544dSBjoern A. Zeeb 		if (unlikely(n_frames < 0))
5676c92544dSBjoern A. Zeeb 			return n_frames;
5686c92544dSBjoern A. Zeeb 
5696c92544dSBjoern A. Zeeb 		ret += n_frames;
5706c92544dSBjoern A. Zeeb 	}
5716c92544dSBjoern A. Zeeb 
5726c92544dSBjoern A. Zeeb 	return ret;
5736c92544dSBjoern A. Zeeb }
5746c92544dSBjoern A. Zeeb 
mt76_txq_schedule(struct mt76_phy * phy,enum mt76_txq_id qid)5756c92544dSBjoern A. Zeeb void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
5766c92544dSBjoern A. Zeeb {
5776c92544dSBjoern A. Zeeb 	int len;
5786c92544dSBjoern A. Zeeb 
5796c92544dSBjoern A. Zeeb 	if (qid >= 4)
5806c92544dSBjoern A. Zeeb 		return;
5816c92544dSBjoern A. Zeeb 
5826c92544dSBjoern A. Zeeb 	local_bh_disable();
5836c92544dSBjoern A. Zeeb 	rcu_read_lock();
5846c92544dSBjoern A. Zeeb 
5856c92544dSBjoern A. Zeeb 	do {
5866c92544dSBjoern A. Zeeb 		ieee80211_txq_schedule_start(phy->hw, qid);
5876c92544dSBjoern A. Zeeb 		len = mt76_txq_schedule_list(phy, qid);
5886c92544dSBjoern A. Zeeb 		ieee80211_txq_schedule_end(phy->hw, qid);
5896c92544dSBjoern A. Zeeb 	} while (len > 0);
5906c92544dSBjoern A. Zeeb 
5916c92544dSBjoern A. Zeeb 	rcu_read_unlock();
5926c92544dSBjoern A. Zeeb 	local_bh_enable();
5936c92544dSBjoern A. Zeeb }
5946c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_txq_schedule);
5956c92544dSBjoern A. Zeeb 
mt76_txq_schedule_all(struct mt76_phy * phy)5966c92544dSBjoern A. Zeeb void mt76_txq_schedule_all(struct mt76_phy *phy)
5976c92544dSBjoern A. Zeeb {
5986c92544dSBjoern A. Zeeb 	int i;
5996c92544dSBjoern A. Zeeb 
6006c92544dSBjoern A. Zeeb 	for (i = 0; i <= MT_TXQ_BK; i++)
6016c92544dSBjoern A. Zeeb 		mt76_txq_schedule(phy, i);
6026c92544dSBjoern A. Zeeb }
6036c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
6046c92544dSBjoern A. Zeeb 
mt76_tx_worker_run(struct mt76_dev * dev)6056c92544dSBjoern A. Zeeb void mt76_tx_worker_run(struct mt76_dev *dev)
6066c92544dSBjoern A. Zeeb {
6076c92544dSBjoern A. Zeeb 	struct mt76_phy *phy;
6086c92544dSBjoern A. Zeeb 	int i;
6096c92544dSBjoern A. Zeeb 
6106c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
6116c92544dSBjoern A. Zeeb 		phy = dev->phys[i];
6126c92544dSBjoern A. Zeeb 		if (!phy)
6136c92544dSBjoern A. Zeeb 			continue;
6146c92544dSBjoern A. Zeeb 
6156c92544dSBjoern A. Zeeb 		mt76_txq_schedule_all(phy);
6166c92544dSBjoern A. Zeeb 	}
6176c92544dSBjoern A. Zeeb 
6186c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
6196c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
6206c92544dSBjoern A. Zeeb 		phy = dev->phys[i];
6216c92544dSBjoern A. Zeeb 		if (!phy || !phy->test.tx_pending)
6226c92544dSBjoern A. Zeeb 			continue;
6236c92544dSBjoern A. Zeeb 
6246c92544dSBjoern A. Zeeb 		mt76_testmode_tx_pending(phy);
6256c92544dSBjoern A. Zeeb 	}
6266c92544dSBjoern A. Zeeb #endif
6276c92544dSBjoern A. Zeeb }
6286c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_tx_worker_run);
6296c92544dSBjoern A. Zeeb 
mt76_tx_worker(struct mt76_worker * w)6306c92544dSBjoern A. Zeeb void mt76_tx_worker(struct mt76_worker *w)
6316c92544dSBjoern A. Zeeb {
6326c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
6336c92544dSBjoern A. Zeeb 
6346c92544dSBjoern A. Zeeb 	mt76_tx_worker_run(dev);
6356c92544dSBjoern A. Zeeb }
6366c92544dSBjoern A. Zeeb 
mt76_stop_tx_queues(struct mt76_phy * phy,struct ieee80211_sta * sta,bool send_bar)6376c92544dSBjoern A. Zeeb void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
6386c92544dSBjoern A. Zeeb 			 bool send_bar)
6396c92544dSBjoern A. Zeeb {
6406c92544dSBjoern A. Zeeb 	int i;
6416c92544dSBjoern A. Zeeb 
6426c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
6436c92544dSBjoern A. Zeeb 		struct ieee80211_txq *txq = sta->txq[i];
6446c92544dSBjoern A. Zeeb 		struct mt76_queue *hwq;
6456c92544dSBjoern A. Zeeb 		struct mt76_txq *mtxq;
6466c92544dSBjoern A. Zeeb 
6476c92544dSBjoern A. Zeeb 		if (!txq)
6486c92544dSBjoern A. Zeeb 			continue;
6496c92544dSBjoern A. Zeeb 
6506c92544dSBjoern A. Zeeb 		hwq = phy->q_tx[mt76_txq_get_qid(txq)];
6516c92544dSBjoern A. Zeeb 		mtxq = (struct mt76_txq *)txq->drv_priv;
6526c92544dSBjoern A. Zeeb 
6536c92544dSBjoern A. Zeeb 		spin_lock_bh(&hwq->lock);
6546c92544dSBjoern A. Zeeb 		mtxq->send_bar = mtxq->aggr && send_bar;
6556c92544dSBjoern A. Zeeb 		spin_unlock_bh(&hwq->lock);
6566c92544dSBjoern A. Zeeb 	}
6576c92544dSBjoern A. Zeeb }
6586c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_stop_tx_queues);
6596c92544dSBjoern A. Zeeb 
mt76_wake_tx_queue(struct ieee80211_hw * hw,struct ieee80211_txq * txq)6606c92544dSBjoern A. Zeeb void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
6616c92544dSBjoern A. Zeeb {
6626c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
6636c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
6646c92544dSBjoern A. Zeeb 
6656c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_RUNNING, &phy->state))
6666c92544dSBjoern A. Zeeb 		return;
6676c92544dSBjoern A. Zeeb 
6686c92544dSBjoern A. Zeeb 	mt76_worker_schedule(&dev->tx_worker);
6696c92544dSBjoern A. Zeeb }
6706c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
6716c92544dSBjoern A. Zeeb 
mt76_ac_to_hwq(u8 ac)6726c92544dSBjoern A. Zeeb u8 mt76_ac_to_hwq(u8 ac)
6736c92544dSBjoern A. Zeeb {
6746c92544dSBjoern A. Zeeb 	static const u8 wmm_queue_map[] = {
6756c92544dSBjoern A. Zeeb 		[IEEE80211_AC_BE] = 0,
6766c92544dSBjoern A. Zeeb 		[IEEE80211_AC_BK] = 1,
6776c92544dSBjoern A. Zeeb 		[IEEE80211_AC_VI] = 2,
6786c92544dSBjoern A. Zeeb 		[IEEE80211_AC_VO] = 3,
6796c92544dSBjoern A. Zeeb 	};
6806c92544dSBjoern A. Zeeb 
6816c92544dSBjoern A. Zeeb 	if (WARN_ON(ac >= IEEE80211_NUM_ACS))
6826c92544dSBjoern A. Zeeb 		return 0;
6836c92544dSBjoern A. Zeeb 
6846c92544dSBjoern A. Zeeb 	return wmm_queue_map[ac];
6856c92544dSBjoern A. Zeeb }
6866c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
6876c92544dSBjoern A. Zeeb 
mt76_skb_adjust_pad(struct sk_buff * skb,int pad)6886c92544dSBjoern A. Zeeb int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
6896c92544dSBjoern A. Zeeb {
6906c92544dSBjoern A. Zeeb 	struct sk_buff *iter, *last = skb;
6916c92544dSBjoern A. Zeeb 
6926c92544dSBjoern A. Zeeb 	/* First packet of a A-MSDU burst keeps track of the whole burst
6936c92544dSBjoern A. Zeeb 	 * length, need to update length of it and the last packet.
6946c92544dSBjoern A. Zeeb 	 */
6956c92544dSBjoern A. Zeeb 	skb_walk_frags(skb, iter) {
6966c92544dSBjoern A. Zeeb 		last = iter;
6976c92544dSBjoern A. Zeeb 		if (!iter->next) {
6986c92544dSBjoern A. Zeeb 			skb->data_len += pad;
6996c92544dSBjoern A. Zeeb 			skb->len += pad;
7006c92544dSBjoern A. Zeeb 			break;
7016c92544dSBjoern A. Zeeb 		}
7026c92544dSBjoern A. Zeeb 	}
7036c92544dSBjoern A. Zeeb 
7046c92544dSBjoern A. Zeeb 	if (skb_pad(last, pad))
7056c92544dSBjoern A. Zeeb 		return -ENOMEM;
7066c92544dSBjoern A. Zeeb 
7076c92544dSBjoern A. Zeeb 	__skb_put(last, pad);
7086c92544dSBjoern A. Zeeb 
7096c92544dSBjoern A. Zeeb 	return 0;
7106c92544dSBjoern A. Zeeb }
7116c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad);
7126c92544dSBjoern A. Zeeb 
mt76_queue_tx_complete(struct mt76_dev * dev,struct mt76_queue * q,struct mt76_queue_entry * e)7136c92544dSBjoern A. Zeeb void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
7146c92544dSBjoern A. Zeeb 			    struct mt76_queue_entry *e)
7156c92544dSBjoern A. Zeeb {
7166c92544dSBjoern A. Zeeb 	if (e->skb)
7176c92544dSBjoern A. Zeeb 		dev->drv->tx_complete_skb(dev, e);
7186c92544dSBjoern A. Zeeb 
7196c92544dSBjoern A. Zeeb 	spin_lock_bh(&q->lock);
7206c92544dSBjoern A. Zeeb 	q->tail = (q->tail + 1) % q->ndesc;
7216c92544dSBjoern A. Zeeb 	q->queued--;
7226c92544dSBjoern A. Zeeb 	spin_unlock_bh(&q->lock);
7236c92544dSBjoern A. Zeeb }
7246c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
7256c92544dSBjoern A. Zeeb 
__mt76_set_tx_blocked(struct mt76_dev * dev,bool blocked)7266c92544dSBjoern A. Zeeb void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
7276c92544dSBjoern A. Zeeb {
7286c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = &dev->phy;
7296c92544dSBjoern A. Zeeb 	struct mt76_queue *q = phy->q_tx[0];
7306c92544dSBjoern A. Zeeb 
7316c92544dSBjoern A. Zeeb 	if (blocked == q->blocked)
7326c92544dSBjoern A. Zeeb 		return;
7336c92544dSBjoern A. Zeeb 
7346c92544dSBjoern A. Zeeb 	q->blocked = blocked;
7356c92544dSBjoern A. Zeeb 
7366c92544dSBjoern A. Zeeb 	phy = dev->phys[MT_BAND1];
7376c92544dSBjoern A. Zeeb 	if (phy) {
7386c92544dSBjoern A. Zeeb 		q = phy->q_tx[0];
7396c92544dSBjoern A. Zeeb 		q->blocked = blocked;
7406c92544dSBjoern A. Zeeb 	}
7416c92544dSBjoern A. Zeeb 	phy = dev->phys[MT_BAND2];
7426c92544dSBjoern A. Zeeb 	if (phy) {
7436c92544dSBjoern A. Zeeb 		q = phy->q_tx[0];
7446c92544dSBjoern A. Zeeb 		q->blocked = blocked;
7456c92544dSBjoern A. Zeeb 	}
7466c92544dSBjoern A. Zeeb 
7476c92544dSBjoern A. Zeeb 	if (!blocked)
7486c92544dSBjoern A. Zeeb 		mt76_worker_schedule(&dev->tx_worker);
7496c92544dSBjoern A. Zeeb }
7506c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_set_tx_blocked);
7516c92544dSBjoern A. Zeeb 
mt76_token_consume(struct mt76_dev * dev,struct mt76_txwi_cache ** ptxwi)7526c92544dSBjoern A. Zeeb int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
7536c92544dSBjoern A. Zeeb {
7546c92544dSBjoern A. Zeeb 	int token;
7556c92544dSBjoern A. Zeeb 
7566c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->token_lock);
7576c92544dSBjoern A. Zeeb 
7586c92544dSBjoern A. Zeeb 	token = idr_alloc(&dev->token, *ptxwi, 0, dev->token_size, GFP_ATOMIC);
7596c92544dSBjoern A. Zeeb 	if (token >= 0)
7606c92544dSBjoern A. Zeeb 		dev->token_count++;
7616c92544dSBjoern A. Zeeb 
7626c92544dSBjoern A. Zeeb #ifdef CONFIG_NET_MEDIATEK_SOC_WED
7636c92544dSBjoern A. Zeeb 	if (mtk_wed_device_active(&dev->mmio.wed) &&
7646c92544dSBjoern A. Zeeb 	    token >= dev->mmio.wed.wlan.token_start)
7656c92544dSBjoern A. Zeeb 		dev->wed_token_count++;
7666c92544dSBjoern A. Zeeb #endif
7676c92544dSBjoern A. Zeeb 
7686c92544dSBjoern A. Zeeb 	if (dev->token_count >= dev->token_size - MT76_TOKEN_FREE_THR)
7696c92544dSBjoern A. Zeeb 		__mt76_set_tx_blocked(dev, true);
7706c92544dSBjoern A. Zeeb 
7716c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->token_lock);
7726c92544dSBjoern A. Zeeb 
7736c92544dSBjoern A. Zeeb 	return token;
7746c92544dSBjoern A. Zeeb }
7756c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_token_consume);
7766c92544dSBjoern A. Zeeb 
mt76_rx_token_consume(struct mt76_dev * dev,void * ptr,struct mt76_txwi_cache * t,dma_addr_t phys)777cbb3ec25SBjoern A. Zeeb int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
778cbb3ec25SBjoern A. Zeeb 			  struct mt76_txwi_cache *t, dma_addr_t phys)
779cbb3ec25SBjoern A. Zeeb {
780cbb3ec25SBjoern A. Zeeb 	int token;
781cbb3ec25SBjoern A. Zeeb 
782cbb3ec25SBjoern A. Zeeb 	spin_lock_bh(&dev->rx_token_lock);
783cbb3ec25SBjoern A. Zeeb 	token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size,
784cbb3ec25SBjoern A. Zeeb 			  GFP_ATOMIC);
785cbb3ec25SBjoern A. Zeeb 	if (token >= 0) {
786cbb3ec25SBjoern A. Zeeb 		t->ptr = ptr;
787cbb3ec25SBjoern A. Zeeb 		t->dma_addr = phys;
788cbb3ec25SBjoern A. Zeeb 	}
789cbb3ec25SBjoern A. Zeeb 	spin_unlock_bh(&dev->rx_token_lock);
790cbb3ec25SBjoern A. Zeeb 
791cbb3ec25SBjoern A. Zeeb 	return token;
792cbb3ec25SBjoern A. Zeeb }
793cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_token_consume);
794cbb3ec25SBjoern A. Zeeb 
7956c92544dSBjoern A. Zeeb struct mt76_txwi_cache *
mt76_token_release(struct mt76_dev * dev,int token,bool * wake)7966c92544dSBjoern A. Zeeb mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
7976c92544dSBjoern A. Zeeb {
7986c92544dSBjoern A. Zeeb 	struct mt76_txwi_cache *txwi;
7996c92544dSBjoern A. Zeeb 
8006c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->token_lock);
8016c92544dSBjoern A. Zeeb 
8026c92544dSBjoern A. Zeeb 	txwi = idr_remove(&dev->token, token);
8036c92544dSBjoern A. Zeeb 	if (txwi) {
8046c92544dSBjoern A. Zeeb 		dev->token_count--;
8056c92544dSBjoern A. Zeeb 
8066c92544dSBjoern A. Zeeb #ifdef CONFIG_NET_MEDIATEK_SOC_WED
8076c92544dSBjoern A. Zeeb 		if (mtk_wed_device_active(&dev->mmio.wed) &&
8086c92544dSBjoern A. Zeeb 		    token >= dev->mmio.wed.wlan.token_start &&
8096c92544dSBjoern A. Zeeb 		    --dev->wed_token_count == 0)
8106c92544dSBjoern A. Zeeb 			wake_up(&dev->tx_wait);
8116c92544dSBjoern A. Zeeb #endif
8126c92544dSBjoern A. Zeeb 	}
8136c92544dSBjoern A. Zeeb 
8146c92544dSBjoern A. Zeeb 	if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR &&
8156c92544dSBjoern A. Zeeb 	    dev->phy.q_tx[0]->blocked)
8166c92544dSBjoern A. Zeeb 		*wake = true;
8176c92544dSBjoern A. Zeeb 
8186c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->token_lock);
8196c92544dSBjoern A. Zeeb 
8206c92544dSBjoern A. Zeeb 	return txwi;
8216c92544dSBjoern A. Zeeb }
8226c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_token_release);
823cbb3ec25SBjoern A. Zeeb 
824cbb3ec25SBjoern A. Zeeb struct mt76_txwi_cache *
mt76_rx_token_release(struct mt76_dev * dev,int token)825cbb3ec25SBjoern A. Zeeb mt76_rx_token_release(struct mt76_dev *dev, int token)
826cbb3ec25SBjoern A. Zeeb {
827cbb3ec25SBjoern A. Zeeb 	struct mt76_txwi_cache *t;
828cbb3ec25SBjoern A. Zeeb 
829cbb3ec25SBjoern A. Zeeb 	spin_lock_bh(&dev->rx_token_lock);
830cbb3ec25SBjoern A. Zeeb 	t = idr_remove(&dev->rx_token, token);
831cbb3ec25SBjoern A. Zeeb 	spin_unlock_bh(&dev->rx_token_lock);
832cbb3ec25SBjoern A. Zeeb 
833cbb3ec25SBjoern A. Zeeb 	return t;
834cbb3ec25SBjoern A. Zeeb }
835cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_token_release);
836