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 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 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 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 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); 80*cbb3ec25SBjoern A. Zeeb spin_lock_bh(&dev->rx_lock); 816c92544dSBjoern A. Zeeb ieee80211_tx_status_ext(hw, &status); 82*cbb3ec25SBjoern 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 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 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 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 { 124*cbb3ec25SBjoern 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 | 138*cbb3ec25SBjoern A. Zeeb IEEE80211_TX_CTL_RATE_CTRL_PROBE))) { 139*cbb3ec25SBjoern A. Zeeb if (mtk_wed_device_active(&dev->mmio.wed) && 140*cbb3ec25SBjoern A. Zeeb ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) || 141*cbb3ec25SBjoern A. Zeeb ieee80211_is_data(hdr->frame_control))) 142*cbb3ec25SBjoern A. Zeeb return MT_PACKET_ID_WED; 143*cbb3ec25SBjoern A. Zeeb 1446c92544dSBjoern A. Zeeb return MT_PACKET_ID_NO_SKB; 145*cbb3ec25SBjoern 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 * 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 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 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 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) { 273*cbb3ec25SBjoern A. Zeeb struct ieee80211_rate_status rs = {}; 274*cbb3ec25SBjoern A. Zeeb 2756c92544dSBjoern A. Zeeb hw = mt76_tx_status_get_hw(dev, skb); 2766c92544dSBjoern A. Zeeb status.sta = wcid_to_sta(wcid); 277*cbb3ec25SBjoern A. Zeeb if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) { 278*cbb3ec25SBjoern A. Zeeb rs.rate_idx = wcid->rate; 279*cbb3ec25SBjoern A. Zeeb status.rates = &rs; 280*cbb3ec25SBjoern A. Zeeb status.n_rates = 1; 281*cbb3ec25SBjoern A. Zeeb } 282*cbb3ec25SBjoern A. Zeeb spin_lock_bh(&dev->rx_lock); 2836c92544dSBjoern A. Zeeb ieee80211_tx_status_ext(hw, &status); 284*cbb3ec25SBjoern 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 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 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) && 351*cbb3ec25SBjoern 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 777*cbb3ec25SBjoern A. Zeeb int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr, 778*cbb3ec25SBjoern A. Zeeb struct mt76_txwi_cache *t, dma_addr_t phys) 779*cbb3ec25SBjoern A. Zeeb { 780*cbb3ec25SBjoern A. Zeeb int token; 781*cbb3ec25SBjoern A. Zeeb 782*cbb3ec25SBjoern A. Zeeb spin_lock_bh(&dev->rx_token_lock); 783*cbb3ec25SBjoern A. Zeeb token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size, 784*cbb3ec25SBjoern A. Zeeb GFP_ATOMIC); 785*cbb3ec25SBjoern A. Zeeb if (token >= 0) { 786*cbb3ec25SBjoern A. Zeeb t->ptr = ptr; 787*cbb3ec25SBjoern A. Zeeb t->dma_addr = phys; 788*cbb3ec25SBjoern A. Zeeb } 789*cbb3ec25SBjoern A. Zeeb spin_unlock_bh(&dev->rx_token_lock); 790*cbb3ec25SBjoern A. Zeeb 791*cbb3ec25SBjoern A. Zeeb return token; 792*cbb3ec25SBjoern A. Zeeb } 793*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_token_consume); 794*cbb3ec25SBjoern A. Zeeb 7956c92544dSBjoern A. Zeeb struct mt76_txwi_cache * 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); 823*cbb3ec25SBjoern A. Zeeb 824*cbb3ec25SBjoern A. Zeeb struct mt76_txwi_cache * 825*cbb3ec25SBjoern A. Zeeb mt76_rx_token_release(struct mt76_dev *dev, int token) 826*cbb3ec25SBjoern A. Zeeb { 827*cbb3ec25SBjoern A. Zeeb struct mt76_txwi_cache *t; 828*cbb3ec25SBjoern A. Zeeb 829*cbb3ec25SBjoern A. Zeeb spin_lock_bh(&dev->rx_token_lock); 830*cbb3ec25SBjoern A. Zeeb t = idr_remove(&dev->rx_token, token); 831*cbb3ec25SBjoern A. Zeeb spin_unlock_bh(&dev->rx_token_lock); 832*cbb3ec25SBjoern A. Zeeb 833*cbb3ec25SBjoern A. Zeeb return t; 834*cbb3ec25SBjoern A. Zeeb } 835*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_token_release); 836