18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "mt76.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistatic int
98c2ecf20Sopenharmony_cimt76_txq_get_qid(struct ieee80211_txq *txq)
108c2ecf20Sopenharmony_ci{
118c2ecf20Sopenharmony_ci	if (!txq->sta)
128c2ecf20Sopenharmony_ci		return MT_TXQ_BE;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	return txq->ac;
158c2ecf20Sopenharmony_ci}
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_civoid
188c2ecf20Sopenharmony_cimt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
218c2ecf20Sopenharmony_ci	struct ieee80211_txq *txq;
228c2ecf20Sopenharmony_ci	struct mt76_txq *mtxq;
238c2ecf20Sopenharmony_ci	u8 tid;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if (!sta || !ieee80211_is_data_qos(hdr->frame_control) ||
268c2ecf20Sopenharmony_ci	    !ieee80211_is_data_present(hdr->frame_control))
278c2ecf20Sopenharmony_ci		return;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
308c2ecf20Sopenharmony_ci	txq = sta->txq[tid];
318c2ecf20Sopenharmony_ci	mtxq = (struct mt76_txq *)txq->drv_priv;
328c2ecf20Sopenharmony_ci	if (!mtxq->aggr)
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_civoid
408c2ecf20Sopenharmony_cimt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
418c2ecf20Sopenharmony_ci		   __acquires(&dev->status_list.lock)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	__skb_queue_head_init(list);
448c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->status_list.lock);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_lock);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid
498c2ecf20Sopenharmony_cimt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
508c2ecf20Sopenharmony_ci		      __releases(&dev->status_list.lock)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw;
538c2ecf20Sopenharmony_ci	struct sk_buff *skb;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->status_list.lock);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(list)) != NULL) {
588c2ecf20Sopenharmony_ci		hw = mt76_tx_status_get_hw(dev, skb);
598c2ecf20Sopenharmony_ci		ieee80211_tx_status(hw, skb);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_unlock);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void
668c2ecf20Sopenharmony_ci__mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
678c2ecf20Sopenharmony_ci			  struct sk_buff_head *list)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
708c2ecf20Sopenharmony_ci	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
718c2ecf20Sopenharmony_ci	u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	flags |= cb->flags;
748c2ecf20Sopenharmony_ci	cb->flags = flags;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if ((flags & done) != done)
778c2ecf20Sopenharmony_ci		return;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	__skb_unlink(skb, &dev->status_list);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* Tx status can be unreliable. if it fails, mark the frame as ACKed */
828c2ecf20Sopenharmony_ci	if (flags & MT_TX_CB_TXS_FAILED) {
838c2ecf20Sopenharmony_ci		ieee80211_tx_info_clear_status(info);
848c2ecf20Sopenharmony_ci		info->status.rates[0].idx = -1;
858c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	__skb_queue_tail(list, skb);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_civoid
928c2ecf20Sopenharmony_cimt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
938c2ecf20Sopenharmony_ci			struct sk_buff_head *list)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_skb_done);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint
1008c2ecf20Sopenharmony_cimt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
1018c2ecf20Sopenharmony_ci		       struct sk_buff *skb)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1048c2ecf20Sopenharmony_ci	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
1058c2ecf20Sopenharmony_ci	int pid;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (!wcid)
1088c2ecf20Sopenharmony_ci		return MT_PACKET_ID_NO_ACK;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
1118c2ecf20Sopenharmony_ci		return MT_PACKET_ID_NO_ACK;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
1148c2ecf20Sopenharmony_ci			     IEEE80211_TX_CTL_RATE_CTRL_PROBE)))
1158c2ecf20Sopenharmony_ci		return MT_PACKET_ID_NO_SKB;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->status_list.lock);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	memset(cb, 0, sizeof(*cb));
1208c2ecf20Sopenharmony_ci	wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK;
1218c2ecf20Sopenharmony_ci	if (wcid->packet_id == MT_PACKET_ID_NO_ACK ||
1228c2ecf20Sopenharmony_ci	    wcid->packet_id == MT_PACKET_ID_NO_SKB)
1238c2ecf20Sopenharmony_ci		wcid->packet_id = MT_PACKET_ID_FIRST;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	pid = wcid->packet_id;
1268c2ecf20Sopenharmony_ci	cb->wcid = wcid->idx;
1278c2ecf20Sopenharmony_ci	cb->pktid = pid;
1288c2ecf20Sopenharmony_ci	cb->jiffies = jiffies;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	__skb_queue_tail(&dev->status_list, skb);
1318c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->status_list.lock);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return pid;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_skb_add);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistruct sk_buff *
1388c2ecf20Sopenharmony_cimt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid,
1398c2ecf20Sopenharmony_ci		       struct sk_buff_head *list)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct sk_buff *skb, *tmp;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	skb_queue_walk_safe(&dev->status_list, skb, tmp) {
1448c2ecf20Sopenharmony_ci		struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		if (wcid && cb->wcid != wcid->idx)
1478c2ecf20Sopenharmony_ci			continue;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		if (cb->pktid == pktid)
1508c2ecf20Sopenharmony_ci			return skb;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		if (pktid >= 0 && !time_after(jiffies, cb->jiffies +
1538c2ecf20Sopenharmony_ci					      MT_TX_STATUS_SKB_TIMEOUT))
1548c2ecf20Sopenharmony_ci			continue;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED |
1578c2ecf20Sopenharmony_ci						    MT_TX_CB_TXS_DONE, list);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return NULL;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_skb_get);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_civoid
1658c2ecf20Sopenharmony_cimt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	struct sk_buff_head list;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	mt76_tx_status_lock(dev, &list);
1708c2ecf20Sopenharmony_ci	mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list);
1718c2ecf20Sopenharmony_ci	mt76_tx_status_unlock(dev, &list);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_status_check);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void
1768c2ecf20Sopenharmony_cimt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1798c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
1808c2ecf20Sopenharmony_ci	int pending;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (info->tx_time_est)
1838c2ecf20Sopenharmony_ci		return;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (wcid_idx >= ARRAY_SIZE(dev->wcid))
1868c2ecf20Sopenharmony_ci		return;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	rcu_read_lock();
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	wcid = rcu_dereference(dev->wcid[wcid_idx]);
1918c2ecf20Sopenharmony_ci	if (wcid) {
1928c2ecf20Sopenharmony_ci		pending = atomic_dec_return(&wcid->non_aql_packets);
1938c2ecf20Sopenharmony_ci		if (pending < 0)
1948c2ecf20Sopenharmony_ci			atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	rcu_read_unlock();
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_civoid mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw;
2038c2ecf20Sopenharmony_ci	struct sk_buff_head list;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
2068c2ecf20Sopenharmony_ci	if (skb == dev->test.tx_skb) {
2078c2ecf20Sopenharmony_ci		dev->test.tx_done++;
2088c2ecf20Sopenharmony_ci		if (dev->test.tx_queued == dev->test.tx_done)
2098c2ecf20Sopenharmony_ci			wake_up(&dev->tx_wait);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci#endif
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	mt76_tx_check_non_aql(dev, wcid_idx, skb);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (!skb->prev) {
2168c2ecf20Sopenharmony_ci		hw = mt76_tx_status_get_hw(dev, skb);
2178c2ecf20Sopenharmony_ci		ieee80211_free_txskb(hw, skb);
2188c2ecf20Sopenharmony_ci		return;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	mt76_tx_status_lock(dev, &list);
2228c2ecf20Sopenharmony_ci	__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list);
2238c2ecf20Sopenharmony_ci	mt76_tx_status_unlock(dev, &list);
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int
2288c2ecf20Sopenharmony_ci__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb,
2298c2ecf20Sopenharmony_ci		    struct mt76_wcid *wcid, struct ieee80211_sta *sta,
2308c2ecf20Sopenharmony_ci		    bool *stop)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2338c2ecf20Sopenharmony_ci	struct mt76_queue *q;
2348c2ecf20Sopenharmony_ci	bool non_aql;
2358c2ecf20Sopenharmony_ci	int pending;
2368c2ecf20Sopenharmony_ci	int idx;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	non_aql = !info->tx_time_est;
2398c2ecf20Sopenharmony_ci	idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
2408c2ecf20Sopenharmony_ci	if (idx < 0 || !sta || !non_aql)
2418c2ecf20Sopenharmony_ci		return idx;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	wcid = (struct mt76_wcid *)sta->drv_priv;
2448c2ecf20Sopenharmony_ci	q = dev->q_tx[qid];
2458c2ecf20Sopenharmony_ci	q->entry[idx].wcid = wcid->idx;
2468c2ecf20Sopenharmony_ci	pending = atomic_inc_return(&wcid->non_aql_packets);
2478c2ecf20Sopenharmony_ci	if (stop && pending >= MT_MAX_NON_AQL_PKT)
2488c2ecf20Sopenharmony_ci		*stop = true;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return idx;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_civoid
2548c2ecf20Sopenharmony_cimt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
2558c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid, struct sk_buff *skb)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct mt76_dev *dev = phy->dev;
2588c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2598c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
2608c2ecf20Sopenharmony_ci	struct mt76_queue *q;
2618c2ecf20Sopenharmony_ci	int qid = skb_get_queue_mapping(skb);
2628c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (mt76_testmode_enabled(dev)) {
2658c2ecf20Sopenharmony_ci		ieee80211_free_txskb(phy->hw, skb);
2668c2ecf20Sopenharmony_ci		return;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (WARN_ON(qid >= MT_TXQ_PSD)) {
2708c2ecf20Sopenharmony_ci		qid = MT_TXQ_BE;
2718c2ecf20Sopenharmony_ci		skb_set_queue_mapping(skb, qid);
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
2758c2ecf20Sopenharmony_ci	    !ieee80211_is_data(hdr->frame_control) &&
2768c2ecf20Sopenharmony_ci	    !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
2778c2ecf20Sopenharmony_ci		qid = MT_TXQ_PSD;
2788c2ecf20Sopenharmony_ci		skb_set_queue_mapping(skb, qid);
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET))
2828c2ecf20Sopenharmony_ci		ieee80211_get_tx_rates(info->control.vif, sta, skb,
2838c2ecf20Sopenharmony_ci				       info->control.rates, 1);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (ext_phy)
2868c2ecf20Sopenharmony_ci		info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	q = dev->q_tx[qid];
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	spin_lock_bh(&q->lock);
2918c2ecf20Sopenharmony_ci	__mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL);
2928c2ecf20Sopenharmony_ci	dev->queue_ops->kick(dev, q);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (q->queued > q->ndesc - 8 && !q->stopped) {
2958c2ecf20Sopenharmony_ci		ieee80211_stop_queue(phy->hw, skb_get_queue_mapping(skb));
2968c2ecf20Sopenharmony_ci		q->stopped = true;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	spin_unlock_bh(&q->lock);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_tx);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic struct sk_buff *
3048c2ecf20Sopenharmony_cimt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
3078c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
3088c2ecf20Sopenharmony_ci	bool ext_phy = phy != &phy->dev->phy;
3098c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	skb = ieee80211_tx_dequeue(phy->hw, txq);
3128c2ecf20Sopenharmony_ci	if (!skb)
3138c2ecf20Sopenharmony_ci		return NULL;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
3168c2ecf20Sopenharmony_ci	if (ext_phy)
3178c2ecf20Sopenharmony_ci		info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return skb;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic void
3238c2ecf20Sopenharmony_cimt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
3248c2ecf20Sopenharmony_ci		  struct sk_buff *skb, bool last)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
3278c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
3308c2ecf20Sopenharmony_ci	if (last)
3318c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STATUS_EOSP |
3328c2ecf20Sopenharmony_ci			       IEEE80211_TX_CTL_REQ_TX_STATUS;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	mt76_skb_set_moredata(skb, !last);
3358c2ecf20Sopenharmony_ci	__mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_civoid
3398c2ecf20Sopenharmony_cimt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
3408c2ecf20Sopenharmony_ci			     u16 tids, int nframes,
3418c2ecf20Sopenharmony_ci			     enum ieee80211_frame_release_type reason,
3428c2ecf20Sopenharmony_ci			     bool more_data)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct mt76_phy *phy = hw->priv;
3458c2ecf20Sopenharmony_ci	struct mt76_dev *dev = phy->dev;
3468c2ecf20Sopenharmony_ci	struct sk_buff *last_skb = NULL;
3478c2ecf20Sopenharmony_ci	struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD];
3488c2ecf20Sopenharmony_ci	int i;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	spin_lock_bh(&hwq->lock);
3518c2ecf20Sopenharmony_ci	for (i = 0; tids && nframes; i++, tids >>= 1) {
3528c2ecf20Sopenharmony_ci		struct ieee80211_txq *txq = sta->txq[i];
3538c2ecf20Sopenharmony_ci		struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
3548c2ecf20Sopenharmony_ci		struct sk_buff *skb;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci		if (!(tids & 1))
3578c2ecf20Sopenharmony_ci			continue;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		do {
3608c2ecf20Sopenharmony_ci			skb = mt76_txq_dequeue(phy, mtxq);
3618c2ecf20Sopenharmony_ci			if (!skb)
3628c2ecf20Sopenharmony_ci				break;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci			nframes--;
3658c2ecf20Sopenharmony_ci			if (last_skb)
3668c2ecf20Sopenharmony_ci				mt76_queue_ps_skb(dev, sta, last_skb, false);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci			last_skb = skb;
3698c2ecf20Sopenharmony_ci		} while (nframes);
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (last_skb) {
3738c2ecf20Sopenharmony_ci		mt76_queue_ps_skb(dev, sta, last_skb, true);
3748c2ecf20Sopenharmony_ci		dev->queue_ops->kick(dev, hwq);
3758c2ecf20Sopenharmony_ci	} else {
3768c2ecf20Sopenharmony_ci		ieee80211_sta_eosp(sta);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	spin_unlock_bh(&hwq->lock);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int
3848c2ecf20Sopenharmony_cimt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
3858c2ecf20Sopenharmony_ci		    struct mt76_txq *mtxq)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct mt76_dev *dev = phy->dev;
3888c2ecf20Sopenharmony_ci	struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
3898c2ecf20Sopenharmony_ci	enum mt76_txq_id qid = mt76_txq_get_qid(txq);
3908c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid = mtxq->wcid;
3918c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
3928c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3938c2ecf20Sopenharmony_ci	int n_frames = 1;
3948c2ecf20Sopenharmony_ci	bool stop = false;
3958c2ecf20Sopenharmony_ci	int idx;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
3988c2ecf20Sopenharmony_ci		return 0;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	skb = mt76_txq_dequeue(phy, mtxq);
4048c2ecf20Sopenharmony_ci	if (!skb)
4058c2ecf20Sopenharmony_ci		return 0;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
4088c2ecf20Sopenharmony_ci	if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
4098c2ecf20Sopenharmony_ci		ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
4108c2ecf20Sopenharmony_ci				       info->control.rates, 1);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
4138c2ecf20Sopenharmony_ci	if (idx < 0)
4148c2ecf20Sopenharmony_ci		return idx;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	do {
4178c2ecf20Sopenharmony_ci		if (test_bit(MT76_STATE_PM, &phy->state) ||
4188c2ecf20Sopenharmony_ci		    test_bit(MT76_RESET, &phy->state))
4198c2ecf20Sopenharmony_ci			return -EBUSY;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		if (stop)
4228c2ecf20Sopenharmony_ci			break;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
4258c2ecf20Sopenharmony_ci			break;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		skb = mt76_txq_dequeue(phy, mtxq);
4288c2ecf20Sopenharmony_ci		if (!skb)
4298c2ecf20Sopenharmony_ci			break;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		info = IEEE80211_SKB_CB(skb);
4328c2ecf20Sopenharmony_ci		if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
4338c2ecf20Sopenharmony_ci			ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
4348c2ecf20Sopenharmony_ci					       info->control.rates, 1);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
4378c2ecf20Sopenharmony_ci		if (idx < 0)
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		n_frames++;
4418c2ecf20Sopenharmony_ci	} while (1);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	dev->queue_ops->kick(dev, q);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	return n_frames;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int
4498c2ecf20Sopenharmony_cimt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	struct mt76_dev *dev = phy->dev;
4528c2ecf20Sopenharmony_ci	struct mt76_queue *q = dev->q_tx[qid];
4538c2ecf20Sopenharmony_ci	struct ieee80211_txq *txq;
4548c2ecf20Sopenharmony_ci	struct mt76_txq *mtxq;
4558c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
4568c2ecf20Sopenharmony_ci	int ret = 0;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	spin_lock_bh(&q->lock);
4598c2ecf20Sopenharmony_ci	while (1) {
4608c2ecf20Sopenharmony_ci		if (test_bit(MT76_STATE_PM, &phy->state) ||
4618c2ecf20Sopenharmony_ci		    test_bit(MT76_RESET, &phy->state)) {
4628c2ecf20Sopenharmony_ci			ret = -EBUSY;
4638c2ecf20Sopenharmony_ci			break;
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
4678c2ecf20Sopenharmony_ci			break;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		txq = ieee80211_next_txq(phy->hw, qid);
4708c2ecf20Sopenharmony_ci		if (!txq)
4718c2ecf20Sopenharmony_ci			break;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		mtxq = (struct mt76_txq *)txq->drv_priv;
4748c2ecf20Sopenharmony_ci		wcid = mtxq->wcid;
4758c2ecf20Sopenharmony_ci		if (wcid && test_bit(MT_WCID_FLAG_PS, &wcid->flags))
4768c2ecf20Sopenharmony_ci			continue;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		if (mtxq->send_bar && mtxq->aggr) {
4798c2ecf20Sopenharmony_ci			struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
4808c2ecf20Sopenharmony_ci			struct ieee80211_sta *sta = txq->sta;
4818c2ecf20Sopenharmony_ci			struct ieee80211_vif *vif = txq->vif;
4828c2ecf20Sopenharmony_ci			u16 agg_ssn = mtxq->agg_ssn;
4838c2ecf20Sopenharmony_ci			u8 tid = txq->tid;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci			mtxq->send_bar = false;
4868c2ecf20Sopenharmony_ci			spin_unlock_bh(&q->lock);
4878c2ecf20Sopenharmony_ci			ieee80211_send_bar(vif, sta->addr, tid, agg_ssn);
4888c2ecf20Sopenharmony_ci			spin_lock_bh(&q->lock);
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		ret += mt76_txq_send_burst(phy, q, mtxq);
4928c2ecf20Sopenharmony_ci		ieee80211_return_txq(phy->hw, txq, false);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	spin_unlock_bh(&q->lock);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	return ret;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_civoid mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	int len;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (qid >= 4)
5048c2ecf20Sopenharmony_ci		return;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	rcu_read_lock();
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	do {
5098c2ecf20Sopenharmony_ci		ieee80211_txq_schedule_start(phy->hw, qid);
5108c2ecf20Sopenharmony_ci		len = mt76_txq_schedule_list(phy, qid);
5118c2ecf20Sopenharmony_ci		ieee80211_txq_schedule_end(phy->hw, qid);
5128c2ecf20Sopenharmony_ci	} while (len > 0);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	rcu_read_unlock();
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_txq_schedule);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_civoid mt76_txq_schedule_all(struct mt76_phy *phy)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int i;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	for (i = 0; i <= MT_TXQ_BK; i++)
5238c2ecf20Sopenharmony_ci		mt76_txq_schedule(phy, i);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_civoid mt76_tx_worker(struct mt76_worker *w)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	mt76_txq_schedule_all(&dev->phy);
5328c2ecf20Sopenharmony_ci	if (dev->phy2)
5338c2ecf20Sopenharmony_ci		mt76_txq_schedule_all(dev->phy2);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
5368c2ecf20Sopenharmony_ci	if (dev->test.tx_pending)
5378c2ecf20Sopenharmony_ci		mt76_testmode_tx_pending(dev);
5388c2ecf20Sopenharmony_ci#endif
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_civoid mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
5428c2ecf20Sopenharmony_ci			 bool send_bar)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	int i;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
5478c2ecf20Sopenharmony_ci		struct ieee80211_txq *txq = sta->txq[i];
5488c2ecf20Sopenharmony_ci		struct mt76_queue *hwq;
5498c2ecf20Sopenharmony_ci		struct mt76_txq *mtxq;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (!txq)
5528c2ecf20Sopenharmony_ci			continue;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		hwq = dev->q_tx[mt76_txq_get_qid(txq)];
5558c2ecf20Sopenharmony_ci		mtxq = (struct mt76_txq *)txq->drv_priv;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		spin_lock_bh(&hwq->lock);
5588c2ecf20Sopenharmony_ci		mtxq->send_bar = mtxq->aggr && send_bar;
5598c2ecf20Sopenharmony_ci		spin_unlock_bh(&hwq->lock);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_stop_tx_queues);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_civoid mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct mt76_phy *phy = hw->priv;
5678c2ecf20Sopenharmony_ci	struct mt76_dev *dev = phy->dev;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &phy->state))
5708c2ecf20Sopenharmony_ci		return;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	mt76_worker_schedule(&dev->tx_worker);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ciu8 mt76_ac_to_hwq(u8 ac)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	static const u8 wmm_queue_map[] = {
5798c2ecf20Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
5808c2ecf20Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
5818c2ecf20Sopenharmony_ci		[IEEE80211_AC_VI] = 2,
5828c2ecf20Sopenharmony_ci		[IEEE80211_AC_VO] = 3,
5838c2ecf20Sopenharmony_ci	};
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (WARN_ON(ac >= IEEE80211_NUM_ACS))
5868c2ecf20Sopenharmony_ci		return 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	return wmm_queue_map[ac];
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ciint mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct sk_buff *iter, *last = skb;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	/* First packet of a A-MSDU burst keeps track of the whole burst
5978c2ecf20Sopenharmony_ci	 * length, need to update length of it and the last packet.
5988c2ecf20Sopenharmony_ci	 */
5998c2ecf20Sopenharmony_ci	skb_walk_frags(skb, iter) {
6008c2ecf20Sopenharmony_ci		last = iter;
6018c2ecf20Sopenharmony_ci		if (!iter->next) {
6028c2ecf20Sopenharmony_ci			skb->data_len += pad;
6038c2ecf20Sopenharmony_ci			skb->len += pad;
6048c2ecf20Sopenharmony_ci			break;
6058c2ecf20Sopenharmony_ci		}
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (skb_pad(last, pad))
6098c2ecf20Sopenharmony_ci		return -ENOMEM;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	__skb_put(last, pad);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return 0;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_skb_adjust_pad);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_civoid mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
6188c2ecf20Sopenharmony_ci			    struct mt76_queue_entry *e)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	if (e->skb)
6218c2ecf20Sopenharmony_ci		dev->drv->tx_complete_skb(dev, e);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	spin_lock_bh(&q->lock);
6248c2ecf20Sopenharmony_ci	q->tail = (q->tail + 1) % q->ndesc;
6258c2ecf20Sopenharmony_ci	q->queued--;
6268c2ecf20Sopenharmony_ci	spin_unlock_bh(&q->lock);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
629