10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau */
517f1de56SFelix Fietkau
617f1de56SFelix Fietkau #include "mt76.h"
717f1de56SFelix Fietkau
817f1de56SFelix Fietkau static int
mt76_txq_get_qid(struct ieee80211_txq * txq)917f1de56SFelix Fietkau mt76_txq_get_qid(struct ieee80211_txq *txq)
1017f1de56SFelix Fietkau {
1117f1de56SFelix Fietkau if (!txq->sta)
1217f1de56SFelix Fietkau return MT_TXQ_BE;
1317f1de56SFelix Fietkau
1417f1de56SFelix Fietkau return txq->ac;
1517f1de56SFelix Fietkau }
1617f1de56SFelix Fietkau
17c50d105aSFelix Fietkau void
mt76_tx_check_agg_ssn(struct ieee80211_sta * sta,struct sk_buff * skb)18c50d105aSFelix Fietkau mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb)
1949f45fa1SFelix Fietkau {
2049f45fa1SFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
21c50d105aSFelix Fietkau struct ieee80211_txq *txq;
22c50d105aSFelix Fietkau struct mt76_txq *mtxq;
23c50d105aSFelix Fietkau u8 tid;
2449f45fa1SFelix Fietkau
25c50d105aSFelix Fietkau if (!sta || !ieee80211_is_data_qos(hdr->frame_control) ||
265155938dSFelix Fietkau !ieee80211_is_data_present(hdr->frame_control))
2749f45fa1SFelix Fietkau return;
2849f45fa1SFelix Fietkau
29c50d105aSFelix Fietkau tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
30c50d105aSFelix Fietkau txq = sta->txq[tid];
31c50d105aSFelix Fietkau mtxq = (struct mt76_txq *)txq->drv_priv;
32c50d105aSFelix Fietkau if (!mtxq->aggr)
33c50d105aSFelix Fietkau return;
34c50d105aSFelix Fietkau
3549f45fa1SFelix Fietkau mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
3649f45fa1SFelix Fietkau }
37c50d105aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
3849f45fa1SFelix Fietkau
3917f1de56SFelix Fietkau void
mt76_tx_status_lock(struct mt76_dev * dev,struct sk_buff_head * list)4079d1c94cSFelix Fietkau mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
41c34f1005SLorenzo Bianconi __acquires(&dev->status_lock)
4279d1c94cSFelix Fietkau {
4379d1c94cSFelix Fietkau __skb_queue_head_init(list);
44c34f1005SLorenzo Bianconi spin_lock_bh(&dev->status_lock);
4579d1c94cSFelix Fietkau }
4679d1c94cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_lock);
4779d1c94cSFelix Fietkau
4879d1c94cSFelix Fietkau void
mt76_tx_status_unlock(struct mt76_dev * dev,struct sk_buff_head * list)4979d1c94cSFelix Fietkau mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
50c34f1005SLorenzo Bianconi __releases(&dev->status_lock)
5179d1c94cSFelix Fietkau {
52e394b575SFelix Fietkau struct ieee80211_hw *hw;
5379d1c94cSFelix Fietkau struct sk_buff *skb;
5479d1c94cSFelix Fietkau
55c34f1005SLorenzo Bianconi spin_unlock_bh(&dev->status_lock);
5679d1c94cSFelix Fietkau
570fe88644SFelix Fietkau rcu_read_lock();
58e394b575SFelix Fietkau while ((skb = __skb_dequeue(list)) != NULL) {
590fe88644SFelix Fietkau struct ieee80211_tx_status status = {
600fe88644SFelix Fietkau .skb = skb,
610fe88644SFelix Fietkau .info = IEEE80211_SKB_CB(skb),
620fe88644SFelix Fietkau };
636b430f72SFelix Fietkau struct ieee80211_rate_status rs = {};
640fe88644SFelix Fietkau struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
650fe88644SFelix Fietkau struct mt76_wcid *wcid;
66e394b575SFelix Fietkau
670fe88644SFelix Fietkau wcid = rcu_dereference(dev->wcid[cb->wcid]);
689908d98aSRyder Lee if (wcid) {
690fe88644SFelix Fietkau status.sta = wcid_to_sta(wcid);
706b430f72SFelix Fietkau if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
716b430f72SFelix Fietkau rs.rate_idx = wcid->rate;
726b430f72SFelix Fietkau status.rates = &rs;
736b430f72SFelix Fietkau status.n_rates = 1;
746b430f72SFelix Fietkau } else {
7544fa75f2SJonas Jelonek status.n_rates = 0;
769908d98aSRyder Lee }
776b430f72SFelix Fietkau }
789908d98aSRyder Lee
790fe88644SFelix Fietkau hw = mt76_tx_status_get_hw(dev, skb);
805b8ccdfbSFelix Fietkau spin_lock_bh(&dev->rx_lock);
810fe88644SFelix Fietkau ieee80211_tx_status_ext(hw, &status);
825b8ccdfbSFelix Fietkau spin_unlock_bh(&dev->rx_lock);
830fe88644SFelix Fietkau }
840fe88644SFelix Fietkau rcu_read_unlock();
8579d1c94cSFelix Fietkau }
8679d1c94cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_unlock);
8779d1c94cSFelix Fietkau
8888046b2cSFelix Fietkau static void
__mt76_tx_status_skb_done(struct mt76_dev * dev,struct sk_buff * skb,u8 flags,struct sk_buff_head * list)8979d1c94cSFelix Fietkau __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
9079d1c94cSFelix Fietkau struct sk_buff_head *list)
9188046b2cSFelix Fietkau {
9288046b2cSFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
9388046b2cSFelix Fietkau struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
9488046b2cSFelix Fietkau u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE;
9588046b2cSFelix Fietkau
9688046b2cSFelix Fietkau flags |= cb->flags;
9788046b2cSFelix Fietkau cb->flags = flags;
9888046b2cSFelix Fietkau
9988046b2cSFelix Fietkau if ((flags & done) != done)
10088046b2cSFelix Fietkau return;
10188046b2cSFelix Fietkau
10288046b2cSFelix Fietkau /* Tx status can be unreliable. if it fails, mark the frame as ACKed */
10388046b2cSFelix Fietkau if (flags & MT_TX_CB_TXS_FAILED) {
1040fe88644SFelix Fietkau info->status.rates[0].count = 0;
10588046b2cSFelix Fietkau info->status.rates[0].idx = -1;
10688046b2cSFelix Fietkau info->flags |= IEEE80211_TX_STAT_ACK;
10788046b2cSFelix Fietkau }
10888046b2cSFelix Fietkau
10979d1c94cSFelix Fietkau __skb_queue_tail(list, skb);
11088046b2cSFelix Fietkau }
11188046b2cSFelix Fietkau
11288046b2cSFelix Fietkau void
mt76_tx_status_skb_done(struct mt76_dev * dev,struct sk_buff * skb,struct sk_buff_head * list)11379d1c94cSFelix Fietkau mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
11479d1c94cSFelix Fietkau struct sk_buff_head *list)
11588046b2cSFelix Fietkau {
11679d1c94cSFelix Fietkau __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list);
11788046b2cSFelix Fietkau }
11888046b2cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_skb_done);
11988046b2cSFelix Fietkau
12088046b2cSFelix Fietkau int
mt76_tx_status_skb_add(struct mt76_dev * dev,struct mt76_wcid * wcid,struct sk_buff * skb)12188046b2cSFelix Fietkau mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
12288046b2cSFelix Fietkau struct sk_buff *skb)
12388046b2cSFelix Fietkau {
124f39d4993SPeter Chiu struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
12588046b2cSFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
12688046b2cSFelix Fietkau struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
12788046b2cSFelix Fietkau int pid;
12888046b2cSFelix Fietkau
129bd1e3e7bSLorenzo Bianconi memset(cb, 0, sizeof(*cb));
130bd1e3e7bSLorenzo Bianconi
131fcfe1b5eSFelix Fietkau if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx]))
132013b2dffSFelix Fietkau return MT_PACKET_ID_NO_ACK;
13388046b2cSFelix Fietkau
13488046b2cSFelix Fietkau if (info->flags & IEEE80211_TX_CTL_NO_ACK)
13588046b2cSFelix Fietkau return MT_PACKET_ID_NO_ACK;
13688046b2cSFelix Fietkau
13788046b2cSFelix Fietkau if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
138f39d4993SPeter Chiu IEEE80211_TX_CTL_RATE_CTRL_PROBE))) {
139f39d4993SPeter Chiu if (mtk_wed_device_active(&dev->mmio.wed) &&
140f39d4993SPeter Chiu ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ||
141f39d4993SPeter Chiu ieee80211_is_data(hdr->frame_control)))
142f39d4993SPeter Chiu return MT_PACKET_ID_WED;
143f39d4993SPeter Chiu
144013b2dffSFelix Fietkau return MT_PACKET_ID_NO_SKB;
145f39d4993SPeter Chiu }
14688046b2cSFelix Fietkau
147c34f1005SLorenzo Bianconi spin_lock_bh(&dev->status_lock);
14888046b2cSFelix Fietkau
149bd1e3e7bSLorenzo Bianconi pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST,
150bd1e3e7bSLorenzo Bianconi MT_PACKET_ID_MASK, GFP_ATOMIC);
151bd1e3e7bSLorenzo Bianconi if (pid < 0) {
152bd1e3e7bSLorenzo Bianconi pid = MT_PACKET_ID_NO_SKB;
153bd1e3e7bSLorenzo Bianconi goto out;
154bd1e3e7bSLorenzo Bianconi }
155bd1e3e7bSLorenzo Bianconi
15688046b2cSFelix Fietkau cb->wcid = wcid->idx;
15788046b2cSFelix Fietkau cb->pktid = pid;
15888046b2cSFelix Fietkau
159bd1e3e7bSLorenzo Bianconi if (list_empty(&wcid->list))
160bd1e3e7bSLorenzo Bianconi list_add_tail(&wcid->list, &dev->wcid_list);
161bd1e3e7bSLorenzo Bianconi
162bd1e3e7bSLorenzo Bianconi out:
163c34f1005SLorenzo Bianconi spin_unlock_bh(&dev->status_lock);
16488046b2cSFelix Fietkau
16588046b2cSFelix Fietkau return pid;
16688046b2cSFelix Fietkau }
16788046b2cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_skb_add);
16888046b2cSFelix Fietkau
16988046b2cSFelix Fietkau struct sk_buff *
mt76_tx_status_skb_get(struct mt76_dev * dev,struct mt76_wcid * wcid,int pktid,struct sk_buff_head * list)17079d1c94cSFelix Fietkau mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid,
17179d1c94cSFelix Fietkau struct sk_buff_head *list)
17288046b2cSFelix Fietkau {
173bd1e3e7bSLorenzo Bianconi struct sk_buff *skb;
174bd1e3e7bSLorenzo Bianconi int id;
17588046b2cSFelix Fietkau
176c34f1005SLorenzo Bianconi lockdep_assert_held(&dev->status_lock);
177bd1e3e7bSLorenzo Bianconi
178bd1e3e7bSLorenzo Bianconi skb = idr_remove(&wcid->pktid, pktid);
179bd1e3e7bSLorenzo Bianconi if (skb)
180bd1e3e7bSLorenzo Bianconi goto out;
181bd1e3e7bSLorenzo Bianconi
182bd1e3e7bSLorenzo Bianconi /* look for stale entries in the wcid idr queue */
183bd1e3e7bSLorenzo Bianconi idr_for_each_entry(&wcid->pktid, skb, id) {
18488046b2cSFelix Fietkau struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
18588046b2cSFelix Fietkau
186bd1e3e7bSLorenzo Bianconi if (pktid >= 0) {
187bd1e3e7bSLorenzo Bianconi if (!(cb->flags & MT_TX_CB_DMA_DONE))
18888046b2cSFelix Fietkau continue;
18988046b2cSFelix Fietkau
190ebb75b1bSDeren Wu if (time_is_after_jiffies(cb->jiffies +
19113381dcdSRyder Lee MT_TX_STATUS_SKB_TIMEOUT))
19288046b2cSFelix Fietkau continue;
193bd1e3e7bSLorenzo Bianconi }
19488046b2cSFelix Fietkau
195c4a784e3SLorenzo Bianconi /* It has been too long since DMA_DONE, time out this packet
196c4a784e3SLorenzo Bianconi * and stop waiting for TXS callback.
197c4a784e3SLorenzo Bianconi */
198bd1e3e7bSLorenzo Bianconi idr_remove(&wcid->pktid, cb->pktid);
19988046b2cSFelix Fietkau __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED |
20079d1c94cSFelix Fietkau MT_TX_CB_TXS_DONE, list);
20188046b2cSFelix Fietkau }
20288046b2cSFelix Fietkau
203bd1e3e7bSLorenzo Bianconi out:
204bd1e3e7bSLorenzo Bianconi if (idr_is_empty(&wcid->pktid))
205bd1e3e7bSLorenzo Bianconi list_del_init(&wcid->list);
206bd1e3e7bSLorenzo Bianconi
207bd1e3e7bSLorenzo Bianconi return skb;
20888046b2cSFelix Fietkau }
20988046b2cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_skb_get);
21088046b2cSFelix Fietkau
21179d1c94cSFelix Fietkau void
mt76_tx_status_check(struct mt76_dev * dev,bool flush)212c02f86eeSLorenzo Bianconi mt76_tx_status_check(struct mt76_dev *dev, bool flush)
21379d1c94cSFelix Fietkau {
214c02f86eeSLorenzo Bianconi struct mt76_wcid *wcid, *tmp;
21579d1c94cSFelix Fietkau struct sk_buff_head list;
21679d1c94cSFelix Fietkau
21779d1c94cSFelix Fietkau mt76_tx_status_lock(dev, &list);
218bd1e3e7bSLorenzo Bianconi list_for_each_entry_safe(wcid, tmp, &dev->wcid_list, list)
21979d1c94cSFelix Fietkau mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list);
22079d1c94cSFelix Fietkau mt76_tx_status_unlock(dev, &list);
22179d1c94cSFelix Fietkau }
22279d1c94cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx_status_check);
22379d1c94cSFelix Fietkau
224e1378e52SFelix Fietkau static void
mt76_tx_check_non_aql(struct mt76_dev * dev,struct mt76_wcid * wcid,struct sk_buff * skb)2250fe88644SFelix Fietkau mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
2260fe88644SFelix Fietkau struct sk_buff *skb)
227e1378e52SFelix Fietkau {
228e1378e52SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
229e1378e52SFelix Fietkau int pending;
230e1378e52SFelix Fietkau
2310fe88644SFelix Fietkau if (!wcid || info->tx_time_est)
232e1378e52SFelix Fietkau return;
233e1378e52SFelix Fietkau
234e1378e52SFelix Fietkau pending = atomic_dec_return(&wcid->non_aql_packets);
235e1378e52SFelix Fietkau if (pending < 0)
236e1378e52SFelix Fietkau atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
237e1378e52SFelix Fietkau }
238e1378e52SFelix Fietkau
__mt76_tx_complete_skb(struct mt76_dev * dev,u16 wcid_idx,struct sk_buff * skb,struct list_head * free_list)2390fe88644SFelix Fietkau void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb,
2400fe88644SFelix Fietkau struct list_head *free_list)
24188046b2cSFelix Fietkau {
242bd1e3e7bSLorenzo Bianconi struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
2430fe88644SFelix Fietkau struct ieee80211_tx_status status = {
2440fe88644SFelix Fietkau .skb = skb,
2450fe88644SFelix Fietkau .free_list = free_list,
2460fe88644SFelix Fietkau };
2470fe88644SFelix Fietkau struct mt76_wcid *wcid = NULL;
248e394b575SFelix Fietkau struct ieee80211_hw *hw;
24979d1c94cSFelix Fietkau struct sk_buff_head list;
25079d1c94cSFelix Fietkau
2510fe88644SFelix Fietkau rcu_read_lock();
2520fe88644SFelix Fietkau
2530fe88644SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid))
2540fe88644SFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]);
2550fe88644SFelix Fietkau
2560fe88644SFelix Fietkau mt76_tx_check_non_aql(dev, wcid, skb);
257c918c74dSShayne Chen
258f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
259c918c74dSShayne Chen if (mt76_is_testmode_skb(dev, skb, &hw)) {
260c918c74dSShayne Chen struct mt76_phy *phy = hw->priv;
261c918c74dSShayne Chen
262c918c74dSShayne Chen if (skb == phy->test.tx_skb)
263c918c74dSShayne Chen phy->test.tx_done++;
264c918c74dSShayne Chen if (phy->test.tx_queued == phy->test.tx_done)
265f0efa862SFelix Fietkau wake_up(&dev->tx_wait);
266c918c74dSShayne Chen
2672601dda8SShayne Chen dev_kfree_skb_any(skb);
2680fe88644SFelix Fietkau goto out;
269f0efa862SFelix Fietkau }
270f0efa862SFelix Fietkau #endif
271f0efa862SFelix Fietkau
272bd1e3e7bSLorenzo Bianconi if (cb->pktid < MT_PACKET_ID_FIRST) {
273e890c3cfSPeter Chiu struct ieee80211_rate_status rs = {};
274e890c3cfSPeter Chiu
275e394b575SFelix Fietkau hw = mt76_tx_status_get_hw(dev, skb);
2760fe88644SFelix Fietkau status.sta = wcid_to_sta(wcid);
277e890c3cfSPeter Chiu if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
278e890c3cfSPeter Chiu rs.rate_idx = wcid->rate;
279e890c3cfSPeter Chiu status.rates = &rs;
280e890c3cfSPeter Chiu status.n_rates = 1;
281e890c3cfSPeter Chiu }
2825b8ccdfbSFelix Fietkau spin_lock_bh(&dev->rx_lock);
2830fe88644SFelix Fietkau ieee80211_tx_status_ext(hw, &status);
2845b8ccdfbSFelix Fietkau spin_unlock_bh(&dev->rx_lock);
2850fe88644SFelix Fietkau goto out;
28688046b2cSFelix Fietkau }
28788046b2cSFelix Fietkau
28879d1c94cSFelix Fietkau mt76_tx_status_lock(dev, &list);
289c4a784e3SLorenzo Bianconi cb->jiffies = jiffies;
29079d1c94cSFelix Fietkau __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list);
29179d1c94cSFelix Fietkau mt76_tx_status_unlock(dev, &list);
2920fe88644SFelix Fietkau
2930fe88644SFelix Fietkau out:
2940fe88644SFelix Fietkau rcu_read_unlock();
29588046b2cSFelix Fietkau }
2960fe88644SFelix Fietkau EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb);
29788046b2cSFelix Fietkau
298e1378e52SFelix Fietkau 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)29989870594SLorenzo Bianconi __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
300e1378e52SFelix Fietkau struct mt76_wcid *wcid, struct ieee80211_sta *sta,
301e1378e52SFelix Fietkau bool *stop)
302e1378e52SFelix Fietkau {
303e1378e52SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
30491990519SLorenzo Bianconi struct mt76_queue *q = phy->q_tx[qid];
30589870594SLorenzo Bianconi struct mt76_dev *dev = phy->dev;
306e1378e52SFelix Fietkau bool non_aql;
307e1378e52SFelix Fietkau int pending;
308e1378e52SFelix Fietkau int idx;
309e1378e52SFelix Fietkau
310e1378e52SFelix Fietkau non_aql = !info->tx_time_est;
311d08295f5SFelix Fietkau idx = dev->queue_ops->tx_queue_skb(dev, q, qid, skb, wcid, sta);
3120fe88644SFelix Fietkau if (idx < 0 || !sta)
313e1378e52SFelix Fietkau return idx;
314e1378e52SFelix Fietkau
315e1378e52SFelix Fietkau wcid = (struct mt76_wcid *)sta->drv_priv;
316e1378e52SFelix Fietkau q->entry[idx].wcid = wcid->idx;
3170fe88644SFelix Fietkau
3180fe88644SFelix Fietkau if (!non_aql)
3190fe88644SFelix Fietkau return idx;
3200fe88644SFelix Fietkau
321e1378e52SFelix Fietkau pending = atomic_inc_return(&wcid->non_aql_packets);
322e1378e52SFelix Fietkau if (stop && pending >= MT_MAX_NON_AQL_PKT)
323e1378e52SFelix Fietkau *stop = true;
324e1378e52SFelix Fietkau
325e1378e52SFelix Fietkau return idx;
326e1378e52SFelix Fietkau }
327e1378e52SFelix Fietkau
32817f1de56SFelix Fietkau void
mt76_tx(struct mt76_phy * phy,struct ieee80211_sta * sta,struct mt76_wcid * wcid,struct sk_buff * skb)3299fba6d07SFelix Fietkau mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
33017f1de56SFelix Fietkau struct mt76_wcid *wcid, struct sk_buff *skb)
33117f1de56SFelix Fietkau {
33217f1de56SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
33317f1de56SFelix Fietkau
334c918c74dSShayne Chen if (mt76_testmode_enabled(phy)) {
335f0efa862SFelix Fietkau ieee80211_free_txskb(phy->hw, skb);
336f0efa862SFelix Fietkau return;
337f0efa862SFelix Fietkau }
338f0efa862SFelix Fietkau
339*d2defcddSFelix Fietkau if (WARN_ON(skb_get_queue_mapping(skb) >= MT_TXQ_PSD))
340*d2defcddSFelix Fietkau skb_set_queue_mapping(skb, MT_TXQ_BE);
341d3c82998SLorenzo Bianconi
342d7400a2fSLorenzo Bianconi if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET))
34317f1de56SFelix Fietkau ieee80211_get_tx_rates(info->control.vif, sta, skb,
34417f1de56SFelix Fietkau info->control.rates, 1);
34517f1de56SFelix Fietkau
346a062f001SLorenzo Bianconi info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);
34717f1de56SFelix Fietkau
348*d2defcddSFelix Fietkau spin_lock_bh(&wcid->tx_pending.lock);
349*d2defcddSFelix Fietkau __skb_queue_tail(&wcid->tx_pending, skb);
350*d2defcddSFelix Fietkau spin_unlock_bh(&wcid->tx_pending.lock);
351*d2defcddSFelix Fietkau
352*d2defcddSFelix Fietkau spin_lock_bh(&phy->tx_lock);
353*d2defcddSFelix Fietkau if (list_empty(&wcid->tx_list))
354*d2defcddSFelix Fietkau list_add_tail(&wcid->tx_list, &phy->tx_list);
355*d2defcddSFelix Fietkau spin_unlock_bh(&phy->tx_lock);
356*d2defcddSFelix Fietkau
357*d2defcddSFelix Fietkau mt76_worker_schedule(&phy->dev->tx_worker);
35817f1de56SFelix Fietkau }
35917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_tx);
36017f1de56SFelix Fietkau
36117f1de56SFelix Fietkau static struct sk_buff *
mt76_txq_dequeue(struct mt76_phy * phy,struct mt76_txq * mtxq)3622bffddedSFelix Fietkau mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
36317f1de56SFelix Fietkau {
36417f1de56SFelix Fietkau struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
365e394b575SFelix Fietkau struct ieee80211_tx_info *info;
36617f1de56SFelix Fietkau struct sk_buff *skb;
36717f1de56SFelix Fietkau
3689fba6d07SFelix Fietkau skb = ieee80211_tx_dequeue(phy->hw, txq);
36917f1de56SFelix Fietkau if (!skb)
37017f1de56SFelix Fietkau return NULL;
37117f1de56SFelix Fietkau
372e394b575SFelix Fietkau info = IEEE80211_SKB_CB(skb);
373a062f001SLorenzo Bianconi info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);
374e394b575SFelix Fietkau
37517f1de56SFelix Fietkau return skb;
37617f1de56SFelix Fietkau }
37717f1de56SFelix Fietkau
37817f1de56SFelix Fietkau static void
mt76_queue_ps_skb(struct mt76_phy * phy,struct ieee80211_sta * sta,struct sk_buff * skb,bool last)37989870594SLorenzo Bianconi mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta,
38017f1de56SFelix Fietkau struct sk_buff *skb, bool last)
38117f1de56SFelix Fietkau {
38217f1de56SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
38317f1de56SFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
38417f1de56SFelix Fietkau
38517f1de56SFelix Fietkau info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
38617f1de56SFelix Fietkau if (last)
3877267a796SFelix Fietkau info->flags |= IEEE80211_TX_STATUS_EOSP |
3887267a796SFelix Fietkau IEEE80211_TX_CTL_REQ_TX_STATUS;
38917f1de56SFelix Fietkau
39017f1de56SFelix Fietkau mt76_skb_set_moredata(skb, !last);
39189870594SLorenzo Bianconi __mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL);
39217f1de56SFelix Fietkau }
39317f1de56SFelix Fietkau
39417f1de56SFelix Fietkau 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)39517f1de56SFelix Fietkau mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
39617f1de56SFelix Fietkau u16 tids, int nframes,
39717f1de56SFelix Fietkau enum ieee80211_frame_release_type reason,
39817f1de56SFelix Fietkau bool more_data)
39917f1de56SFelix Fietkau {
4009fba6d07SFelix Fietkau struct mt76_phy *phy = hw->priv;
4019fba6d07SFelix Fietkau struct mt76_dev *dev = phy->dev;
40217f1de56SFelix Fietkau struct sk_buff *last_skb = NULL;
40391990519SLorenzo Bianconi struct mt76_queue *hwq = phy->q_tx[MT_TXQ_PSD];
40417f1de56SFelix Fietkau int i;
40517f1de56SFelix Fietkau
40617f1de56SFelix Fietkau spin_lock_bh(&hwq->lock);
40717f1de56SFelix Fietkau for (i = 0; tids && nframes; i++, tids >>= 1) {
40817f1de56SFelix Fietkau struct ieee80211_txq *txq = sta->txq[i];
40917f1de56SFelix Fietkau struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
41017f1de56SFelix Fietkau struct sk_buff *skb;
41117f1de56SFelix Fietkau
41217f1de56SFelix Fietkau if (!(tids & 1))
41317f1de56SFelix Fietkau continue;
41417f1de56SFelix Fietkau
41517f1de56SFelix Fietkau do {
4162bffddedSFelix Fietkau skb = mt76_txq_dequeue(phy, mtxq);
41717f1de56SFelix Fietkau if (!skb)
41817f1de56SFelix Fietkau break;
41917f1de56SFelix Fietkau
42017f1de56SFelix Fietkau nframes--;
42117f1de56SFelix Fietkau if (last_skb)
42289870594SLorenzo Bianconi mt76_queue_ps_skb(phy, sta, last_skb, false);
42317f1de56SFelix Fietkau
42417f1de56SFelix Fietkau last_skb = skb;
42517f1de56SFelix Fietkau } while (nframes);
42617f1de56SFelix Fietkau }
42717f1de56SFelix Fietkau
42817f1de56SFelix Fietkau if (last_skb) {
42989870594SLorenzo Bianconi mt76_queue_ps_skb(phy, sta, last_skb, true);
43017f1de56SFelix Fietkau dev->queue_ops->kick(dev, hwq);
431ffc9a7ffSFelix Fietkau } else {
432ffc9a7ffSFelix Fietkau ieee80211_sta_eosp(sta);
43317f1de56SFelix Fietkau }
434ffc9a7ffSFelix Fietkau
43517f1de56SFelix Fietkau spin_unlock_bh(&hwq->lock);
43617f1de56SFelix Fietkau }
43717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
43817f1de56SFelix Fietkau
43990d494c9SFelix Fietkau static bool
mt76_txq_stopped(struct mt76_queue * q)44090d494c9SFelix Fietkau mt76_txq_stopped(struct mt76_queue *q)
44190d494c9SFelix Fietkau {
44290d494c9SFelix Fietkau return q->stopped || q->blocked ||
44390d494c9SFelix Fietkau q->queued + MT_TXQ_FREE_THR >= q->ndesc;
44490d494c9SFelix Fietkau }
44590d494c9SFelix Fietkau
44617f1de56SFelix Fietkau static int
mt76_txq_send_burst(struct mt76_phy * phy,struct mt76_queue * q,struct mt76_txq * mtxq,struct mt76_wcid * wcid)447f099c2e5SFelix Fietkau mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
44851fb1278SFelix Fietkau struct mt76_txq *mtxq, struct mt76_wcid *wcid)
44917f1de56SFelix Fietkau {
4509fba6d07SFelix Fietkau struct mt76_dev *dev = phy->dev;
45117f1de56SFelix Fietkau struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
45289a37842SLorenzo Bianconi enum mt76_txq_id qid = mt76_txq_get_qid(txq);
453af005f26SLorenzo Bianconi struct ieee80211_tx_info *info;
45417f1de56SFelix Fietkau struct sk_buff *skb;
455e1378e52SFelix Fietkau int n_frames = 1;
456e1378e52SFelix Fietkau bool stop = false;
45717f1de56SFelix Fietkau int idx;
45817f1de56SFelix Fietkau
459a6701111SLorenzo Bianconi if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
460d225581dSFelix Fietkau return 0;
461d225581dSFelix Fietkau
462e1378e52SFelix Fietkau if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
463e1378e52SFelix Fietkau return 0;
464e1378e52SFelix Fietkau
4652bffddedSFelix Fietkau skb = mt76_txq_dequeue(phy, mtxq);
466a6701111SLorenzo Bianconi if (!skb)
46717f1de56SFelix Fietkau return 0;
46817f1de56SFelix Fietkau
46917f1de56SFelix Fietkau info = IEEE80211_SKB_CB(skb);
470db9f11d3SFelix Fietkau if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
47117f1de56SFelix Fietkau ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
47217f1de56SFelix Fietkau info->control.rates, 1);
47317f1de56SFelix Fietkau
4749912a463SFelix Fietkau spin_lock(&q->lock);
47589870594SLorenzo Bianconi idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
4769912a463SFelix Fietkau spin_unlock(&q->lock);
47717f1de56SFelix Fietkau if (idx < 0)
47817f1de56SFelix Fietkau return idx;
47917f1de56SFelix Fietkau
48017f1de56SFelix Fietkau do {
48137a86488SLorenzo Bianconi if (test_bit(MT76_RESET, &phy->state))
48217f1de56SFelix Fietkau return -EBUSY;
48317f1de56SFelix Fietkau
48490d494c9SFelix Fietkau if (stop || mt76_txq_stopped(q))
485e1378e52SFelix Fietkau break;
486e1378e52SFelix Fietkau
4872bffddedSFelix Fietkau skb = mt76_txq_dequeue(phy, mtxq);
488a6701111SLorenzo Bianconi if (!skb)
48917f1de56SFelix Fietkau break;
49017f1de56SFelix Fietkau
49117f1de56SFelix Fietkau info = IEEE80211_SKB_CB(skb);
492e1378e52SFelix Fietkau if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
493e1378e52SFelix Fietkau ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
494e1378e52SFelix Fietkau info->control.rates, 1);
49517f1de56SFelix Fietkau
4969912a463SFelix Fietkau spin_lock(&q->lock);
49789870594SLorenzo Bianconi idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
4989912a463SFelix Fietkau spin_unlock(&q->lock);
49917f1de56SFelix Fietkau if (idx < 0)
500e1378e52SFelix Fietkau break;
50117f1de56SFelix Fietkau
50217f1de56SFelix Fietkau n_frames++;
503e1378e52SFelix Fietkau } while (1);
50417f1de56SFelix Fietkau
5059912a463SFelix Fietkau spin_lock(&q->lock);
506f099c2e5SFelix Fietkau dev->queue_ops->kick(dev, q);
5079912a463SFelix Fietkau spin_unlock(&q->lock);
50817f1de56SFelix Fietkau
50917f1de56SFelix Fietkau return n_frames;
51017f1de56SFelix Fietkau }
51117f1de56SFelix Fietkau
51217f1de56SFelix Fietkau static int
mt76_txq_schedule_list(struct mt76_phy * phy,enum mt76_txq_id qid)5139fba6d07SFelix Fietkau mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
51417f1de56SFelix Fietkau {
51591990519SLorenzo Bianconi struct mt76_queue *q = phy->q_tx[qid];
5169716ef04SFelix Fietkau struct mt76_dev *dev = phy->dev;
51790fdc171SFelix Fietkau struct ieee80211_txq *txq;
51890fdc171SFelix Fietkau struct mt76_txq *mtxq;
51990fdc171SFelix Fietkau struct mt76_wcid *wcid;
52090fdc171SFelix Fietkau int ret = 0;
52117f1de56SFelix Fietkau
52290fdc171SFelix Fietkau while (1) {
52357b8b575SLorenzo Bianconi int n_frames = 0;
52457b8b575SLorenzo Bianconi
52537a86488SLorenzo Bianconi if (test_bit(MT76_RESET, &phy->state))
52657b8b575SLorenzo Bianconi return -EBUSY;
52795135e8cSFelix Fietkau
5289716ef04SFelix Fietkau if (dev->queue_ops->tx_cleanup &&
5299716ef04SFelix Fietkau q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) {
5309716ef04SFelix Fietkau dev->queue_ops->tx_cleanup(dev, q, false);
5319716ef04SFelix Fietkau }
5329716ef04SFelix Fietkau
5339fba6d07SFelix Fietkau txq = ieee80211_next_txq(phy->hw, qid);
53490fdc171SFelix Fietkau if (!txq)
53590fdc171SFelix Fietkau break;
53690fdc171SFelix Fietkau
53790fdc171SFelix Fietkau mtxq = (struct mt76_txq *)txq->drv_priv;
53851fb1278SFelix Fietkau wcid = rcu_dereference(dev->wcid[mtxq->wcid]);
53951fb1278SFelix Fietkau if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags))
54090fdc171SFelix Fietkau continue;
54190fdc171SFelix Fietkau
54217f1de56SFelix Fietkau if (mtxq->send_bar && mtxq->aggr) {
54317f1de56SFelix Fietkau struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
54417f1de56SFelix Fietkau struct ieee80211_sta *sta = txq->sta;
54517f1de56SFelix Fietkau struct ieee80211_vif *vif = txq->vif;
54617f1de56SFelix Fietkau u16 agg_ssn = mtxq->agg_ssn;
54717f1de56SFelix Fietkau u8 tid = txq->tid;
54817f1de56SFelix Fietkau
54917f1de56SFelix Fietkau mtxq->send_bar = false;
55017f1de56SFelix Fietkau ieee80211_send_bar(vif, sta->addr, tid, agg_ssn);
55117f1de56SFelix Fietkau }
55217f1de56SFelix Fietkau
5532fbcdb43SFelix Fietkau if (!mt76_txq_stopped(q))
55451fb1278SFelix Fietkau n_frames = mt76_txq_send_burst(phy, q, mtxq, wcid);
5552fbcdb43SFelix Fietkau
5562bffddedSFelix Fietkau ieee80211_return_txq(phy->hw, txq, false);
55757b8b575SLorenzo Bianconi
55857b8b575SLorenzo Bianconi if (unlikely(n_frames < 0))
55957b8b575SLorenzo Bianconi return n_frames;
56057b8b575SLorenzo Bianconi
56157b8b575SLorenzo Bianconi ret += n_frames;
56290fdc171SFelix Fietkau }
56317f1de56SFelix Fietkau
56490fdc171SFelix Fietkau return ret;
56517f1de56SFelix Fietkau }
56617f1de56SFelix Fietkau
mt76_txq_schedule(struct mt76_phy * phy,enum mt76_txq_id qid)5679fba6d07SFelix Fietkau void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
56817f1de56SFelix Fietkau {
56917f1de56SFelix Fietkau int len;
57017f1de56SFelix Fietkau
57190fdc171SFelix Fietkau if (qid >= 4)
57290fdc171SFelix Fietkau return;
57317f1de56SFelix Fietkau
5749912a463SFelix Fietkau local_bh_disable();
57590fdc171SFelix Fietkau rcu_read_lock();
57690fdc171SFelix Fietkau
57790fdc171SFelix Fietkau do {
5789fba6d07SFelix Fietkau ieee80211_txq_schedule_start(phy->hw, qid);
5799fba6d07SFelix Fietkau len = mt76_txq_schedule_list(phy, qid);
5809fba6d07SFelix Fietkau ieee80211_txq_schedule_end(phy->hw, qid);
58117f1de56SFelix Fietkau } while (len > 0);
58290fdc171SFelix Fietkau
5831d868b70SFelix Fietkau rcu_read_unlock();
5849912a463SFelix Fietkau local_bh_enable();
58517f1de56SFelix Fietkau }
58617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_txq_schedule);
58717f1de56SFelix Fietkau
588*d2defcddSFelix Fietkau static int
mt76_txq_schedule_pending_wcid(struct mt76_phy * phy,struct mt76_wcid * wcid)589*d2defcddSFelix Fietkau mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid)
590*d2defcddSFelix Fietkau {
591*d2defcddSFelix Fietkau struct mt76_dev *dev = phy->dev;
592*d2defcddSFelix Fietkau struct ieee80211_sta *sta;
593*d2defcddSFelix Fietkau struct mt76_queue *q;
594*d2defcddSFelix Fietkau struct sk_buff *skb;
595*d2defcddSFelix Fietkau int ret = 0;
596*d2defcddSFelix Fietkau
597*d2defcddSFelix Fietkau spin_lock(&wcid->tx_pending.lock);
598*d2defcddSFelix Fietkau while ((skb = skb_peek(&wcid->tx_pending)) != NULL) {
599*d2defcddSFelix Fietkau struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
600*d2defcddSFelix Fietkau struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
601*d2defcddSFelix Fietkau int qid = skb_get_queue_mapping(skb);
602*d2defcddSFelix Fietkau
603*d2defcddSFelix Fietkau if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
604*d2defcddSFelix Fietkau !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
605*d2defcddSFelix Fietkau !ieee80211_is_data(hdr->frame_control) &&
606*d2defcddSFelix Fietkau !ieee80211_is_bufferable_mmpdu(skb))
607*d2defcddSFelix Fietkau qid = MT_TXQ_PSD;
608*d2defcddSFelix Fietkau
609*d2defcddSFelix Fietkau q = phy->q_tx[qid];
610*d2defcddSFelix Fietkau if (mt76_txq_stopped(q)) {
611*d2defcddSFelix Fietkau ret = -1;
612*d2defcddSFelix Fietkau break;
613*d2defcddSFelix Fietkau }
614*d2defcddSFelix Fietkau
615*d2defcddSFelix Fietkau __skb_unlink(skb, &wcid->tx_pending);
616*d2defcddSFelix Fietkau spin_unlock(&wcid->tx_pending.lock);
617*d2defcddSFelix Fietkau
618*d2defcddSFelix Fietkau sta = wcid_to_sta(wcid);
619*d2defcddSFelix Fietkau spin_lock(&q->lock);
620*d2defcddSFelix Fietkau __mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL);
621*d2defcddSFelix Fietkau dev->queue_ops->kick(dev, q);
622*d2defcddSFelix Fietkau spin_unlock(&q->lock);
623*d2defcddSFelix Fietkau
624*d2defcddSFelix Fietkau spin_lock(&wcid->tx_pending.lock);
625*d2defcddSFelix Fietkau }
626*d2defcddSFelix Fietkau spin_unlock(&wcid->tx_pending.lock);
627*d2defcddSFelix Fietkau
628*d2defcddSFelix Fietkau return ret;
629*d2defcddSFelix Fietkau }
630*d2defcddSFelix Fietkau
mt76_txq_schedule_pending(struct mt76_phy * phy)631*d2defcddSFelix Fietkau static void mt76_txq_schedule_pending(struct mt76_phy *phy)
632*d2defcddSFelix Fietkau {
633*d2defcddSFelix Fietkau if (list_empty(&phy->tx_list))
634*d2defcddSFelix Fietkau return;
635*d2defcddSFelix Fietkau
636*d2defcddSFelix Fietkau local_bh_disable();
637*d2defcddSFelix Fietkau rcu_read_lock();
638*d2defcddSFelix Fietkau
639*d2defcddSFelix Fietkau spin_lock(&phy->tx_lock);
640*d2defcddSFelix Fietkau while (!list_empty(&phy->tx_list)) {
641*d2defcddSFelix Fietkau struct mt76_wcid *wcid = NULL;
642*d2defcddSFelix Fietkau int ret;
643*d2defcddSFelix Fietkau
644*d2defcddSFelix Fietkau wcid = list_first_entry(&phy->tx_list, struct mt76_wcid, tx_list);
645*d2defcddSFelix Fietkau list_del_init(&wcid->tx_list);
646*d2defcddSFelix Fietkau
647*d2defcddSFelix Fietkau spin_unlock(&phy->tx_lock);
648*d2defcddSFelix Fietkau ret = mt76_txq_schedule_pending_wcid(phy, wcid);
649*d2defcddSFelix Fietkau spin_lock(&phy->tx_lock);
650*d2defcddSFelix Fietkau
651*d2defcddSFelix Fietkau if (ret) {
652*d2defcddSFelix Fietkau if (list_empty(&wcid->tx_list))
653*d2defcddSFelix Fietkau list_add_tail(&wcid->tx_list, &phy->tx_list);
654*d2defcddSFelix Fietkau break;
655*d2defcddSFelix Fietkau }
656*d2defcddSFelix Fietkau }
657*d2defcddSFelix Fietkau spin_unlock(&phy->tx_lock);
658*d2defcddSFelix Fietkau
659*d2defcddSFelix Fietkau rcu_read_unlock();
660*d2defcddSFelix Fietkau local_bh_enable();
661*d2defcddSFelix Fietkau }
662*d2defcddSFelix Fietkau
mt76_txq_schedule_all(struct mt76_phy * phy)6639fba6d07SFelix Fietkau void mt76_txq_schedule_all(struct mt76_phy *phy)
66417f1de56SFelix Fietkau {
66517f1de56SFelix Fietkau int i;
66617f1de56SFelix Fietkau
667*d2defcddSFelix Fietkau mt76_txq_schedule_pending(phy);
66890fdc171SFelix Fietkau for (i = 0; i <= MT_TXQ_BK; i++)
6699fba6d07SFelix Fietkau mt76_txq_schedule(phy, i);
67017f1de56SFelix Fietkau }
67117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
67217f1de56SFelix Fietkau
mt76_tx_worker_run(struct mt76_dev * dev)673335e97acSLorenzo Bianconi void mt76_tx_worker_run(struct mt76_dev *dev)
674c325c9c7SLorenzo Bianconi {
675dc44c45cSLorenzo Bianconi struct mt76_phy *phy;
676dc44c45cSLorenzo Bianconi int i;
677dc44c45cSLorenzo Bianconi
678dc44c45cSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
679dc44c45cSLorenzo Bianconi phy = dev->phys[i];
680dc44c45cSLorenzo Bianconi if (!phy)
681dc44c45cSLorenzo Bianconi continue;
682dc44c45cSLorenzo Bianconi
683dc44c45cSLorenzo Bianconi mt76_txq_schedule_all(phy);
684dc44c45cSLorenzo Bianconi }
685f0efa862SFelix Fietkau
686f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
687dc44c45cSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
688dc44c45cSLorenzo Bianconi phy = dev->phys[i];
689dc44c45cSLorenzo Bianconi if (!phy || !phy->test.tx_pending)
690dc44c45cSLorenzo Bianconi continue;
691dc44c45cSLorenzo Bianconi
692dc44c45cSLorenzo Bianconi mt76_testmode_tx_pending(phy);
693dc44c45cSLorenzo Bianconi }
694f0efa862SFelix Fietkau #endif
695c325c9c7SLorenzo Bianconi }
696335e97acSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_tx_worker_run);
697335e97acSLorenzo Bianconi
mt76_tx_worker(struct mt76_worker * w)698335e97acSLorenzo Bianconi void mt76_tx_worker(struct mt76_worker *w)
699335e97acSLorenzo Bianconi {
700335e97acSLorenzo Bianconi struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
701335e97acSLorenzo Bianconi
702335e97acSLorenzo Bianconi mt76_tx_worker_run(dev);
703335e97acSLorenzo Bianconi }
704c325c9c7SLorenzo Bianconi
mt76_stop_tx_queues(struct mt76_phy * phy,struct ieee80211_sta * sta,bool send_bar)70591990519SLorenzo Bianconi void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
70617f1de56SFelix Fietkau bool send_bar)
70717f1de56SFelix Fietkau {
70817f1de56SFelix Fietkau int i;
70917f1de56SFelix Fietkau
71017f1de56SFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
71117f1de56SFelix Fietkau struct ieee80211_txq *txq = sta->txq[i];
712af005f26SLorenzo Bianconi struct mt76_queue *hwq;
7137c250f46SLorenzo Bianconi struct mt76_txq *mtxq;
7147c250f46SLorenzo Bianconi
7157c250f46SLorenzo Bianconi if (!txq)
7167c250f46SLorenzo Bianconi continue;
7177c250f46SLorenzo Bianconi
71891990519SLorenzo Bianconi hwq = phy->q_tx[mt76_txq_get_qid(txq)];
7197c250f46SLorenzo Bianconi mtxq = (struct mt76_txq *)txq->drv_priv;
72017f1de56SFelix Fietkau
721af005f26SLorenzo Bianconi spin_lock_bh(&hwq->lock);
72217f1de56SFelix Fietkau mtxq->send_bar = mtxq->aggr && send_bar;
723af005f26SLorenzo Bianconi spin_unlock_bh(&hwq->lock);
72417f1de56SFelix Fietkau }
72517f1de56SFelix Fietkau }
72617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_stop_tx_queues);
72717f1de56SFelix Fietkau
mt76_wake_tx_queue(struct ieee80211_hw * hw,struct ieee80211_txq * txq)72817f1de56SFelix Fietkau void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
72917f1de56SFelix Fietkau {
7309fba6d07SFelix Fietkau struct mt76_phy *phy = hw->priv;
7319fba6d07SFelix Fietkau struct mt76_dev *dev = phy->dev;
73217f1de56SFelix Fietkau
733011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state))
73400496042SFelix Fietkau return;
73500496042SFelix Fietkau
736781eef5bSFelix Fietkau mt76_worker_schedule(&dev->tx_worker);
73717f1de56SFelix Fietkau }
73817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
73917f1de56SFelix Fietkau
mt76_ac_to_hwq(u8 ac)7401d0496c6SStanislaw Gruszka u8 mt76_ac_to_hwq(u8 ac)
7411d0496c6SStanislaw Gruszka {
7421d0496c6SStanislaw Gruszka static const u8 wmm_queue_map[] = {
7431d0496c6SStanislaw Gruszka [IEEE80211_AC_BE] = 0,
7441d0496c6SStanislaw Gruszka [IEEE80211_AC_BK] = 1,
7451d0496c6SStanislaw Gruszka [IEEE80211_AC_VI] = 2,
7461d0496c6SStanislaw Gruszka [IEEE80211_AC_VO] = 3,
7471d0496c6SStanislaw Gruszka };
7481d0496c6SStanislaw Gruszka
7491d0496c6SStanislaw Gruszka if (WARN_ON(ac >= IEEE80211_NUM_ACS))
7501d0496c6SStanislaw Gruszka return 0;
7511d0496c6SStanislaw Gruszka
7521d0496c6SStanislaw Gruszka return wmm_queue_map[ac];
7531d0496c6SStanislaw Gruszka }
7541d0496c6SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
75575b10f0cSLorenzo Bianconi
mt76_skb_adjust_pad(struct sk_buff * skb,int pad)756e98e6df6SLorenzo Bianconi int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
75775b10f0cSLorenzo Bianconi {
75875b10f0cSLorenzo Bianconi struct sk_buff *iter, *last = skb;
75975b10f0cSLorenzo Bianconi
76075b10f0cSLorenzo Bianconi /* First packet of a A-MSDU burst keeps track of the whole burst
76175b10f0cSLorenzo Bianconi * length, need to update length of it and the last packet.
76275b10f0cSLorenzo Bianconi */
76375b10f0cSLorenzo Bianconi skb_walk_frags(skb, iter) {
76475b10f0cSLorenzo Bianconi last = iter;
76575b10f0cSLorenzo Bianconi if (!iter->next) {
76675b10f0cSLorenzo Bianconi skb->data_len += pad;
76775b10f0cSLorenzo Bianconi skb->len += pad;
76875b10f0cSLorenzo Bianconi break;
76975b10f0cSLorenzo Bianconi }
77075b10f0cSLorenzo Bianconi }
77175b10f0cSLorenzo Bianconi
77275b10f0cSLorenzo Bianconi if (skb_pad(last, pad))
77375b10f0cSLorenzo Bianconi return -ENOMEM;
77475b10f0cSLorenzo Bianconi
77575b10f0cSLorenzo Bianconi __skb_put(last, pad);
77675b10f0cSLorenzo Bianconi
77775b10f0cSLorenzo Bianconi return 0;
77875b10f0cSLorenzo Bianconi }
77975b10f0cSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad);
780fe5b5ab5SFelix Fietkau
mt76_queue_tx_complete(struct mt76_dev * dev,struct mt76_queue * q,struct mt76_queue_entry * e)781fe5b5ab5SFelix Fietkau void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
782fe5b5ab5SFelix Fietkau struct mt76_queue_entry *e)
783fe5b5ab5SFelix Fietkau {
784fe5b5ab5SFelix Fietkau if (e->skb)
785d80e52c7SFelix Fietkau dev->drv->tx_complete_skb(dev, e);
786fe5b5ab5SFelix Fietkau
787fe5b5ab5SFelix Fietkau spin_lock_bh(&q->lock);
788fe5b5ab5SFelix Fietkau q->tail = (q->tail + 1) % q->ndesc;
789fe5b5ab5SFelix Fietkau q->queued--;
790fe5b5ab5SFelix Fietkau spin_unlock_bh(&q->lock);
791fe5b5ab5SFelix Fietkau }
792fe5b5ab5SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
793d089692bSLorenzo Bianconi
__mt76_set_tx_blocked(struct mt76_dev * dev,bool blocked)794d089692bSLorenzo Bianconi void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
795d089692bSLorenzo Bianconi {
796dc44c45cSLorenzo Bianconi struct mt76_phy *phy = &dev->phy;
797dc44c45cSLorenzo Bianconi struct mt76_queue *q = phy->q_tx[0];
798d089692bSLorenzo Bianconi
799d089692bSLorenzo Bianconi if (blocked == q->blocked)
800d089692bSLorenzo Bianconi return;
801d089692bSLorenzo Bianconi
802d089692bSLorenzo Bianconi q->blocked = blocked;
803dc44c45cSLorenzo Bianconi
804dc44c45cSLorenzo Bianconi phy = dev->phys[MT_BAND1];
805dc44c45cSLorenzo Bianconi if (phy) {
806dc44c45cSLorenzo Bianconi q = phy->q_tx[0];
807dc44c45cSLorenzo Bianconi q->blocked = blocked;
808dc44c45cSLorenzo Bianconi }
809dc44c45cSLorenzo Bianconi phy = dev->phys[MT_BAND2];
810dc44c45cSLorenzo Bianconi if (phy) {
811dc44c45cSLorenzo Bianconi q = phy->q_tx[0];
812dc44c45cSLorenzo Bianconi q->blocked = blocked;
813d089692bSLorenzo Bianconi }
814d089692bSLorenzo Bianconi
815d089692bSLorenzo Bianconi if (!blocked)
816d089692bSLorenzo Bianconi mt76_worker_schedule(&dev->tx_worker);
817d089692bSLorenzo Bianconi }
818d089692bSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_set_tx_blocked);
819d089692bSLorenzo Bianconi
mt76_token_consume(struct mt76_dev * dev,struct mt76_txwi_cache ** ptxwi)820d089692bSLorenzo Bianconi int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
821d089692bSLorenzo Bianconi {
822d089692bSLorenzo Bianconi int token;
823d089692bSLorenzo Bianconi
824d089692bSLorenzo Bianconi spin_lock_bh(&dev->token_lock);
825d089692bSLorenzo Bianconi
82661b5156bSFelix Fietkau token = idr_alloc(&dev->token, *ptxwi, 0, dev->token_size, GFP_ATOMIC);
827d089692bSLorenzo Bianconi if (token >= 0)
828d089692bSLorenzo Bianconi dev->token_count++;
829d089692bSLorenzo Bianconi
830f68d6762SFelix Fietkau #ifdef CONFIG_NET_MEDIATEK_SOC_WED
831f68d6762SFelix Fietkau if (mtk_wed_device_active(&dev->mmio.wed) &&
832f68d6762SFelix Fietkau token >= dev->mmio.wed.wlan.token_start)
833f68d6762SFelix Fietkau dev->wed_token_count++;
834f68d6762SFelix Fietkau #endif
835f68d6762SFelix Fietkau
83661b5156bSFelix Fietkau if (dev->token_count >= dev->token_size - MT76_TOKEN_FREE_THR)
837d089692bSLorenzo Bianconi __mt76_set_tx_blocked(dev, true);
838d089692bSLorenzo Bianconi
839d089692bSLorenzo Bianconi spin_unlock_bh(&dev->token_lock);
840d089692bSLorenzo Bianconi
841d089692bSLorenzo Bianconi return token;
842d089692bSLorenzo Bianconi }
843d089692bSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_token_consume);
844d089692bSLorenzo Bianconi
mt76_rx_token_consume(struct mt76_dev * dev,void * ptr,struct mt76_txwi_cache * t,dma_addr_t phys)8452666beceSSujuan Chen int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
8462666beceSSujuan Chen struct mt76_txwi_cache *t, dma_addr_t phys)
8472666beceSSujuan Chen {
8482666beceSSujuan Chen int token;
8492666beceSSujuan Chen
8502666beceSSujuan Chen spin_lock_bh(&dev->rx_token_lock);
8512666beceSSujuan Chen token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size,
8522666beceSSujuan Chen GFP_ATOMIC);
853e5c3ac89SLorenzo Bianconi if (token >= 0) {
8542666beceSSujuan Chen t->ptr = ptr;
8552666beceSSujuan Chen t->dma_addr = phys;
856e5c3ac89SLorenzo Bianconi }
857e5c3ac89SLorenzo Bianconi spin_unlock_bh(&dev->rx_token_lock);
8582666beceSSujuan Chen
8592666beceSSujuan Chen return token;
8602666beceSSujuan Chen }
8612666beceSSujuan Chen EXPORT_SYMBOL_GPL(mt76_rx_token_consume);
8622666beceSSujuan Chen
863d089692bSLorenzo Bianconi struct mt76_txwi_cache *
mt76_token_release(struct mt76_dev * dev,int token,bool * wake)864d089692bSLorenzo Bianconi mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
865d089692bSLorenzo Bianconi {
866d089692bSLorenzo Bianconi struct mt76_txwi_cache *txwi;
867d089692bSLorenzo Bianconi
868d089692bSLorenzo Bianconi spin_lock_bh(&dev->token_lock);
869d089692bSLorenzo Bianconi
870d089692bSLorenzo Bianconi txwi = idr_remove(&dev->token, token);
871f68d6762SFelix Fietkau if (txwi) {
872d089692bSLorenzo Bianconi dev->token_count--;
873d089692bSLorenzo Bianconi
874f68d6762SFelix Fietkau #ifdef CONFIG_NET_MEDIATEK_SOC_WED
875f68d6762SFelix Fietkau if (mtk_wed_device_active(&dev->mmio.wed) &&
876f68d6762SFelix Fietkau token >= dev->mmio.wed.wlan.token_start &&
877f68d6762SFelix Fietkau --dev->wed_token_count == 0)
878f68d6762SFelix Fietkau wake_up(&dev->tx_wait);
879f68d6762SFelix Fietkau #endif
880f68d6762SFelix Fietkau }
881f68d6762SFelix Fietkau
88261b5156bSFelix Fietkau if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR &&
883d089692bSLorenzo Bianconi dev->phy.q_tx[0]->blocked)
884d089692bSLorenzo Bianconi *wake = true;
885d089692bSLorenzo Bianconi
886d089692bSLorenzo Bianconi spin_unlock_bh(&dev->token_lock);
887d089692bSLorenzo Bianconi
888d089692bSLorenzo Bianconi return txwi;
889d089692bSLorenzo Bianconi }
890d089692bSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_token_release);
8912666beceSSujuan Chen
8922666beceSSujuan Chen struct mt76_txwi_cache *
mt76_rx_token_release(struct mt76_dev * dev,int token)8932666beceSSujuan Chen mt76_rx_token_release(struct mt76_dev *dev, int token)
8942666beceSSujuan Chen {
8952666beceSSujuan Chen struct mt76_txwi_cache *t;
8962666beceSSujuan Chen
8972666beceSSujuan Chen spin_lock_bh(&dev->rx_token_lock);
8982666beceSSujuan Chen t = idr_remove(&dev->rx_token, token);
8992666beceSSujuan Chen spin_unlock_bh(&dev->rx_token_lock);
9002666beceSSujuan Chen
9012666beceSSujuan Chen return t;
9022666beceSSujuan Chen }
9032666beceSSujuan Chen EXPORT_SYMBOL_GPL(mt76_rx_token_release);
904