18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 188c2ecf20Sopenharmony_ci#include "ath9k.h" 198c2ecf20Sopenharmony_ci#include "ar9003_mac.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define BITS_PER_BYTE 8 228c2ecf20Sopenharmony_ci#define OFDM_PLCP_BITS 22 238c2ecf20Sopenharmony_ci#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 248c2ecf20Sopenharmony_ci#define L_STF 8 258c2ecf20Sopenharmony_ci#define L_LTF 8 268c2ecf20Sopenharmony_ci#define L_SIG 4 278c2ecf20Sopenharmony_ci#define HT_SIG 8 288c2ecf20Sopenharmony_ci#define HT_STF 4 298c2ecf20Sopenharmony_ci#define HT_LTF(_ns) (4 * (_ns)) 308c2ecf20Sopenharmony_ci#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */ 318c2ecf20Sopenharmony_ci#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */ 328c2ecf20Sopenharmony_ci#define TIME_SYMBOLS(t) ((t) >> 2) 338c2ecf20Sopenharmony_ci#define TIME_SYMBOLS_HALFGI(t) (((t) * 5 - 4) / 18) 348c2ecf20Sopenharmony_ci#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) 358c2ecf20Sopenharmony_ci#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic u16 bits_per_symbol[][2] = { 398c2ecf20Sopenharmony_ci /* 20MHz 40MHz */ 408c2ecf20Sopenharmony_ci { 26, 54 }, /* 0: BPSK */ 418c2ecf20Sopenharmony_ci { 52, 108 }, /* 1: QPSK 1/2 */ 428c2ecf20Sopenharmony_ci { 78, 162 }, /* 2: QPSK 3/4 */ 438c2ecf20Sopenharmony_ci { 104, 216 }, /* 3: 16-QAM 1/2 */ 448c2ecf20Sopenharmony_ci { 156, 324 }, /* 4: 16-QAM 3/4 */ 458c2ecf20Sopenharmony_ci { 208, 432 }, /* 5: 64-QAM 2/3 */ 468c2ecf20Sopenharmony_ci { 234, 486 }, /* 6: 64-QAM 3/4 */ 478c2ecf20Sopenharmony_ci { 260, 540 }, /* 7: 64-QAM 5/6 */ 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, 518c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, struct sk_buff *skb); 528c2ecf20Sopenharmony_cistatic void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, 538c2ecf20Sopenharmony_ci int tx_flags, struct ath_txq *txq, 548c2ecf20Sopenharmony_ci struct ieee80211_sta *sta); 558c2ecf20Sopenharmony_cistatic void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 568c2ecf20Sopenharmony_ci struct ath_txq *txq, struct list_head *bf_q, 578c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 588c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int txok); 598c2ecf20Sopenharmony_cistatic void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, 608c2ecf20Sopenharmony_ci struct list_head *head, bool internal); 618c2ecf20Sopenharmony_cistatic void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, 628c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int nframes, int nbad, 638c2ecf20Sopenharmony_ci int txok); 648c2ecf20Sopenharmony_cistatic void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 658c2ecf20Sopenharmony_ci struct ath_buf *bf); 668c2ecf20Sopenharmony_cistatic struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, 678c2ecf20Sopenharmony_ci struct ath_txq *txq, 688c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, 698c2ecf20Sopenharmony_ci struct sk_buff *skb); 708c2ecf20Sopenharmony_cistatic int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, 718c2ecf20Sopenharmony_ci struct ath_tx_control *txctl); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cienum { 748c2ecf20Sopenharmony_ci MCS_HT20, 758c2ecf20Sopenharmony_ci MCS_HT20_SGI, 768c2ecf20Sopenharmony_ci MCS_HT40, 778c2ecf20Sopenharmony_ci MCS_HT40_SGI, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/*********************/ 818c2ecf20Sopenharmony_ci/* Aggregation logic */ 828c2ecf20Sopenharmony_ci/*********************/ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 878c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = info->status.status_driver_data[0]; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | 908c2ecf20Sopenharmony_ci IEEE80211_TX_STATUS_EOSP)) { 918c2ecf20Sopenharmony_ci ieee80211_tx_status(hw, skb); 928c2ecf20Sopenharmony_ci return; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (sta) 968c2ecf20Sopenharmony_ci ieee80211_tx_status_noskb(hw, sta, info); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) 1028c2ecf20Sopenharmony_ci __releases(&txq->axq_lock) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 1058c2ecf20Sopenharmony_ci struct sk_buff_head q; 1068c2ecf20Sopenharmony_ci struct sk_buff *skb; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci __skb_queue_head_init(&q); 1098c2ecf20Sopenharmony_ci skb_queue_splice_init(&txq->complete_q, &q); 1108c2ecf20Sopenharmony_ci spin_unlock_bh(&txq->axq_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&q))) 1138c2ecf20Sopenharmony_ci ath_tx_status(hw, skb); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct ieee80211_txq *queue = 1198c2ecf20Sopenharmony_ci container_of((void *)tid, struct ieee80211_txq, drv_priv); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ieee80211_schedule_txq(sc->hw, queue); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_civoid ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 1278c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 1288c2ecf20Sopenharmony_ci struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; 1298c2ecf20Sopenharmony_ci struct ath_txq *txq = tid->txq; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", 1328c2ecf20Sopenharmony_ci queue->sta ? queue->sta->addr : queue->vif->addr, 1338c2ecf20Sopenharmony_ci tid->tidno); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 1368c2ecf20Sopenharmony_ci ath_txq_schedule(sc, txq); 1378c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic struct ath_frame_info *get_frame_info(struct sk_buff *skb) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 1438c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ath_frame_info) > 1448c2ecf20Sopenharmony_ci sizeof(tx_info->status.status_driver_data)); 1458c2ecf20Sopenharmony_ci return (struct ath_frame_info *) &tx_info->status.status_driver_data[0]; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (!tid->an->sta) 1518c2ecf20Sopenharmony_ci return; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, 1548c2ecf20Sopenharmony_ci seqno << IEEE80211_SEQ_SEQ_SHIFT); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, 1588c2ecf20Sopenharmony_ci struct ath_buf *bf) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, 1618c2ecf20Sopenharmony_ci ARRAY_SIZE(bf->rates)); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, 1658c2ecf20Sopenharmony_ci struct sk_buff *skb) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 1688c2ecf20Sopenharmony_ci int q = fi->txq; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (q < 0) 1718c2ecf20Sopenharmony_ci return; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci txq = sc->tx.txq_map[q]; 1748c2ecf20Sopenharmony_ci if (WARN_ON(--txq->pending_frames < 0)) 1758c2ecf20Sopenharmony_ci txq->pending_frames = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic struct ath_atx_tid * 1808c2ecf20Sopenharmony_ciath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK; 1838c2ecf20Sopenharmony_ci return ATH_AN_2_TID(an, tidno); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int 1878c2ecf20Sopenharmony_ciath_tid_pull(struct ath_atx_tid *tid, struct sk_buff **skbuf) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv); 1908c2ecf20Sopenharmony_ci struct ath_softc *sc = tid->an->sc; 1918c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 1928c2ecf20Sopenharmony_ci struct ath_tx_control txctl = { 1938c2ecf20Sopenharmony_ci .txq = tid->txq, 1948c2ecf20Sopenharmony_ci .sta = tid->an->sta, 1958c2ecf20Sopenharmony_ci }; 1968c2ecf20Sopenharmony_ci struct sk_buff *skb; 1978c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 1988c2ecf20Sopenharmony_ci int q, ret; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci skb = ieee80211_tx_dequeue(hw, txq); 2018c2ecf20Sopenharmony_ci if (!skb) 2028c2ecf20Sopenharmony_ci return -ENOENT; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ret = ath_tx_prepare(hw, skb, &txctl); 2058c2ecf20Sopenharmony_ci if (ret) { 2068c2ecf20Sopenharmony_ci ieee80211_free_txskb(hw, skb); 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci q = skb_get_queue_mapping(skb); 2118c2ecf20Sopenharmony_ci if (tid->txq == sc->tx.txq_map[q]) { 2128c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 2138c2ecf20Sopenharmony_ci fi->txq = q; 2148c2ecf20Sopenharmony_ci ++tid->txq->pending_frames; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci *skbuf = skb; 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int ath_tid_dequeue(struct ath_atx_tid *tid, 2228c2ecf20Sopenharmony_ci struct sk_buff **skb) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int ret = 0; 2258c2ecf20Sopenharmony_ci *skb = __skb_dequeue(&tid->retry_q); 2268c2ecf20Sopenharmony_ci if (!*skb) 2278c2ecf20Sopenharmony_ci ret = ath_tid_pull(tid, skb); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct ath_txq *txq = tid->txq; 2358c2ecf20Sopenharmony_ci struct sk_buff *skb; 2368c2ecf20Sopenharmony_ci struct ath_buf *bf; 2378c2ecf20Sopenharmony_ci struct list_head bf_head; 2388c2ecf20Sopenharmony_ci struct ath_tx_status ts; 2398c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 2408c2ecf20Sopenharmony_ci bool sendbar = false; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&tid->retry_q))) { 2478c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 2488c2ecf20Sopenharmony_ci bf = fi->bf; 2498c2ecf20Sopenharmony_ci if (!bf) { 2508c2ecf20Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 2518c2ecf20Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 2528c2ecf20Sopenharmony_ci continue; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (fi->baw_tracked) { 2568c2ecf20Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 2578c2ecf20Sopenharmony_ci sendbar = true; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 2618c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (sendbar) { 2658c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 2668c2ecf20Sopenharmony_ci ath_send_bar(tid, tid->seq_start); 2678c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 2728c2ecf20Sopenharmony_ci struct ath_buf *bf) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 2758c2ecf20Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 2768c2ecf20Sopenharmony_ci int index, cindex; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!fi->baw_tracked) 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci index = ATH_BA_INDEX(tid->seq_start, seqno); 2828c2ecf20Sopenharmony_ci cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci __clear_bit(cindex, tid->tx_buf); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) { 2878c2ecf20Sopenharmony_ci INCR(tid->seq_start, IEEE80211_SEQ_MAX); 2888c2ecf20Sopenharmony_ci INCR(tid->baw_head, ATH_TID_MAX_BUFS); 2898c2ecf20Sopenharmony_ci if (tid->bar_index >= 0) 2908c2ecf20Sopenharmony_ci tid->bar_index--; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 2958c2ecf20Sopenharmony_ci struct ath_buf *bf) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 2988c2ecf20Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 2998c2ecf20Sopenharmony_ci int index, cindex; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (fi->baw_tracked) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci index = ATH_BA_INDEX(tid->seq_start, seqno); 3058c2ecf20Sopenharmony_ci cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); 3068c2ecf20Sopenharmony_ci __set_bit(cindex, tid->tx_buf); 3078c2ecf20Sopenharmony_ci fi->baw_tracked = 1; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (index >= ((tid->baw_tail - tid->baw_head) & 3108c2ecf20Sopenharmony_ci (ATH_TID_MAX_BUFS - 1))) { 3118c2ecf20Sopenharmony_ci tid->baw_tail = cindex; 3128c2ecf20Sopenharmony_ci INCR(tid->baw_tail, ATH_TID_MAX_BUFS); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, 3178c2ecf20Sopenharmony_ci struct ath_atx_tid *tid) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct sk_buff *skb; 3218c2ecf20Sopenharmony_ci struct ath_buf *bf; 3228c2ecf20Sopenharmony_ci struct list_head bf_head; 3238c2ecf20Sopenharmony_ci struct ath_tx_status ts; 3248c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 3258c2ecf20Sopenharmony_ci int ret; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 3288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci while ((ret = ath_tid_dequeue(tid, &skb)) == 0) { 3318c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 3328c2ecf20Sopenharmony_ci bf = fi->bf; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!bf) { 3358c2ecf20Sopenharmony_ci ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL); 3368c2ecf20Sopenharmony_ci continue; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 3408c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, 3458c2ecf20Sopenharmony_ci struct sk_buff *skb, int count) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 3488c2ecf20Sopenharmony_ci struct ath_buf *bf = fi->bf; 3498c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 3508c2ecf20Sopenharmony_ci int prev = fi->retries; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_retries); 3538c2ecf20Sopenharmony_ci fi->retries += count; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (prev > 0) 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 3598c2ecf20Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); 3608c2ecf20Sopenharmony_ci dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, 3618c2ecf20Sopenharmony_ci sizeof(*hdr), DMA_TO_DEVICE); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct ath_buf *bf = NULL; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci spin_lock_bh(&sc->tx.txbuflock); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (unlikely(list_empty(&sc->tx.txbuf))) { 3718c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 3728c2ecf20Sopenharmony_ci return NULL; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); 3768c2ecf20Sopenharmony_ci list_del(&bf->list); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return bf; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci spin_lock_bh(&sc->tx.txbuflock); 3868c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &sc->tx.txbuf); 3878c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct ath_buf *tbf; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci tbf = ath_tx_get_buffer(sc); 3958c2ecf20Sopenharmony_ci if (WARN_ON(!tbf)) 3968c2ecf20Sopenharmony_ci return NULL; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ATH_TXBUF_RESET(tbf); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci tbf->bf_mpdu = bf->bf_mpdu; 4018c2ecf20Sopenharmony_ci tbf->bf_buf_addr = bf->bf_buf_addr; 4028c2ecf20Sopenharmony_ci memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); 4038c2ecf20Sopenharmony_ci tbf->bf_state = bf->bf_state; 4048c2ecf20Sopenharmony_ci tbf->bf_state.stale = false; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return tbf; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, 4108c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int txok, 4118c2ecf20Sopenharmony_ci int *nframes, int *nbad) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci u16 seq_st = 0; 4148c2ecf20Sopenharmony_ci u32 ba[WME_BA_BMP_SIZE >> 5]; 4158c2ecf20Sopenharmony_ci int ba_index; 4168c2ecf20Sopenharmony_ci int isaggr = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci *nbad = 0; 4198c2ecf20Sopenharmony_ci *nframes = 0; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci isaggr = bf_isaggr(bf); 4228c2ecf20Sopenharmony_ci if (isaggr) { 4238c2ecf20Sopenharmony_ci seq_st = ts->ts_seqnum; 4248c2ecf20Sopenharmony_ci memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci while (bf) { 4288c2ecf20Sopenharmony_ci ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci (*nframes)++; 4318c2ecf20Sopenharmony_ci if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) 4328c2ecf20Sopenharmony_ci (*nbad)++; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci bf = bf->bf_next; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, 4408c2ecf20Sopenharmony_ci struct ath_buf *bf, struct list_head *bf_q, 4418c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 4428c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, 4438c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int txok) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct ath_node *an = NULL; 4468c2ecf20Sopenharmony_ci struct sk_buff *skb; 4478c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 4488c2ecf20Sopenharmony_ci struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; 4498c2ecf20Sopenharmony_ci struct list_head bf_head; 4508c2ecf20Sopenharmony_ci struct sk_buff_head bf_pending; 4518c2ecf20Sopenharmony_ci u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; 4528c2ecf20Sopenharmony_ci u32 ba[WME_BA_BMP_SIZE >> 5]; 4538c2ecf20Sopenharmony_ci int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; 4548c2ecf20Sopenharmony_ci bool rc_update = true, isba; 4558c2ecf20Sopenharmony_ci struct ieee80211_tx_rate rates[4]; 4568c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 4578c2ecf20Sopenharmony_ci int nframes; 4588c2ecf20Sopenharmony_ci bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); 4598c2ecf20Sopenharmony_ci int i, retries; 4608c2ecf20Sopenharmony_ci int bar_index = -1; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 4638c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci memcpy(rates, bf->rates, sizeof(rates)); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci retries = ts->ts_longretry + 1; 4688c2ecf20Sopenharmony_ci for (i = 0; i < ts->ts_rateindex; i++) 4698c2ecf20Sopenharmony_ci retries += rates[i].count; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!sta) { 4728c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 4738c2ecf20Sopenharmony_ci while (bf) { 4748c2ecf20Sopenharmony_ci bf_next = bf->bf_next; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!bf->bf_state.stale || bf_next != NULL) 4778c2ecf20Sopenharmony_ci list_move_tail(&bf->list, &bf_head); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, 0); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci bf = bf_next; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 4878c2ecf20Sopenharmony_ci seq_first = tid->seq_start; 4888c2ecf20Sopenharmony_ci isba = ts->ts_flags & ATH9K_TX_BA; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * The hardware occasionally sends a tx status for the wrong TID. 4928c2ecf20Sopenharmony_ci * In this case, the BA status cannot be considered valid and all 4938c2ecf20Sopenharmony_ci * subframes need to be retransmitted 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * Only BlockAcks have a TID and therefore normal Acks cannot be 4968c2ecf20Sopenharmony_ci * checked 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci if (isba && tid->tidno != ts->tid) 4998c2ecf20Sopenharmony_ci txok = false; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci isaggr = bf_isaggr(bf); 5028c2ecf20Sopenharmony_ci memset(ba, 0, WME_BA_BMP_SIZE >> 3); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (isaggr && txok) { 5058c2ecf20Sopenharmony_ci if (ts->ts_flags & ATH9K_TX_BA) { 5068c2ecf20Sopenharmony_ci seq_st = ts->ts_seqnum; 5078c2ecf20Sopenharmony_ci memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); 5088c2ecf20Sopenharmony_ci } else { 5098c2ecf20Sopenharmony_ci /* 5108c2ecf20Sopenharmony_ci * AR5416 can become deaf/mute when BA 5118c2ecf20Sopenharmony_ci * issue happens. Chip needs to be reset. 5128c2ecf20Sopenharmony_ci * But AP code may have sychronization issues 5138c2ecf20Sopenharmony_ci * when perform internal reset in this routine. 5148c2ecf20Sopenharmony_ci * Only enable reset in STA mode for now. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) 5178c2ecf20Sopenharmony_ci needreset = 1; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci __skb_queue_head_init(&bf_pending); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); 5248c2ecf20Sopenharmony_ci while (bf) { 5258c2ecf20Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci txfail = txpending = sendbar = 0; 5288c2ecf20Sopenharmony_ci bf_next = bf->bf_next; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 5318c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 5328c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno) || 5358c2ecf20Sopenharmony_ci !tid->active) { 5368c2ecf20Sopenharmony_ci /* 5378c2ecf20Sopenharmony_ci * Outside of the current BlockAck window, 5388c2ecf20Sopenharmony_ci * maybe part of a previous session 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci txfail = 1; 5418c2ecf20Sopenharmony_ci } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { 5428c2ecf20Sopenharmony_ci /* transmit completion, subframe is 5438c2ecf20Sopenharmony_ci * acked by block ack */ 5448c2ecf20Sopenharmony_ci acked_cnt++; 5458c2ecf20Sopenharmony_ci } else if (!isaggr && txok) { 5468c2ecf20Sopenharmony_ci /* transmit completion */ 5478c2ecf20Sopenharmony_ci acked_cnt++; 5488c2ecf20Sopenharmony_ci } else if (flush) { 5498c2ecf20Sopenharmony_ci txpending = 1; 5508c2ecf20Sopenharmony_ci } else if (fi->retries < ATH_MAX_SW_RETRIES) { 5518c2ecf20Sopenharmony_ci if (txok || !an->sleeping) 5528c2ecf20Sopenharmony_ci ath_tx_set_retry(sc, txq, bf->bf_mpdu, 5538c2ecf20Sopenharmony_ci retries); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci txpending = 1; 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci txfail = 1; 5588c2ecf20Sopenharmony_ci txfail_cnt++; 5598c2ecf20Sopenharmony_ci bar_index = max_t(int, bar_index, 5608c2ecf20Sopenharmony_ci ATH_BA_INDEX(seq_first, seqno)); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * Make sure the last desc is reclaimed if it 5658c2ecf20Sopenharmony_ci * not a holding desc. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 5688c2ecf20Sopenharmony_ci if (bf_next != NULL || !bf_last->bf_state.stale) 5698c2ecf20Sopenharmony_ci list_move_tail(&bf->list, &bf_head); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!txpending) { 5728c2ecf20Sopenharmony_ci /* 5738c2ecf20Sopenharmony_ci * complete the acked-ones/xretried ones; update 5748c2ecf20Sopenharmony_ci * block-ack window 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { 5798c2ecf20Sopenharmony_ci memcpy(tx_info->control.rates, rates, sizeof(rates)); 5808c2ecf20Sopenharmony_ci ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); 5818c2ecf20Sopenharmony_ci rc_update = false; 5828c2ecf20Sopenharmony_ci if (bf == bf->bf_lastbf) 5838c2ecf20Sopenharmony_ci ath_dynack_sample_tx_ts(sc->sc_ah, 5848c2ecf20Sopenharmony_ci bf->bf_mpdu, 5858c2ecf20Sopenharmony_ci ts, sta); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts, 5898c2ecf20Sopenharmony_ci !txfail); 5908c2ecf20Sopenharmony_ci } else { 5918c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) { 5928c2ecf20Sopenharmony_ci tx_info->flags &= ~IEEE80211_TX_STATUS_EOSP; 5938c2ecf20Sopenharmony_ci ieee80211_sta_eosp(sta); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci /* retry the un-acked ones */ 5968c2ecf20Sopenharmony_ci if (bf->bf_next == NULL && bf_last->bf_state.stale) { 5978c2ecf20Sopenharmony_ci struct ath_buf *tbf; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci tbf = ath_clone_txbuf(sc, bf_last); 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * Update tx baw and complete the 6028c2ecf20Sopenharmony_ci * frame with failed status if we 6038c2ecf20Sopenharmony_ci * run out of tx buf. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci if (!tbf) { 6068c2ecf20Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, 6098c2ecf20Sopenharmony_ci &bf_head, NULL, ts, 6108c2ecf20Sopenharmony_ci 0); 6118c2ecf20Sopenharmony_ci bar_index = max_t(int, bar_index, 6128c2ecf20Sopenharmony_ci ATH_BA_INDEX(seq_first, seqno)); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci fi->bf = tbf; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * Put this buffer to the temporary pending 6218c2ecf20Sopenharmony_ci * queue to retain ordering 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci __skb_queue_tail(&bf_pending, skb); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci bf = bf_next; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* prepend un-acked frames to the beginning of the pending frame queue */ 6308c2ecf20Sopenharmony_ci if (!skb_queue_empty(&bf_pending)) { 6318c2ecf20Sopenharmony_ci if (an->sleeping) 6328c2ecf20Sopenharmony_ci ieee80211_sta_set_buffered(sta, tid->tidno, true); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci skb_queue_splice_tail(&bf_pending, &tid->retry_q); 6358c2ecf20Sopenharmony_ci if (!an->sleeping) { 6368c2ecf20Sopenharmony_ci ath_tx_queue_tid(sc, tid); 6378c2ecf20Sopenharmony_ci if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) 6388c2ecf20Sopenharmony_ci tid->clear_ps_filter = true; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (bar_index >= 0) { 6438c2ecf20Sopenharmony_ci u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq)) 6468c2ecf20Sopenharmony_ci tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 6498c2ecf20Sopenharmony_ci ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1)); 6508c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (needreset) 6548c2ecf20Sopenharmony_ci ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic bool bf_is_ampdu_not_probing(struct ath_buf *bf) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); 6608c2ecf20Sopenharmony_ci return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void ath_tx_count_airtime(struct ath_softc *sc, 6648c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 6658c2ecf20Sopenharmony_ci struct ath_buf *bf, 6668c2ecf20Sopenharmony_ci struct ath_tx_status *ts, 6678c2ecf20Sopenharmony_ci u8 tid) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci u32 airtime = 0; 6708c2ecf20Sopenharmony_ci int i; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci airtime += ts->duration * (ts->ts_longretry + 1); 6738c2ecf20Sopenharmony_ci for(i = 0; i < ts->ts_rateindex; i++) { 6748c2ecf20Sopenharmony_ci int rate_dur = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, i); 6758c2ecf20Sopenharmony_ci airtime += rate_dur * bf->rates[i].count; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, airtime, 0); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, 6828c2ecf20Sopenharmony_ci struct ath_tx_status *ts, struct ath_buf *bf, 6838c2ecf20Sopenharmony_ci struct list_head *bf_head) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 6868c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 6878c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 6888c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 6898c2ecf20Sopenharmony_ci struct ath_atx_tid *tid = NULL; 6908c2ecf20Sopenharmony_ci bool txok, flush; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci txok = !(ts->ts_status & ATH9K_TXERR_MASK); 6938c2ecf20Sopenharmony_ci flush = !!(ts->ts_status & ATH9K_TX_FLUSH); 6948c2ecf20Sopenharmony_ci txq->axq_tx_inprogress = false; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci txq->axq_depth--; 6978c2ecf20Sopenharmony_ci if (bf_is_ampdu_not_probing(bf)) 6988c2ecf20Sopenharmony_ci txq->axq_ampdu_depth--; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, 7018c2ecf20Sopenharmony_ci ts->ts_rateindex); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; 7048c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); 7058c2ecf20Sopenharmony_ci if (sta) { 7068c2ecf20Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 7078c2ecf20Sopenharmony_ci tid = ath_get_skb_tid(sc, an, bf->bf_mpdu); 7088c2ecf20Sopenharmony_ci ath_tx_count_airtime(sc, sta, bf, ts, tid->tidno); 7098c2ecf20Sopenharmony_ci if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) 7108c2ecf20Sopenharmony_ci tid->clear_ps_filter = true; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (!bf_isampdu(bf)) { 7148c2ecf20Sopenharmony_ci if (!flush) { 7158c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(bf->bf_mpdu); 7168c2ecf20Sopenharmony_ci memcpy(info->control.rates, bf->rates, 7178c2ecf20Sopenharmony_ci sizeof(info->control.rates)); 7188c2ecf20Sopenharmony_ci ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); 7198c2ecf20Sopenharmony_ci ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts, 7208c2ecf20Sopenharmony_ci sta); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); 7238c2ecf20Sopenharmony_ci } else 7248c2ecf20Sopenharmony_ci ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (!flush) 7278c2ecf20Sopenharmony_ci ath_txq_schedule(sc, txq); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic bool ath_lookup_legacy(struct ath_buf *bf) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct sk_buff *skb; 7338c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 7348c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates; 7358c2ecf20Sopenharmony_ci int i; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 7388c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 7398c2ecf20Sopenharmony_ci rates = tx_info->control.rates; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 7428c2ecf20Sopenharmony_ci if (!rates[i].count || rates[i].idx < 0) 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) 7468c2ecf20Sopenharmony_ci return true; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return false; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, 7538c2ecf20Sopenharmony_ci struct ath_atx_tid *tid) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct sk_buff *skb; 7568c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 7578c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates; 7588c2ecf20Sopenharmony_ci u32 max_4ms_framelen, frmlen; 7598c2ecf20Sopenharmony_ci u16 aggr_limit, bt_aggr_limit, legacy = 0; 7608c2ecf20Sopenharmony_ci int q = tid->txq->mac80211_qnum; 7618c2ecf20Sopenharmony_ci int i; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 7648c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 7658c2ecf20Sopenharmony_ci rates = bf->rates; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* 7688c2ecf20Sopenharmony_ci * Find the lowest frame length among the rate series that will have a 7698c2ecf20Sopenharmony_ci * 4ms (or TXOP limited) transmit duration. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 7748c2ecf20Sopenharmony_ci int modeidx; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!rates[i].count) 7778c2ecf20Sopenharmony_ci continue; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { 7808c2ecf20Sopenharmony_ci legacy = 1; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 7858c2ecf20Sopenharmony_ci modeidx = MCS_HT40; 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci modeidx = MCS_HT20; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) 7908c2ecf20Sopenharmony_ci modeidx++; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci frmlen = sc->tx.max_aggr_framelen[q][modeidx][rates[i].idx]; 7938c2ecf20Sopenharmony_ci max_4ms_framelen = min(max_4ms_framelen, frmlen); 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* 7978c2ecf20Sopenharmony_ci * limit aggregate size by the minimum rate if rate selected is 7988c2ecf20Sopenharmony_ci * not a probe rate, if rate selected is a probe rate then 7998c2ecf20Sopenharmony_ci * avoid aggregation of this packet. 8008c2ecf20Sopenharmony_ci */ 8018c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* 8078c2ecf20Sopenharmony_ci * Override the default aggregation limit for BTCOEX. 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen); 8108c2ecf20Sopenharmony_ci if (bt_aggr_limit) 8118c2ecf20Sopenharmony_ci aggr_limit = bt_aggr_limit; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (tid->an->maxampdu) 8148c2ecf20Sopenharmony_ci aggr_limit = min(aggr_limit, tid->an->maxampdu); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci return aggr_limit; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci/* 8208c2ecf20Sopenharmony_ci * Returns the number of delimiters to be added to 8218c2ecf20Sopenharmony_ci * meet the minimum required mpdudensity. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_cistatic int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, 8248c2ecf20Sopenharmony_ci struct ath_buf *bf, u16 frmlen, 8258c2ecf20Sopenharmony_ci bool first_subfrm) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci#define FIRST_DESC_NDELIMS 60 8288c2ecf20Sopenharmony_ci u32 nsymbits, nsymbols; 8298c2ecf20Sopenharmony_ci u16 minlen; 8308c2ecf20Sopenharmony_ci u8 flags, rix; 8318c2ecf20Sopenharmony_ci int width, streams, half_gi, ndelim, mindelim; 8328c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Select standard number of delimiters based on frame length alone */ 8358c2ecf20Sopenharmony_ci ndelim = ATH_AGGR_GET_NDELIM(frmlen); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* 8388c2ecf20Sopenharmony_ci * If encryption enabled, hardware requires some more padding between 8398c2ecf20Sopenharmony_ci * subframes. 8408c2ecf20Sopenharmony_ci * TODO - this could be improved to be dependent on the rate. 8418c2ecf20Sopenharmony_ci * The hardware can keep up at lower rates, but not higher rates 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci if ((fi->keyix != ATH9K_TXKEYIX_INVALID) && 8448c2ecf20Sopenharmony_ci !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) 8458c2ecf20Sopenharmony_ci ndelim += ATH_AGGR_ENCRYPTDELIM; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * Add delimiter when using RTS/CTS with aggregation 8498c2ecf20Sopenharmony_ci * and non enterprise AR9003 card 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci if (first_subfrm && !AR_SREV_9580_10_OR_LATER(sc->sc_ah) && 8528c2ecf20Sopenharmony_ci (sc->sc_ah->ent_mode & AR_ENT_OTP_MIN_PKT_SIZE_DISABLE)) 8538c2ecf20Sopenharmony_ci ndelim = max(ndelim, FIRST_DESC_NDELIMS); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * Convert desired mpdu density from microeconds to bytes based 8578c2ecf20Sopenharmony_ci * on highest rate in rate series (i.e. first rate) to determine 8588c2ecf20Sopenharmony_ci * required minimum length for subframe. Take into account 8598c2ecf20Sopenharmony_ci * whether high rate is 20 or 40Mhz and half or full GI. 8608c2ecf20Sopenharmony_ci * 8618c2ecf20Sopenharmony_ci * If there is no mpdu density restriction, no further calculation 8628c2ecf20Sopenharmony_ci * is needed. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (tid->an->mpdudensity == 0) 8668c2ecf20Sopenharmony_ci return ndelim; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci rix = bf->rates[0].idx; 8698c2ecf20Sopenharmony_ci flags = bf->rates[0].flags; 8708c2ecf20Sopenharmony_ci width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; 8718c2ecf20Sopenharmony_ci half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (half_gi) 8748c2ecf20Sopenharmony_ci nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity); 8758c2ecf20Sopenharmony_ci else 8768c2ecf20Sopenharmony_ci nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (nsymbols == 0) 8798c2ecf20Sopenharmony_ci nsymbols = 1; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci streams = HT_RC_2_STREAMS(rix); 8828c2ecf20Sopenharmony_ci nsymbits = bits_per_symbol[rix % 8][width] * streams; 8838c2ecf20Sopenharmony_ci minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (frmlen < minlen) { 8868c2ecf20Sopenharmony_ci mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ; 8878c2ecf20Sopenharmony_ci ndelim = max(mindelim, ndelim); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci return ndelim; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic int 8948c2ecf20Sopenharmony_ciath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, 8958c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, struct ath_buf **buf) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 8988c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 8998c2ecf20Sopenharmony_ci struct ath_buf *bf; 9008c2ecf20Sopenharmony_ci struct sk_buff *skb, *first_skb = NULL; 9018c2ecf20Sopenharmony_ci u16 seqno; 9028c2ecf20Sopenharmony_ci int ret; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci while (1) { 9058c2ecf20Sopenharmony_ci ret = ath_tid_dequeue(tid, &skb); 9068c2ecf20Sopenharmony_ci if (ret < 0) 9078c2ecf20Sopenharmony_ci return ret; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 9108c2ecf20Sopenharmony_ci bf = fi->bf; 9118c2ecf20Sopenharmony_ci if (!fi->bf) 9128c2ecf20Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txq, tid, skb); 9138c2ecf20Sopenharmony_ci else 9148c2ecf20Sopenharmony_ci bf->bf_state.stale = false; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (!bf) { 9178c2ecf20Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 9188c2ecf20Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 9198c2ecf20Sopenharmony_ci continue; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci bf->bf_next = NULL; 9238c2ecf20Sopenharmony_ci bf->bf_lastbf = bf; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 9268c2ecf20Sopenharmony_ci tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | 9278c2ecf20Sopenharmony_ci IEEE80211_TX_STATUS_EOSP); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * No aggregation session is running, but there may be frames 9318c2ecf20Sopenharmony_ci * from a previous session or a failed attempt in the queue. 9328c2ecf20Sopenharmony_ci * Send them out as normal data frames 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (!tid->active) 9358c2ecf20Sopenharmony_ci tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { 9388c2ecf20Sopenharmony_ci bf->bf_state.bf_type = 0; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; 9438c2ecf20Sopenharmony_ci seqno = bf->bf_state.seqno; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* do not step over block-ack window */ 9468c2ecf20Sopenharmony_ci if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { 9478c2ecf20Sopenharmony_ci __skb_queue_tail(&tid->retry_q, skb); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* If there are other skbs in the retry q, they are 9508c2ecf20Sopenharmony_ci * probably within the BAW, so loop immediately to get 9518c2ecf20Sopenharmony_ci * one of them. Otherwise the queue can get stuck. */ 9528c2ecf20Sopenharmony_ci if (!skb_queue_is_first(&tid->retry_q, skb) && 9538c2ecf20Sopenharmony_ci !WARN_ON(skb == first_skb)) { 9548c2ecf20Sopenharmony_ci if(!first_skb) /* infinite loop prevention */ 9558c2ecf20Sopenharmony_ci first_skb = skb; 9568c2ecf20Sopenharmony_ci continue; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci return -EINPROGRESS; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { 9628c2ecf20Sopenharmony_ci struct ath_tx_status ts = {}; 9638c2ecf20Sopenharmony_ci struct list_head bf_head; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 9668c2ecf20Sopenharmony_ci list_add(&bf->list, &bf_head); 9678c2ecf20Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 9688c2ecf20Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 9698c2ecf20Sopenharmony_ci continue; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (bf_isampdu(bf)) 9738c2ecf20Sopenharmony_ci ath_tx_addto_baw(sc, tid, bf); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci *buf = bf; 9798c2ecf20Sopenharmony_ci return 0; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic int 9838c2ecf20Sopenharmony_ciath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, 9848c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, struct list_head *bf_q, 9858c2ecf20Sopenharmony_ci struct ath_buf *bf_first) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) 9888c2ecf20Sopenharmony_ci struct ath_buf *bf = bf_first, *bf_prev = NULL; 9898c2ecf20Sopenharmony_ci int nframes = 0, ndelim, ret; 9908c2ecf20Sopenharmony_ci u16 aggr_limit = 0, al = 0, bpad = 0, 9918c2ecf20Sopenharmony_ci al_delta, h_baw = tid->baw_size / 2; 9928c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 9938c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 9948c2ecf20Sopenharmony_ci struct sk_buff *skb; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci bf = bf_first; 9988c2ecf20Sopenharmony_ci aggr_limit = ath_lookup_rate(sc, bf, tid); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci while (bf) 10018c2ecf20Sopenharmony_ci { 10028c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 10038c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* do not exceed aggregation limit */ 10068c2ecf20Sopenharmony_ci al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; 10078c2ecf20Sopenharmony_ci if (nframes) { 10088c2ecf20Sopenharmony_ci if (aggr_limit < al + bpad + al_delta || 10098c2ecf20Sopenharmony_ci ath_lookup_legacy(bf) || nframes >= h_baw) 10108c2ecf20Sopenharmony_ci goto stop; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 10138c2ecf20Sopenharmony_ci if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || 10148c2ecf20Sopenharmony_ci !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) 10158c2ecf20Sopenharmony_ci goto stop; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* add padding for previous frame to aggregation length */ 10198c2ecf20Sopenharmony_ci al += bpad + al_delta; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* 10228c2ecf20Sopenharmony_ci * Get the delimiters needed to meet the MPDU 10238c2ecf20Sopenharmony_ci * density for this node. 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_ci ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen, 10268c2ecf20Sopenharmony_ci !nframes); 10278c2ecf20Sopenharmony_ci bpad = PADBYTES(al_delta) + (ndelim << 2); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci nframes++; 10308c2ecf20Sopenharmony_ci bf->bf_next = NULL; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci /* link buffers of this frame to the aggregate */ 10338c2ecf20Sopenharmony_ci bf->bf_state.ndelim = ndelim; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci list_add_tail(&bf->list, bf_q); 10368c2ecf20Sopenharmony_ci if (bf_prev) 10378c2ecf20Sopenharmony_ci bf_prev->bf_next = bf; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci bf_prev = bf; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 10428c2ecf20Sopenharmony_ci if (ret < 0) 10438c2ecf20Sopenharmony_ci break; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci goto finish; 10468c2ecf20Sopenharmony_cistop: 10478c2ecf20Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 10488c2ecf20Sopenharmony_cifinish: 10498c2ecf20Sopenharmony_ci bf = bf_first; 10508c2ecf20Sopenharmony_ci bf->bf_lastbf = bf_prev; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (bf == bf_prev) { 10538c2ecf20Sopenharmony_ci al = get_frame_info(bf->bf_mpdu)->framelen; 10548c2ecf20Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU; 10558c2ecf20Sopenharmony_ci } else { 10568c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_aggr); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return al; 10608c2ecf20Sopenharmony_ci#undef PADBYTES 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci/* 10648c2ecf20Sopenharmony_ci * rix - rate index 10658c2ecf20Sopenharmony_ci * pktlen - total bytes (delims + data + fcs + pads + pad delims) 10668c2ecf20Sopenharmony_ci * width - 0 for 20 MHz, 1 for 40 MHz 10678c2ecf20Sopenharmony_ci * half_gi - to use 4us v/s 3.6 us for symbol time 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_ciu32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, 10708c2ecf20Sopenharmony_ci int width, int half_gi, bool shortPreamble) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci u32 nbits, nsymbits, duration, nsymbols; 10738c2ecf20Sopenharmony_ci int streams; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* find number of symbols: PLCP + data */ 10768c2ecf20Sopenharmony_ci streams = HT_RC_2_STREAMS(rix); 10778c2ecf20Sopenharmony_ci nbits = (pktlen << 3) + OFDM_PLCP_BITS; 10788c2ecf20Sopenharmony_ci nsymbits = bits_per_symbol[rix % 8][width] * streams; 10798c2ecf20Sopenharmony_ci nsymbols = (nbits + nsymbits - 1) / nsymbits; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!half_gi) 10828c2ecf20Sopenharmony_ci duration = SYMBOL_TIME(nsymbols); 10838c2ecf20Sopenharmony_ci else 10848c2ecf20Sopenharmony_ci duration = SYMBOL_TIME_HALFGI(nsymbols); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci /* addup duration for legacy/ht training and signal fields */ 10878c2ecf20Sopenharmony_ci duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return duration; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci int streams = HT_RC_2_STREAMS(mcs); 10958c2ecf20Sopenharmony_ci int symbols, bits; 10968c2ecf20Sopenharmony_ci int bytes = 0; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 10998c2ecf20Sopenharmony_ci symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); 11008c2ecf20Sopenharmony_ci bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; 11018c2ecf20Sopenharmony_ci bits -= OFDM_PLCP_BITS; 11028c2ecf20Sopenharmony_ci bytes = bits / 8; 11038c2ecf20Sopenharmony_ci if (bytes > 65532) 11048c2ecf20Sopenharmony_ci bytes = 65532; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci return bytes; 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_civoid ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci u16 *cur_ht20, *cur_ht20_sgi, *cur_ht40, *cur_ht40_sgi; 11128c2ecf20Sopenharmony_ci int mcs; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* 4ms is the default (and maximum) duration */ 11158c2ecf20Sopenharmony_ci if (!txop || txop > 4096) 11168c2ecf20Sopenharmony_ci txop = 4096; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci cur_ht20 = sc->tx.max_aggr_framelen[queue][MCS_HT20]; 11198c2ecf20Sopenharmony_ci cur_ht20_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT20_SGI]; 11208c2ecf20Sopenharmony_ci cur_ht40 = sc->tx.max_aggr_framelen[queue][MCS_HT40]; 11218c2ecf20Sopenharmony_ci cur_ht40_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT40_SGI]; 11228c2ecf20Sopenharmony_ci for (mcs = 0; mcs < 32; mcs++) { 11238c2ecf20Sopenharmony_ci cur_ht20[mcs] = ath_max_framelen(txop, mcs, false, false); 11248c2ecf20Sopenharmony_ci cur_ht20_sgi[mcs] = ath_max_framelen(txop, mcs, false, true); 11258c2ecf20Sopenharmony_ci cur_ht40[mcs] = ath_max_framelen(txop, mcs, true, false); 11268c2ecf20Sopenharmony_ci cur_ht40_sgi[mcs] = ath_max_framelen(txop, mcs, true, true); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, 11318c2ecf20Sopenharmony_ci u8 rateidx, bool is_40, bool is_cck) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci u8 max_power; 11348c2ecf20Sopenharmony_ci struct sk_buff *skb; 11358c2ecf20Sopenharmony_ci struct ath_frame_info *fi; 11368c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 11378c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (sc->tx99_state || !ah->tpc_enabled) 11408c2ecf20Sopenharmony_ci return MAX_RATE_POWER; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 11438c2ecf20Sopenharmony_ci fi = get_frame_info(skb); 11448c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (!AR_SREV_9300_20_OR_LATER(ah)) { 11478c2ecf20Sopenharmony_ci int txpower = fi->tx_power; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (is_40) { 11508c2ecf20Sopenharmony_ci u8 power_ht40delta; 11518c2ecf20Sopenharmony_ci struct ar5416_eeprom_def *eep = &ah->eeprom.def; 11528c2ecf20Sopenharmony_ci u16 eeprom_rev = ah->eep_ops->get_eeprom_rev(ah); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (eeprom_rev >= AR5416_EEP_MINOR_VER_2) { 11558c2ecf20Sopenharmony_ci bool is_2ghz; 11568c2ecf20Sopenharmony_ci struct modal_eep_header *pmodal; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci is_2ghz = info->band == NL80211_BAND_2GHZ; 11598c2ecf20Sopenharmony_ci pmodal = &eep->modalHeader[is_2ghz]; 11608c2ecf20Sopenharmony_ci power_ht40delta = pmodal->ht40PowerIncForPdadc; 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci power_ht40delta = 2; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci txpower += power_ht40delta; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (AR_SREV_9287(ah) || AR_SREV_9285(ah) || 11688c2ecf20Sopenharmony_ci AR_SREV_9271(ah)) { 11698c2ecf20Sopenharmony_ci txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB; 11708c2ecf20Sopenharmony_ci } else if (AR_SREV_9280_20_OR_LATER(ah)) { 11718c2ecf20Sopenharmony_ci s8 power_offset; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci power_offset = ah->eep_ops->get_eeprom(ah, 11748c2ecf20Sopenharmony_ci EEP_PWR_TABLE_OFFSET); 11758c2ecf20Sopenharmony_ci txpower -= 2 * power_offset; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (OLC_FOR_AR9280_20_LATER && is_cck) 11798c2ecf20Sopenharmony_ci txpower -= 2; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci txpower = max(txpower, 0); 11828c2ecf20Sopenharmony_ci max_power = min_t(u8, ah->tx_power[rateidx], txpower); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* XXX: clamp minimum TX power at 1 for AR9160 since if 11858c2ecf20Sopenharmony_ci * max_power is set to 0, frames are transmitted at max 11868c2ecf20Sopenharmony_ci * TX power 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ci if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) 11898c2ecf20Sopenharmony_ci max_power = 1; 11908c2ecf20Sopenharmony_ci } else if (!bf->bf_state.bfs_paprd) { 11918c2ecf20Sopenharmony_ci if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) 11928c2ecf20Sopenharmony_ci max_power = min_t(u8, ah->tx_power_stbc[rateidx], 11938c2ecf20Sopenharmony_ci fi->tx_power); 11948c2ecf20Sopenharmony_ci else 11958c2ecf20Sopenharmony_ci max_power = min_t(u8, ah->tx_power[rateidx], 11968c2ecf20Sopenharmony_ci fi->tx_power); 11978c2ecf20Sopenharmony_ci } else { 11988c2ecf20Sopenharmony_ci max_power = ah->paprd_training_power; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return max_power; 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, 12058c2ecf20Sopenharmony_ci struct ath_tx_info *info, int len, bool rts) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 12088c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 12098c2ecf20Sopenharmony_ci struct sk_buff *skb; 12108c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 12118c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates; 12128c2ecf20Sopenharmony_ci const struct ieee80211_rate *rate; 12138c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 12148c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 12158c2ecf20Sopenharmony_ci u32 rts_thresh = sc->hw->wiphy->rts_threshold; 12168c2ecf20Sopenharmony_ci int i; 12178c2ecf20Sopenharmony_ci u8 rix = 0; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci skb = bf->bf_mpdu; 12208c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 12218c2ecf20Sopenharmony_ci rates = bf->rates; 12228c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci /* set dur_update_en for l-sig computation except for PS-Poll frames */ 12258c2ecf20Sopenharmony_ci info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); 12268c2ecf20Sopenharmony_ci info->rtscts_rate = fi->rtscts_rate; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bf->rates); i++) { 12298c2ecf20Sopenharmony_ci bool is_40, is_sgi, is_sp, is_cck; 12308c2ecf20Sopenharmony_ci int phy; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (!rates[i].count || (rates[i].idx < 0)) 12338c2ecf20Sopenharmony_ci continue; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci rix = rates[i].idx; 12368c2ecf20Sopenharmony_ci info->rates[i].Tries = rates[i].count; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* 12398c2ecf20Sopenharmony_ci * Handle RTS threshold for unaggregated HT frames. 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci if (bf_isampdu(bf) && !bf_isaggr(bf) && 12428c2ecf20Sopenharmony_ci (rates[i].flags & IEEE80211_TX_RC_MCS) && 12438c2ecf20Sopenharmony_ci unlikely(rts_thresh != (u32) -1)) { 12448c2ecf20Sopenharmony_ci if (!rts_thresh || (len > rts_thresh)) 12458c2ecf20Sopenharmony_ci rts = true; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { 12498c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; 12508c2ecf20Sopenharmony_ci info->flags |= ATH9K_TXDESC_RTSENA; 12518c2ecf20Sopenharmony_ci } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 12528c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; 12538c2ecf20Sopenharmony_ci info->flags |= ATH9K_TXDESC_CTSENA; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 12578c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_2040; 12588c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) 12598c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); 12628c2ecf20Sopenharmony_ci is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); 12638c2ecf20Sopenharmony_ci is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_MCS) { 12668c2ecf20Sopenharmony_ci /* MCS rates */ 12678c2ecf20Sopenharmony_ci info->rates[i].Rate = rix | 0x80; 12688c2ecf20Sopenharmony_ci info->rates[i].ChSel = ath_txchainmask_reduction(sc, 12698c2ecf20Sopenharmony_ci ah->txchainmask, info->rates[i].Rate); 12708c2ecf20Sopenharmony_ci info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len, 12718c2ecf20Sopenharmony_ci is_40, is_sgi, is_sp); 12728c2ecf20Sopenharmony_ci if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) 12738c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; 12748c2ecf20Sopenharmony_ci if (rix >= 8 && fi->dyn_smps) { 12758c2ecf20Sopenharmony_ci info->rates[i].RateFlags |= 12768c2ecf20Sopenharmony_ci ATH9K_RATESERIES_RTS_CTS; 12778c2ecf20Sopenharmony_ci info->flags |= ATH9K_TXDESC_CTSENA; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, 12818c2ecf20Sopenharmony_ci is_40, false); 12828c2ecf20Sopenharmony_ci continue; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* legacy rates */ 12868c2ecf20Sopenharmony_ci rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; 12878c2ecf20Sopenharmony_ci if ((tx_info->band == NL80211_BAND_2GHZ) && 12888c2ecf20Sopenharmony_ci !(rate->flags & IEEE80211_RATE_ERP_G)) 12898c2ecf20Sopenharmony_ci phy = WLAN_RC_PHY_CCK; 12908c2ecf20Sopenharmony_ci else 12918c2ecf20Sopenharmony_ci phy = WLAN_RC_PHY_OFDM; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci info->rates[i].Rate = rate->hw_value; 12948c2ecf20Sopenharmony_ci if (rate->hw_value_short) { 12958c2ecf20Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 12968c2ecf20Sopenharmony_ci info->rates[i].Rate |= rate->hw_value_short; 12978c2ecf20Sopenharmony_ci } else { 12988c2ecf20Sopenharmony_ci is_sp = false; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (bf->bf_state.bfs_paprd) 13028c2ecf20Sopenharmony_ci info->rates[i].ChSel = ah->txchainmask; 13038c2ecf20Sopenharmony_ci else 13048c2ecf20Sopenharmony_ci info->rates[i].ChSel = ath_txchainmask_reduction(sc, 13058c2ecf20Sopenharmony_ci ah->txchainmask, info->rates[i].Rate); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, 13088c2ecf20Sopenharmony_ci phy, rate->bitrate * 100, len, rix, is_sp); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci is_cck = IS_CCK_RATE(info->rates[i].Rate); 13118c2ecf20Sopenharmony_ci info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false, 13128c2ecf20Sopenharmony_ci is_cck); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ 13168c2ecf20Sopenharmony_ci if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit)) 13178c2ecf20Sopenharmony_ci info->flags &= ~ATH9K_TXDESC_RTSENA; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ 13208c2ecf20Sopenharmony_ci if (info->flags & ATH9K_TXDESC_RTSENA) 13218c2ecf20Sopenharmony_ci info->flags &= ~ATH9K_TXDESC_CTSENA; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 13278c2ecf20Sopenharmony_ci enum ath9k_pkt_type htype; 13288c2ecf20Sopenharmony_ci __le16 fc; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 13318c2ecf20Sopenharmony_ci fc = hdr->frame_control; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (ieee80211_is_beacon(fc)) 13348c2ecf20Sopenharmony_ci htype = ATH9K_PKT_TYPE_BEACON; 13358c2ecf20Sopenharmony_ci else if (ieee80211_is_probe_resp(fc)) 13368c2ecf20Sopenharmony_ci htype = ATH9K_PKT_TYPE_PROBE_RESP; 13378c2ecf20Sopenharmony_ci else if (ieee80211_is_atim(fc)) 13388c2ecf20Sopenharmony_ci htype = ATH9K_PKT_TYPE_ATIM; 13398c2ecf20Sopenharmony_ci else if (ieee80211_is_pspoll(fc)) 13408c2ecf20Sopenharmony_ci htype = ATH9K_PKT_TYPE_PSPOLL; 13418c2ecf20Sopenharmony_ci else 13428c2ecf20Sopenharmony_ci htype = ATH9K_PKT_TYPE_NORMAL; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci return htype; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, 13488c2ecf20Sopenharmony_ci struct ath_txq *txq, int len) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 13518c2ecf20Sopenharmony_ci struct ath_buf *bf_first = NULL; 13528c2ecf20Sopenharmony_ci struct ath_tx_info info; 13538c2ecf20Sopenharmony_ci u32 rts_thresh = sc->hw->wiphy->rts_threshold; 13548c2ecf20Sopenharmony_ci bool rts = false; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 13578c2ecf20Sopenharmony_ci info.is_first = true; 13588c2ecf20Sopenharmony_ci info.is_last = true; 13598c2ecf20Sopenharmony_ci info.qcu = txq->axq_qnum; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci while (bf) { 13628c2ecf20Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 13638c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 13648c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 13658c2ecf20Sopenharmony_ci bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci info.type = get_hw_packet_type(skb); 13688c2ecf20Sopenharmony_ci if (bf->bf_next) 13698c2ecf20Sopenharmony_ci info.link = bf->bf_next->bf_daddr; 13708c2ecf20Sopenharmony_ci else 13718c2ecf20Sopenharmony_ci info.link = (sc->tx99_state) ? bf->bf_daddr : 0; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (!bf_first) { 13748c2ecf20Sopenharmony_ci bf_first = bf; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (!sc->tx99_state) 13778c2ecf20Sopenharmony_ci info.flags = ATH9K_TXDESC_INTREQ; 13788c2ecf20Sopenharmony_ci if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) || 13798c2ecf20Sopenharmony_ci txq == sc->tx.uapsdq) 13808c2ecf20Sopenharmony_ci info.flags |= ATH9K_TXDESC_CLRDMASK; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) 13838c2ecf20Sopenharmony_ci info.flags |= ATH9K_TXDESC_NOACK; 13848c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_LDPC) 13858c2ecf20Sopenharmony_ci info.flags |= ATH9K_TXDESC_LDPC; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (bf->bf_state.bfs_paprd) 13888c2ecf20Sopenharmony_ci info.flags |= (u32) bf->bf_state.bfs_paprd << 13898c2ecf20Sopenharmony_ci ATH9K_TXDESC_PAPRD_S; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* 13928c2ecf20Sopenharmony_ci * mac80211 doesn't handle RTS threshold for HT because 13938c2ecf20Sopenharmony_ci * the decision has to be taken based on AMPDU length 13948c2ecf20Sopenharmony_ci * and aggregation is done entirely inside ath9k. 13958c2ecf20Sopenharmony_ci * Set the RTS/CTS flag for the first subframe based 13968c2ecf20Sopenharmony_ci * on the threshold. 13978c2ecf20Sopenharmony_ci */ 13988c2ecf20Sopenharmony_ci if (aggr && (bf == bf_first) && 13998c2ecf20Sopenharmony_ci unlikely(rts_thresh != (u32) -1)) { 14008c2ecf20Sopenharmony_ci /* 14018c2ecf20Sopenharmony_ci * "len" is the size of the entire AMPDU. 14028c2ecf20Sopenharmony_ci */ 14038c2ecf20Sopenharmony_ci if (!rts_thresh || (len > rts_thresh)) 14048c2ecf20Sopenharmony_ci rts = true; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (!aggr) 14088c2ecf20Sopenharmony_ci len = fi->framelen; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci ath_buf_set_rate(sc, bf, &info, len, rts); 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci info.buf_addr[0] = bf->bf_buf_addr; 14148c2ecf20Sopenharmony_ci info.buf_len[0] = skb->len; 14158c2ecf20Sopenharmony_ci info.pkt_len = fi->framelen; 14168c2ecf20Sopenharmony_ci info.keyix = fi->keyix; 14178c2ecf20Sopenharmony_ci info.keytype = fi->keytype; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (aggr) { 14208c2ecf20Sopenharmony_ci if (bf == bf_first) 14218c2ecf20Sopenharmony_ci info.aggr = AGGR_BUF_FIRST; 14228c2ecf20Sopenharmony_ci else if (bf == bf_first->bf_lastbf) 14238c2ecf20Sopenharmony_ci info.aggr = AGGR_BUF_LAST; 14248c2ecf20Sopenharmony_ci else 14258c2ecf20Sopenharmony_ci info.aggr = AGGR_BUF_MIDDLE; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci info.ndelim = bf->bf_state.ndelim; 14288c2ecf20Sopenharmony_ci info.aggr_len = len; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (bf == bf_first->bf_lastbf) 14328c2ecf20Sopenharmony_ci bf_first = NULL; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); 14358c2ecf20Sopenharmony_ci bf = bf->bf_next; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic void 14408c2ecf20Sopenharmony_ciath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, 14418c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, struct list_head *bf_q, 14428c2ecf20Sopenharmony_ci struct ath_buf *bf_first) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci struct ath_buf *bf = bf_first, *bf_prev = NULL; 14458c2ecf20Sopenharmony_ci int nframes = 0, ret; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci do { 14488c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci nframes++; 14518c2ecf20Sopenharmony_ci list_add_tail(&bf->list, bf_q); 14528c2ecf20Sopenharmony_ci if (bf_prev) 14538c2ecf20Sopenharmony_ci bf_prev->bf_next = bf; 14548c2ecf20Sopenharmony_ci bf_prev = bf; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (nframes >= 2) 14578c2ecf20Sopenharmony_ci break; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 14608c2ecf20Sopenharmony_ci if (ret < 0) 14618c2ecf20Sopenharmony_ci break; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 14648c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 14658c2ecf20Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 14668c2ecf20Sopenharmony_ci break; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 14708c2ecf20Sopenharmony_ci } while (1); 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, 14748c2ecf20Sopenharmony_ci struct ath_atx_tid *tid) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct ath_buf *bf = NULL; 14778c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info; 14788c2ecf20Sopenharmony_ci struct list_head bf_q; 14798c2ecf20Sopenharmony_ci int aggr_len = 0, ret; 14808c2ecf20Sopenharmony_ci bool aggr; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 14858c2ecf20Sopenharmony_ci if (ret < 0) 14868c2ecf20Sopenharmony_ci return ret; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 14898c2ecf20Sopenharmony_ci aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); 14908c2ecf20Sopenharmony_ci if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || 14918c2ecf20Sopenharmony_ci (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { 14928c2ecf20Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 14938c2ecf20Sopenharmony_ci return -EBUSY; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 14978c2ecf20Sopenharmony_ci if (aggr) 14988c2ecf20Sopenharmony_ci aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); 14998c2ecf20Sopenharmony_ci else 15008c2ecf20Sopenharmony_ci ath_tx_form_burst(sc, txq, tid, &bf_q, bf); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (list_empty(&bf_q)) 15038c2ecf20Sopenharmony_ci return -EAGAIN; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (tid->clear_ps_filter || tid->an->no_ps_filter) { 15068c2ecf20Sopenharmony_ci tid->clear_ps_filter = false; 15078c2ecf20Sopenharmony_ci tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, aggr_len); 15118c2ecf20Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, false); 15128c2ecf20Sopenharmony_ci return 0; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ciint ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, 15168c2ecf20Sopenharmony_ci u16 tid, u16 *ssn) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 15198c2ecf20Sopenharmony_ci struct ath_atx_tid *txtid; 15208c2ecf20Sopenharmony_ci struct ath_txq *txq; 15218c2ecf20Sopenharmony_ci struct ath_node *an; 15228c2ecf20Sopenharmony_ci u8 density; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 15278c2ecf20Sopenharmony_ci txtid = ATH_AN_2_TID(an, tid); 15288c2ecf20Sopenharmony_ci txq = txtid->txq; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* update ampdu factor/density, they may have changed. This may happen 15338c2ecf20Sopenharmony_ci * in HT IBSS when a beacon with HT-info is received after the station 15348c2ecf20Sopenharmony_ci * has already been added. 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 15378c2ecf20Sopenharmony_ci an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 15388c2ecf20Sopenharmony_ci sta->ht_cap.ampdu_factor)) - 1; 15398c2ecf20Sopenharmony_ci density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); 15408c2ecf20Sopenharmony_ci an->mpdudensity = density; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci txtid->active = true; 15448c2ecf20Sopenharmony_ci *ssn = txtid->seq_start = txtid->seq_next; 15458c2ecf20Sopenharmony_ci txtid->bar_index = -1; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); 15488c2ecf20Sopenharmony_ci txtid->baw_head = txtid->baw_tail = 0; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return 0; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_civoid ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 15588c2ecf20Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 15598c2ecf20Sopenharmony_ci struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); 15608c2ecf20Sopenharmony_ci struct ath_txq *txq = txtid->txq; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 15658c2ecf20Sopenharmony_ci txtid->active = false; 15668c2ecf20Sopenharmony_ci ath_tx_flush_tid(sc, txtid); 15678c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_civoid ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, 15718c2ecf20Sopenharmony_ci struct ath_node *an) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 15748c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 15758c2ecf20Sopenharmony_ci int tidno; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 15808c2ecf20Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (!skb_queue_empty(&tid->retry_q)) 15838c2ecf20Sopenharmony_ci ieee80211_sta_set_buffered(sta, tid->tidno, true); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_civoid ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 15918c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 15928c2ecf20Sopenharmony_ci struct ath_txq *txq; 15938c2ecf20Sopenharmony_ci int tidno; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 15988c2ecf20Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 15998c2ecf20Sopenharmony_ci txq = tid->txq; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 16028c2ecf20Sopenharmony_ci tid->clear_ps_filter = true; 16038c2ecf20Sopenharmony_ci if (!skb_queue_empty(&tid->retry_q)) { 16048c2ecf20Sopenharmony_ci ath_tx_queue_tid(sc, tid); 16058c2ecf20Sopenharmony_ci ath_txq_schedule(sc, txq); 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic void 16148c2ecf20Sopenharmony_ciath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 16178c2ecf20Sopenharmony_ci u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); 16188c2ecf20Sopenharmony_ci u16 mask_val = mask * val; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; 16218c2ecf20Sopenharmony_ci if ((hdr->frame_control & mask) != mask_val) { 16228c2ecf20Sopenharmony_ci hdr->frame_control = (hdr->frame_control & ~mask) | mask_val; 16238c2ecf20Sopenharmony_ci dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, 16248c2ecf20Sopenharmony_ci sizeof(*hdr), DMA_TO_DEVICE); 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci} 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_civoid ath9k_release_buffered_frames(struct ieee80211_hw *hw, 16298c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 16308c2ecf20Sopenharmony_ci u16 tids, int nframes, 16318c2ecf20Sopenharmony_ci enum ieee80211_frame_release_type reason, 16328c2ecf20Sopenharmony_ci bool more_data) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 16358c2ecf20Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 16368c2ecf20Sopenharmony_ci struct ath_txq *txq = sc->tx.uapsdq; 16378c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 16388c2ecf20Sopenharmony_ci struct list_head bf_q; 16398c2ecf20Sopenharmony_ci struct ath_buf *bf_tail = NULL, *bf = NULL; 16408c2ecf20Sopenharmony_ci int sent = 0; 16418c2ecf20Sopenharmony_ci int i, ret; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 16448c2ecf20Sopenharmony_ci for (i = 0; tids && nframes; i++, tids >>= 1) { 16458c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (!(tids & 1)) 16488c2ecf20Sopenharmony_ci continue; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci tid = ATH_AN_2_TID(an, i); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci ath_txq_lock(sc, tid->txq); 16538c2ecf20Sopenharmony_ci while (nframes > 0) { 16548c2ecf20Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, 16558c2ecf20Sopenharmony_ci tid, &bf); 16568c2ecf20Sopenharmony_ci if (ret < 0) 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci ath9k_set_moredata(sc, bf, true); 16608c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &bf_q); 16618c2ecf20Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 16628c2ecf20Sopenharmony_ci if (bf_isampdu(bf)) 16638c2ecf20Sopenharmony_ci bf->bf_state.bf_type &= ~BUF_AGGR; 16648c2ecf20Sopenharmony_ci if (bf_tail) 16658c2ecf20Sopenharmony_ci bf_tail->bf_next = bf; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci bf_tail = bf; 16688c2ecf20Sopenharmony_ci nframes--; 16698c2ecf20Sopenharmony_ci sent++; 16708c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_queued_hw); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (an->sta && skb_queue_empty(&tid->retry_q)) 16738c2ecf20Sopenharmony_ci ieee80211_sta_set_buffered(an->sta, i, false); 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, tid->txq); 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (list_empty(&bf_q)) 16798c2ecf20Sopenharmony_ci return; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci if (!more_data) 16828c2ecf20Sopenharmony_ci ath9k_set_moredata(sc, bf_tail, false); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(bf_tail->bf_mpdu); 16858c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STATUS_EOSP; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci bf = list_first_entry(&bf_q, struct ath_buf, list); 16888c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 16898c2ecf20Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, 0); 16908c2ecf20Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, false); 16918c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci/********************/ 16958c2ecf20Sopenharmony_ci/* Queue Management */ 16968c2ecf20Sopenharmony_ci/********************/ 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistruct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 17018c2ecf20Sopenharmony_ci struct ath9k_tx_queue_info qi; 17028c2ecf20Sopenharmony_ci static const int subtype_txq_to_hwq[] = { 17038c2ecf20Sopenharmony_ci [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, 17048c2ecf20Sopenharmony_ci [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, 17058c2ecf20Sopenharmony_ci [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, 17068c2ecf20Sopenharmony_ci [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, 17078c2ecf20Sopenharmony_ci }; 17088c2ecf20Sopenharmony_ci int axq_qnum, i; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci memset(&qi, 0, sizeof(qi)); 17118c2ecf20Sopenharmony_ci qi.tqi_subtype = subtype_txq_to_hwq[subtype]; 17128c2ecf20Sopenharmony_ci qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; 17138c2ecf20Sopenharmony_ci qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; 17148c2ecf20Sopenharmony_ci qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; 17158c2ecf20Sopenharmony_ci qi.tqi_physCompBuf = 0; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci /* 17188c2ecf20Sopenharmony_ci * Enable interrupts only for EOL and DESC conditions. 17198c2ecf20Sopenharmony_ci * We mark tx descriptors to receive a DESC interrupt 17208c2ecf20Sopenharmony_ci * when a tx queue gets deep; otherwise waiting for the 17218c2ecf20Sopenharmony_ci * EOL to reap descriptors. Note that this is done to 17228c2ecf20Sopenharmony_ci * reduce interrupt load and this only defers reaping 17238c2ecf20Sopenharmony_ci * descriptors, never transmitting frames. Aside from 17248c2ecf20Sopenharmony_ci * reducing interrupts this also permits more concurrency. 17258c2ecf20Sopenharmony_ci * The only potential downside is if the tx queue backs 17268c2ecf20Sopenharmony_ci * up in which case the top half of the kernel may backup 17278c2ecf20Sopenharmony_ci * due to a lack of tx descriptors. 17288c2ecf20Sopenharmony_ci * 17298c2ecf20Sopenharmony_ci * The UAPSD queue is an exception, since we take a desc- 17308c2ecf20Sopenharmony_ci * based intr on the EOSP frames. 17318c2ecf20Sopenharmony_ci */ 17328c2ecf20Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 17338c2ecf20Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; 17348c2ecf20Sopenharmony_ci } else { 17358c2ecf20Sopenharmony_ci if (qtype == ATH9K_TX_QUEUE_UAPSD) 17368c2ecf20Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; 17378c2ecf20Sopenharmony_ci else 17388c2ecf20Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | 17398c2ecf20Sopenharmony_ci TXQ_FLAG_TXDESCINT_ENABLE; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); 17428c2ecf20Sopenharmony_ci if (axq_qnum == -1) { 17438c2ecf20Sopenharmony_ci /* 17448c2ecf20Sopenharmony_ci * NB: don't print a message, this happens 17458c2ecf20Sopenharmony_ci * normally on parts with too few tx queues 17468c2ecf20Sopenharmony_ci */ 17478c2ecf20Sopenharmony_ci return NULL; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, axq_qnum)) { 17508c2ecf20Sopenharmony_ci struct ath_txq *txq = &sc->tx.txq[axq_qnum]; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci txq->axq_qnum = axq_qnum; 17538c2ecf20Sopenharmony_ci txq->mac80211_qnum = -1; 17548c2ecf20Sopenharmony_ci txq->axq_link = NULL; 17558c2ecf20Sopenharmony_ci __skb_queue_head_init(&txq->complete_q); 17568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&txq->axq_q); 17578c2ecf20Sopenharmony_ci spin_lock_init(&txq->axq_lock); 17588c2ecf20Sopenharmony_ci txq->axq_depth = 0; 17598c2ecf20Sopenharmony_ci txq->axq_ampdu_depth = 0; 17608c2ecf20Sopenharmony_ci txq->axq_tx_inprogress = false; 17618c2ecf20Sopenharmony_ci sc->tx.txqsetup |= 1<<axq_qnum; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci txq->txq_headidx = txq->txq_tailidx = 0; 17648c2ecf20Sopenharmony_ci for (i = 0; i < ATH_TXFIFO_DEPTH; i++) 17658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&txq->txq_fifo[i]); 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci return &sc->tx.txq[axq_qnum]; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ciint ath_txq_update(struct ath_softc *sc, int qnum, 17718c2ecf20Sopenharmony_ci struct ath9k_tx_queue_info *qinfo) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 17748c2ecf20Sopenharmony_ci int error = 0; 17758c2ecf20Sopenharmony_ci struct ath9k_tx_queue_info qi; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci ath9k_hw_get_txq_props(ah, qnum, &qi); 17808c2ecf20Sopenharmony_ci qi.tqi_aifs = qinfo->tqi_aifs; 17818c2ecf20Sopenharmony_ci qi.tqi_cwmin = qinfo->tqi_cwmin; 17828c2ecf20Sopenharmony_ci qi.tqi_cwmax = qinfo->tqi_cwmax; 17838c2ecf20Sopenharmony_ci qi.tqi_burstTime = qinfo->tqi_burstTime; 17848c2ecf20Sopenharmony_ci qi.tqi_readyTime = qinfo->tqi_readyTime; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 17878c2ecf20Sopenharmony_ci ath_err(ath9k_hw_common(sc->sc_ah), 17888c2ecf20Sopenharmony_ci "Unable to update hardware queue %u!\n", qnum); 17898c2ecf20Sopenharmony_ci error = -EIO; 17908c2ecf20Sopenharmony_ci } else { 17918c2ecf20Sopenharmony_ci ath9k_hw_resettxqueue(ah, qnum); 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci return error; 17958c2ecf20Sopenharmony_ci} 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ciint ath_cabq_update(struct ath_softc *sc) 17988c2ecf20Sopenharmony_ci{ 17998c2ecf20Sopenharmony_ci struct ath9k_tx_queue_info qi; 18008c2ecf20Sopenharmony_ci struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; 18018c2ecf20Sopenharmony_ci int qnum = sc->beacon.cabq->axq_qnum; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * 18068c2ecf20Sopenharmony_ci ATH_CABQ_READY_TIME) / 100; 18078c2ecf20Sopenharmony_ci ath_txq_update(sc, qnum, &qi); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci return 0; 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, 18138c2ecf20Sopenharmony_ci struct list_head *list) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci struct ath_buf *bf, *lastbf; 18168c2ecf20Sopenharmony_ci struct list_head bf_head; 18178c2ecf20Sopenharmony_ci struct ath_tx_status ts; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 18208c2ecf20Sopenharmony_ci ts.ts_status = ATH9K_TX_FLUSH; 18218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci while (!list_empty(list)) { 18248c2ecf20Sopenharmony_ci bf = list_first_entry(list, struct ath_buf, list); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (bf->bf_state.stale) { 18278c2ecf20Sopenharmony_ci list_del(&bf->list); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci ath_tx_return_buffer(sc, bf); 18308c2ecf20Sopenharmony_ci continue; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci lastbf = bf->bf_lastbf; 18348c2ecf20Sopenharmony_ci list_cut_position(&bf_head, list, &lastbf->list); 18358c2ecf20Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci/* 18408c2ecf20Sopenharmony_ci * Drain a given TX queue (could be Beacon or Data) 18418c2ecf20Sopenharmony_ci * 18428c2ecf20Sopenharmony_ci * This assumes output has been stopped and 18438c2ecf20Sopenharmony_ci * we do not need to block ath_tx_tasklet. 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_civoid ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci rcu_read_lock(); 18488c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 18518c2ecf20Sopenharmony_ci int idx = txq->txq_tailidx; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci while (!list_empty(&txq->txq_fifo[idx])) { 18548c2ecf20Sopenharmony_ci ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci INCR(idx, ATH_TXFIFO_DEPTH); 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci txq->txq_tailidx = idx; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci txq->axq_link = NULL; 18628c2ecf20Sopenharmony_ci txq->axq_tx_inprogress = false; 18638c2ecf20Sopenharmony_ci ath_drain_txq_list(sc, txq, &txq->axq_q); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 18668c2ecf20Sopenharmony_ci rcu_read_unlock(); 18678c2ecf20Sopenharmony_ci} 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_cibool ath_drain_all_txq(struct ath_softc *sc) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 18728c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 18738c2ecf20Sopenharmony_ci struct ath_txq *txq; 18748c2ecf20Sopenharmony_ci int i; 18758c2ecf20Sopenharmony_ci u32 npend = 0; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci if (test_bit(ATH_OP_INVALID, &common->op_flags)) 18788c2ecf20Sopenharmony_ci return true; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci ath9k_hw_abort_tx_dma(ah); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* Check if any queue remains active */ 18838c2ecf20Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 18848c2ecf20Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 18858c2ecf20Sopenharmony_ci continue; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (!sc->tx.txq[i].axq_depth) 18888c2ecf20Sopenharmony_ci continue; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum)) 18918c2ecf20Sopenharmony_ci npend |= BIT(i); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (npend) { 18958c2ecf20Sopenharmony_ci RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); 18968c2ecf20Sopenharmony_ci ath_dbg(common, RESET, 18978c2ecf20Sopenharmony_ci "Failed to stop TX DMA, queues=0x%03x!\n", npend); 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 19018c2ecf20Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 19028c2ecf20Sopenharmony_ci continue; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci txq = &sc->tx.txq[i]; 19058c2ecf20Sopenharmony_ci ath_draintxq(sc, txq); 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return !npend; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_civoid ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); 19148c2ecf20Sopenharmony_ci sc->tx.txqsetup &= ~(1<<txq->axq_qnum); 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci/* For each acq entry, for each tid, try to schedule packets 19188c2ecf20Sopenharmony_ci * for transmit until ampdu_depth has reached min Q depth. 19198c2ecf20Sopenharmony_ci */ 19208c2ecf20Sopenharmony_civoid ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 19238c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 19248c2ecf20Sopenharmony_ci struct ieee80211_txq *queue; 19258c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 19268c2ecf20Sopenharmony_ci int ret; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (txq->mac80211_qnum < 0) 19298c2ecf20Sopenharmony_ci return; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 19328c2ecf20Sopenharmony_ci return; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci ieee80211_txq_schedule_start(hw, txq->mac80211_qnum); 19358c2ecf20Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 19368c2ecf20Sopenharmony_ci rcu_read_lock(); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if (sc->cur_chan->stopped) 19398c2ecf20Sopenharmony_ci goto out; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci while ((queue = ieee80211_next_txq(hw, txq->mac80211_qnum))) { 19428c2ecf20Sopenharmony_ci bool force; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci tid = (struct ath_atx_tid *)queue->drv_priv; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci ret = ath_tx_sched_aggr(sc, txq, tid); 19478c2ecf20Sopenharmony_ci ath_dbg(common, QUEUE, "ath_tx_sched_aggr returned %d\n", ret); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci force = !skb_queue_empty(&tid->retry_q); 19508c2ecf20Sopenharmony_ci ieee80211_return_txq(hw, queue, force); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ciout: 19548c2ecf20Sopenharmony_ci rcu_read_unlock(); 19558c2ecf20Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 19568c2ecf20Sopenharmony_ci ieee80211_txq_schedule_end(hw, txq->mac80211_qnum); 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_civoid ath_txq_schedule_all(struct ath_softc *sc) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci struct ath_txq *txq; 19628c2ecf20Sopenharmony_ci int i; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 19658c2ecf20Sopenharmony_ci txq = sc->tx.txq_map[i]; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci spin_lock_bh(&txq->axq_lock); 19688c2ecf20Sopenharmony_ci ath_txq_schedule(sc, txq); 19698c2ecf20Sopenharmony_ci spin_unlock_bh(&txq->axq_lock); 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci/***********/ 19748c2ecf20Sopenharmony_ci/* TX, DMA */ 19758c2ecf20Sopenharmony_ci/***********/ 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci/* 19788c2ecf20Sopenharmony_ci * Insert a chain of ath_buf (descriptors) on a txq and 19798c2ecf20Sopenharmony_ci * assume the descriptors are already chained together by caller. 19808c2ecf20Sopenharmony_ci */ 19818c2ecf20Sopenharmony_cistatic void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, 19828c2ecf20Sopenharmony_ci struct list_head *head, bool internal) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 19858c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 19868c2ecf20Sopenharmony_ci struct ath_buf *bf, *bf_last; 19878c2ecf20Sopenharmony_ci bool puttxbuf = false; 19888c2ecf20Sopenharmony_ci bool edma; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* 19918c2ecf20Sopenharmony_ci * Insert the frame on the outbound list and 19928c2ecf20Sopenharmony_ci * pass it on to the hardware. 19938c2ecf20Sopenharmony_ci */ 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (list_empty(head)) 19968c2ecf20Sopenharmony_ci return; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); 19998c2ecf20Sopenharmony_ci bf = list_first_entry(head, struct ath_buf, list); 20008c2ecf20Sopenharmony_ci bf_last = list_entry(head->prev, struct ath_buf, list); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci ath_dbg(common, QUEUE, "qnum: %d, txq depth: %d\n", 20038c2ecf20Sopenharmony_ci txq->axq_qnum, txq->axq_depth); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) { 20068c2ecf20Sopenharmony_ci list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]); 20078c2ecf20Sopenharmony_ci INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); 20088c2ecf20Sopenharmony_ci puttxbuf = true; 20098c2ecf20Sopenharmony_ci } else { 20108c2ecf20Sopenharmony_ci list_splice_tail_init(head, &txq->axq_q); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (txq->axq_link) { 20138c2ecf20Sopenharmony_ci ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr); 20148c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "link[%u] (%p)=%llx (%p)\n", 20158c2ecf20Sopenharmony_ci txq->axq_qnum, txq->axq_link, 20168c2ecf20Sopenharmony_ci ito64(bf->bf_daddr), bf->bf_desc); 20178c2ecf20Sopenharmony_ci } else if (!edma) 20188c2ecf20Sopenharmony_ci puttxbuf = true; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci txq->axq_link = bf_last->bf_desc; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci if (puttxbuf) { 20248c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, puttxbuf); 20258c2ecf20Sopenharmony_ci ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 20268c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n", 20278c2ecf20Sopenharmony_ci txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (!edma || sc->tx99_state) { 20318c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txstart); 20328c2ecf20Sopenharmony_ci ath9k_hw_txstart(ah, txq->axq_qnum); 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (!internal) { 20368c2ecf20Sopenharmony_ci while (bf) { 20378c2ecf20Sopenharmony_ci txq->axq_depth++; 20388c2ecf20Sopenharmony_ci if (bf_is_ampdu_not_probing(bf)) 20398c2ecf20Sopenharmony_ci txq->axq_ampdu_depth++; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci bf_last = bf->bf_lastbf; 20428c2ecf20Sopenharmony_ci bf = bf_last->bf_next; 20438c2ecf20Sopenharmony_ci bf_last->bf_next = NULL; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_cistatic void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, 20498c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, struct sk_buff *skb) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 20528c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 20538c2ecf20Sopenharmony_ci struct list_head bf_head; 20548c2ecf20Sopenharmony_ci struct ath_buf *bf = fi->bf; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 20578c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 20588c2ecf20Sopenharmony_ci bf->bf_state.bf_type = 0; 20598c2ecf20Sopenharmony_ci if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { 20608c2ecf20Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU; 20618c2ecf20Sopenharmony_ci ath_tx_addto_baw(sc, tid, bf); 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci bf->bf_next = NULL; 20658c2ecf20Sopenharmony_ci bf->bf_lastbf = bf; 20668c2ecf20Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, fi->framelen); 20678c2ecf20Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_head, false); 20688c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, queued); 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_cistatic void setup_frame_info(struct ieee80211_hw *hw, 20728c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 20738c2ecf20Sopenharmony_ci struct sk_buff *skb, 20748c2ecf20Sopenharmony_ci int framelen) 20758c2ecf20Sopenharmony_ci{ 20768c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 20778c2ecf20Sopenharmony_ci struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; 20788c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 20798c2ecf20Sopenharmony_ci const struct ieee80211_rate *rate; 20808c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 20818c2ecf20Sopenharmony_ci struct ath_node *an = NULL; 20828c2ecf20Sopenharmony_ci enum ath9k_key_type keytype; 20838c2ecf20Sopenharmony_ci bool short_preamble = false; 20848c2ecf20Sopenharmony_ci u8 txpower; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* 20878c2ecf20Sopenharmony_ci * We check if Short Preamble is needed for the CTS rate by 20888c2ecf20Sopenharmony_ci * checking the BSS's global flag. 20898c2ecf20Sopenharmony_ci * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_ci if (tx_info->control.vif && 20928c2ecf20Sopenharmony_ci tx_info->control.vif->bss_conf.use_short_preamble) 20938c2ecf20Sopenharmony_ci short_preamble = true; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci rate = ieee80211_get_rts_cts_rate(hw, tx_info); 20968c2ecf20Sopenharmony_ci keytype = ath9k_cmn_get_hw_crypto_keytype(skb); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (sta) 20998c2ecf20Sopenharmony_ci an = (struct ath_node *) sta->drv_priv; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (tx_info->control.vif) { 21028c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = tx_info->control.vif; 21038c2ecf20Sopenharmony_ci if (vif->bss_conf.txpower == INT_MIN) 21048c2ecf20Sopenharmony_ci goto nonvifpower; 21058c2ecf20Sopenharmony_ci txpower = 2 * vif->bss_conf.txpower; 21068c2ecf20Sopenharmony_ci } else { 21078c2ecf20Sopenharmony_ci struct ath_softc *sc; 21088c2ecf20Sopenharmony_ci nonvifpower: 21098c2ecf20Sopenharmony_ci sc = hw->priv; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci txpower = sc->cur_chan->cur_txpower; 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci memset(fi, 0, sizeof(*fi)); 21158c2ecf20Sopenharmony_ci fi->txq = -1; 21168c2ecf20Sopenharmony_ci if (hw_key) 21178c2ecf20Sopenharmony_ci fi->keyix = hw_key->hw_key_idx; 21188c2ecf20Sopenharmony_ci else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) 21198c2ecf20Sopenharmony_ci fi->keyix = an->ps_key; 21208c2ecf20Sopenharmony_ci else 21218c2ecf20Sopenharmony_ci fi->keyix = ATH9K_TXKEYIX_INVALID; 21228c2ecf20Sopenharmony_ci fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC; 21238c2ecf20Sopenharmony_ci fi->keytype = keytype; 21248c2ecf20Sopenharmony_ci fi->framelen = framelen; 21258c2ecf20Sopenharmony_ci fi->tx_power = txpower; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci if (!rate) 21288c2ecf20Sopenharmony_ci return; 21298c2ecf20Sopenharmony_ci fi->rtscts_rate = rate->hw_value; 21308c2ecf20Sopenharmony_ci if (short_preamble) 21318c2ecf20Sopenharmony_ci fi->rtscts_rate |= rate->hw_value_short; 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ciu8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) 21358c2ecf20Sopenharmony_ci{ 21368c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 21378c2ecf20Sopenharmony_ci struct ath9k_channel *curchan = ah->curchan; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && IS_CHAN_5GHZ(curchan) && 21408c2ecf20Sopenharmony_ci (chainmask == 0x7) && (rate < 0x90)) 21418c2ecf20Sopenharmony_ci return 0x3; 21428c2ecf20Sopenharmony_ci else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) && 21438c2ecf20Sopenharmony_ci IS_CCK_RATE(rate)) 21448c2ecf20Sopenharmony_ci return 0x2; 21458c2ecf20Sopenharmony_ci else 21468c2ecf20Sopenharmony_ci return chainmask; 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci/* 21508c2ecf20Sopenharmony_ci * Assign a descriptor (and sequence number if necessary, 21518c2ecf20Sopenharmony_ci * and map buffer for DMA. Frees skb on error 21528c2ecf20Sopenharmony_ci */ 21538c2ecf20Sopenharmony_cistatic struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, 21548c2ecf20Sopenharmony_ci struct ath_txq *txq, 21558c2ecf20Sopenharmony_ci struct ath_atx_tid *tid, 21568c2ecf20Sopenharmony_ci struct sk_buff *skb) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 21598c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 21608c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 21618c2ecf20Sopenharmony_ci struct ath_buf *bf; 21628c2ecf20Sopenharmony_ci int fragno; 21638c2ecf20Sopenharmony_ci u16 seqno; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci bf = ath_tx_get_buffer(sc); 21668c2ecf20Sopenharmony_ci if (!bf) { 21678c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "TX buffers are full\n"); 21688c2ecf20Sopenharmony_ci return NULL; 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci ATH_TXBUF_RESET(bf); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (tid && ieee80211_is_data_present(hdr->frame_control)) { 21748c2ecf20Sopenharmony_ci fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; 21758c2ecf20Sopenharmony_ci seqno = tid->seq_next; 21768c2ecf20Sopenharmony_ci hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci if (fragno) 21798c2ecf20Sopenharmony_ci hdr->seq_ctrl |= cpu_to_le16(fragno); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (!ieee80211_has_morefrags(hdr->frame_control)) 21828c2ecf20Sopenharmony_ci INCR(tid->seq_next, IEEE80211_SEQ_MAX); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci bf->bf_state.seqno = seqno; 21858c2ecf20Sopenharmony_ci } 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci bf->bf_mpdu = skb; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, 21908c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 21918c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 21928c2ecf20Sopenharmony_ci bf->bf_mpdu = NULL; 21938c2ecf20Sopenharmony_ci bf->bf_buf_addr = 0; 21948c2ecf20Sopenharmony_ci ath_err(ath9k_hw_common(sc->sc_ah), 21958c2ecf20Sopenharmony_ci "dma_mapping_error() on TX\n"); 21968c2ecf20Sopenharmony_ci ath_tx_return_buffer(sc, bf); 21978c2ecf20Sopenharmony_ci return NULL; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci fi->bf = bf; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci return bf; 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_civoid ath_assign_seq(struct ath_common *common, struct sk_buff *skb) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 22088c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 22098c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 22108c2ecf20Sopenharmony_ci struct ath_vif *avp; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) 22138c2ecf20Sopenharmony_ci return; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci if (!vif) 22168c2ecf20Sopenharmony_ci return; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci avp = (struct ath_vif *)vif->drv_priv; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) 22218c2ecf20Sopenharmony_ci avp->seq_no += 0x10; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 22248c2ecf20Sopenharmony_ci hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); 22258c2ecf20Sopenharmony_ci} 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_cistatic int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, 22288c2ecf20Sopenharmony_ci struct ath_tx_control *txctl) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 22318c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 22328c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = txctl->sta; 22338c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 22348c2ecf20Sopenharmony_ci struct ath_vif *avp; 22358c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 22368c2ecf20Sopenharmony_ci int frmlen = skb->len + FCS_LEN; 22378c2ecf20Sopenharmony_ci int padpos, padsize; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci /* NOTE: sta can be NULL according to net/mac80211.h */ 22408c2ecf20Sopenharmony_ci if (sta) 22418c2ecf20Sopenharmony_ci txctl->an = (struct ath_node *)sta->drv_priv; 22428c2ecf20Sopenharmony_ci else if (vif && ieee80211_is_data(hdr->frame_control)) { 22438c2ecf20Sopenharmony_ci avp = (void *)vif->drv_priv; 22448c2ecf20Sopenharmony_ci txctl->an = &avp->mcast_node; 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci if (info->control.hw_key) 22488c2ecf20Sopenharmony_ci frmlen += info->control.hw_key->icv_len; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb); 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci if ((vif && vif->type != NL80211_IFTYPE_AP && 22538c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_AP_VLAN) || 22548c2ecf20Sopenharmony_ci !ieee80211_is_data(hdr->frame_control)) 22558c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci /* Add the padding after the header if this is not already done */ 22588c2ecf20Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 22598c2ecf20Sopenharmony_ci padsize = padpos & 3; 22608c2ecf20Sopenharmony_ci if (padsize && skb->len > padpos) { 22618c2ecf20Sopenharmony_ci if (skb_headroom(skb) < padsize) 22628c2ecf20Sopenharmony_ci return -ENOMEM; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci skb_push(skb, padsize); 22658c2ecf20Sopenharmony_ci memmove(skb->data, skb->data + padsize, padpos); 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci setup_frame_info(hw, sta, skb, frmlen); 22698c2ecf20Sopenharmony_ci return 0; 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci/* Upon failure caller should free skb */ 22748c2ecf20Sopenharmony_ciint ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, 22758c2ecf20Sopenharmony_ci struct ath_tx_control *txctl) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 22788c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = txctl->sta; 22798c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 22808c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 22818c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 22828c2ecf20Sopenharmony_ci struct ath_txq *txq = txctl->txq; 22838c2ecf20Sopenharmony_ci struct ath_atx_tid *tid = NULL; 22848c2ecf20Sopenharmony_ci struct ath_node *an = NULL; 22858c2ecf20Sopenharmony_ci struct ath_buf *bf; 22868c2ecf20Sopenharmony_ci bool ps_resp; 22878c2ecf20Sopenharmony_ci int q, ret; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci ret = ath_tx_prepare(hw, skb, txctl); 22928c2ecf20Sopenharmony_ci if (ret) 22938c2ecf20Sopenharmony_ci return ret; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci /* 22968c2ecf20Sopenharmony_ci * At this point, the vif, hw_key and sta pointers in the tx control 22978c2ecf20Sopenharmony_ci * info are no longer valid (overwritten by the ath_frame_info data. 22988c2ecf20Sopenharmony_ci */ 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci q = skb_get_queue_mapping(skb); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci if (ps_resp) 23038c2ecf20Sopenharmony_ci txq = sc->tx.uapsdq; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (txctl->sta) { 23068c2ecf20Sopenharmony_ci an = (struct ath_node *) sta->drv_priv; 23078c2ecf20Sopenharmony_ci tid = ath_get_skb_tid(sc, an, skb); 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 23118c2ecf20Sopenharmony_ci if (txq == sc->tx.txq_map[q]) { 23128c2ecf20Sopenharmony_ci fi->txq = q; 23138c2ecf20Sopenharmony_ci ++txq->pending_frames; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txq, tid, skb); 23178c2ecf20Sopenharmony_ci if (!bf) { 23188c2ecf20Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 23198c2ecf20Sopenharmony_ci if (txctl->paprd) 23208c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 23218c2ecf20Sopenharmony_ci else 23228c2ecf20Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 23238c2ecf20Sopenharmony_ci goto out; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci bf->bf_state.bfs_paprd = txctl->paprd; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci if (txctl->paprd) 23298c2ecf20Sopenharmony_ci bf->bf_state.bfs_paprd_timestamp = jiffies; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci ath_set_rates(vif, sta, bf); 23328c2ecf20Sopenharmony_ci ath_tx_send_normal(sc, txq, tid, skb); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ciout: 23358c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci return 0; 23388c2ecf20Sopenharmony_ci} 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_civoid ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 23418c2ecf20Sopenharmony_ci struct sk_buff *skb) 23428c2ecf20Sopenharmony_ci{ 23438c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 23448c2ecf20Sopenharmony_ci struct ath_tx_control txctl = { 23458c2ecf20Sopenharmony_ci .txq = sc->beacon.cabq 23468c2ecf20Sopenharmony_ci }; 23478c2ecf20Sopenharmony_ci struct ath_tx_info info = {}; 23488c2ecf20Sopenharmony_ci struct ath_buf *bf_tail = NULL; 23498c2ecf20Sopenharmony_ci struct ath_buf *bf; 23508c2ecf20Sopenharmony_ci LIST_HEAD(bf_q); 23518c2ecf20Sopenharmony_ci int duration = 0; 23528c2ecf20Sopenharmony_ci int max_duration; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci max_duration = 23558c2ecf20Sopenharmony_ci sc->cur_chan->beacon.beacon_interval * 1000 * 23568c2ecf20Sopenharmony_ci sc->cur_chan->beacon.dtim_period / ATH_BCBUF; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci do { 23598c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (ath_tx_prepare(hw, skb, &txctl)) 23628c2ecf20Sopenharmony_ci break; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txctl.txq, NULL, skb); 23658c2ecf20Sopenharmony_ci if (!bf) 23668c2ecf20Sopenharmony_ci break; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci bf->bf_lastbf = bf; 23698c2ecf20Sopenharmony_ci ath_set_rates(vif, NULL, bf); 23708c2ecf20Sopenharmony_ci ath_buf_set_rate(sc, bf, &info, fi->framelen, false); 23718c2ecf20Sopenharmony_ci duration += info.rates[0].PktDuration; 23728c2ecf20Sopenharmony_ci if (bf_tail) 23738c2ecf20Sopenharmony_ci bf_tail->bf_next = bf; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci list_add_tail(&bf->list, &bf_q); 23768c2ecf20Sopenharmony_ci bf_tail = bf; 23778c2ecf20Sopenharmony_ci skb = NULL; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (duration > max_duration) 23808c2ecf20Sopenharmony_ci break; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci skb = ieee80211_get_buffered_bc(hw, vif); 23838c2ecf20Sopenharmony_ci } while(skb); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci if (skb) 23868c2ecf20Sopenharmony_ci ieee80211_free_txskb(hw, skb); 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci if (list_empty(&bf_q)) 23898c2ecf20Sopenharmony_ci return; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci bf = list_last_entry(&bf_q, struct ath_buf, list); 23928c2ecf20Sopenharmony_ci ath9k_set_moredata(sc, bf, false); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci bf = list_first_entry(&bf_q, struct ath_buf, list); 23958c2ecf20Sopenharmony_ci ath_txq_lock(sc, txctl.txq); 23968c2ecf20Sopenharmony_ci ath_tx_fill_desc(sc, bf, txctl.txq, 0); 23978c2ecf20Sopenharmony_ci ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false); 23988c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txctl.txq->axq_qnum, queued); 23998c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txctl.txq); 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci/*****************/ 24038c2ecf20Sopenharmony_ci/* TX Completion */ 24048c2ecf20Sopenharmony_ci/*****************/ 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_cistatic void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, 24078c2ecf20Sopenharmony_ci int tx_flags, struct ath_txq *txq, 24088c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 24098c2ecf20Sopenharmony_ci{ 24108c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 24118c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 24128c2ecf20Sopenharmony_ci struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; 24138c2ecf20Sopenharmony_ci int padpos, padsize; 24148c2ecf20Sopenharmony_ci unsigned long flags; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if (sc->sc_ah->caldata) 24198c2ecf20Sopenharmony_ci set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (!(tx_flags & ATH_TX_ERROR)) { 24228c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) 24238c2ecf20Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 24248c2ecf20Sopenharmony_ci else 24258c2ecf20Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_ACK; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 24298c2ecf20Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 24308c2ecf20Sopenharmony_ci padsize = padpos & 3; 24318c2ecf20Sopenharmony_ci if (padsize && skb->len>padpos+padsize) { 24328c2ecf20Sopenharmony_ci /* 24338c2ecf20Sopenharmony_ci * Remove MAC header padding before giving the frame back to 24348c2ecf20Sopenharmony_ci * mac80211. 24358c2ecf20Sopenharmony_ci */ 24368c2ecf20Sopenharmony_ci memmove(skb->data + padsize, skb->data, padpos); 24378c2ecf20Sopenharmony_ci skb_pull(skb, padsize); 24388c2ecf20Sopenharmony_ci } 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 24428c2ecf20Sopenharmony_ci if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { 24438c2ecf20Sopenharmony_ci sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; 24448c2ecf20Sopenharmony_ci ath_dbg(common, PS, 24458c2ecf20Sopenharmony_ci "Going back to sleep after having received TX status (0x%lx)\n", 24468c2ecf20Sopenharmony_ci sc->ps_flags & (PS_WAIT_FOR_BEACON | 24478c2ecf20Sopenharmony_ci PS_WAIT_FOR_CAB | 24488c2ecf20Sopenharmony_ci PS_WAIT_FOR_PSPOLL_DATA | 24498c2ecf20Sopenharmony_ci PS_WAIT_FOR_TX_ACK)); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 24548c2ecf20Sopenharmony_ci tx_info->status.status_driver_data[0] = sta; 24558c2ecf20Sopenharmony_ci __skb_queue_tail(&txq->complete_q, skb); 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cistatic void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 24598c2ecf20Sopenharmony_ci struct ath_txq *txq, struct list_head *bf_q, 24608c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 24618c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int txok) 24628c2ecf20Sopenharmony_ci{ 24638c2ecf20Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 24648c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 24658c2ecf20Sopenharmony_ci unsigned long flags; 24668c2ecf20Sopenharmony_ci int tx_flags = 0; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci if (!txok) 24698c2ecf20Sopenharmony_ci tx_flags |= ATH_TX_ERROR; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci if (ts->ts_status & ATH9K_TXERR_FILT) 24728c2ecf20Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); 24758c2ecf20Sopenharmony_ci bf->bf_buf_addr = 0; 24768c2ecf20Sopenharmony_ci if (sc->tx99_state) 24778c2ecf20Sopenharmony_ci goto skip_tx_complete; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (bf->bf_state.bfs_paprd) { 24808c2ecf20Sopenharmony_ci if (time_after(jiffies, 24818c2ecf20Sopenharmony_ci bf->bf_state.bfs_paprd_timestamp + 24828c2ecf20Sopenharmony_ci msecs_to_jiffies(ATH_PAPRD_TIMEOUT))) 24838c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 24848c2ecf20Sopenharmony_ci else 24858c2ecf20Sopenharmony_ci complete(&sc->paprd_complete); 24868c2ecf20Sopenharmony_ci } else { 24878c2ecf20Sopenharmony_ci ath_debug_stat_tx(sc, bf, ts, txq, tx_flags); 24888c2ecf20Sopenharmony_ci ath_tx_complete(sc, skb, tx_flags, txq, sta); 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ciskip_tx_complete: 24918c2ecf20Sopenharmony_ci /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't 24928c2ecf20Sopenharmony_ci * accidentally reference it later. 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_ci bf->bf_mpdu = NULL; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci /* 24978c2ecf20Sopenharmony_ci * Return the list of ath_buf of this mpdu to free queue 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->tx.txbuflock, flags); 25008c2ecf20Sopenharmony_ci list_splice_tail_init(bf_q, &sc->tx.txbuf); 25018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->tx.txbuflock, flags); 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_cistatic void ath_clear_tx_status(struct ieee80211_tx_info *tx_info) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci void *ptr = &tx_info->status; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci memset(ptr + sizeof(tx_info->status.rates), 0, 25098c2ecf20Sopenharmony_ci sizeof(tx_info->status) - 25108c2ecf20Sopenharmony_ci sizeof(tx_info->status.rates) - 25118c2ecf20Sopenharmony_ci sizeof(tx_info->status.status_driver_data)); 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_cistatic void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, 25158c2ecf20Sopenharmony_ci struct ath_tx_status *ts, int nframes, int nbad, 25168c2ecf20Sopenharmony_ci int txok) 25178c2ecf20Sopenharmony_ci{ 25188c2ecf20Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 25198c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 25208c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 25218c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 25228c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 25238c2ecf20Sopenharmony_ci u8 i, tx_rateindex; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci ath_clear_tx_status(tx_info); 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci if (txok) 25288c2ecf20Sopenharmony_ci tx_info->status.ack_signal = ts->ts_rssi; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci tx_rateindex = ts->ts_rateindex; 25318c2ecf20Sopenharmony_ci WARN_ON(tx_rateindex >= hw->max_rates); 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 25348c2ecf20Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_AMPDU; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci BUG_ON(nbad > nframes); 25378c2ecf20Sopenharmony_ci } 25388c2ecf20Sopenharmony_ci tx_info->status.ampdu_len = nframes; 25398c2ecf20Sopenharmony_ci tx_info->status.ampdu_ack_len = nframes - nbad; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci for (i = tx_rateindex + 1; i < hw->max_rates; i++) { 25448c2ecf20Sopenharmony_ci tx_info->status.rates[i].count = 0; 25458c2ecf20Sopenharmony_ci tx_info->status.rates[i].idx = -1; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && 25498c2ecf20Sopenharmony_ci (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { 25508c2ecf20Sopenharmony_ci /* 25518c2ecf20Sopenharmony_ci * If an underrun error is seen assume it as an excessive 25528c2ecf20Sopenharmony_ci * retry only if max frame trigger level has been reached 25538c2ecf20Sopenharmony_ci * (2 KB for single stream, and 4 KB for dual stream). 25548c2ecf20Sopenharmony_ci * Adjust the long retry as if the frame was tried 25558c2ecf20Sopenharmony_ci * hw->max_rate_tries times to affect how rate control updates 25568c2ecf20Sopenharmony_ci * PER for the failed rate. 25578c2ecf20Sopenharmony_ci * In case of congestion on the bus penalizing this type of 25588c2ecf20Sopenharmony_ci * underruns should help hardware actually transmit new frames 25598c2ecf20Sopenharmony_ci * successfully by eventually preferring slower rates. 25608c2ecf20Sopenharmony_ci * This itself should also alleviate congestion on the bus. 25618c2ecf20Sopenharmony_ci */ 25628c2ecf20Sopenharmony_ci if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | 25638c2ecf20Sopenharmony_ci ATH9K_TX_DELIM_UNDERRUN)) && 25648c2ecf20Sopenharmony_ci ieee80211_is_data(hdr->frame_control) && 25658c2ecf20Sopenharmony_ci ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) 25668c2ecf20Sopenharmony_ci tx_info->status.rates[tx_rateindex].count = 25678c2ecf20Sopenharmony_ci hw->max_rate_tries; 25688c2ecf20Sopenharmony_ci } 25698c2ecf20Sopenharmony_ci} 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_cistatic void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) 25728c2ecf20Sopenharmony_ci{ 25738c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 25748c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 25758c2ecf20Sopenharmony_ci struct ath_buf *bf, *lastbf, *bf_held = NULL; 25768c2ecf20Sopenharmony_ci struct list_head bf_head; 25778c2ecf20Sopenharmony_ci struct ath_desc *ds; 25788c2ecf20Sopenharmony_ci struct ath_tx_status ts; 25798c2ecf20Sopenharmony_ci int status; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci ath_dbg(common, QUEUE, "tx queue %d (%x), link %p\n", 25828c2ecf20Sopenharmony_ci txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), 25838c2ecf20Sopenharmony_ci txq->axq_link); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 25868c2ecf20Sopenharmony_ci for (;;) { 25878c2ecf20Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 25888c2ecf20Sopenharmony_ci break; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci if (list_empty(&txq->axq_q)) { 25918c2ecf20Sopenharmony_ci txq->axq_link = NULL; 25928c2ecf20Sopenharmony_ci ath_txq_schedule(sc, txq); 25938c2ecf20Sopenharmony_ci break; 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci bf = list_first_entry(&txq->axq_q, struct ath_buf, list); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci /* 25988c2ecf20Sopenharmony_ci * There is a race condition that a BH gets scheduled 25998c2ecf20Sopenharmony_ci * after sw writes TxE and before hw re-load the last 26008c2ecf20Sopenharmony_ci * descriptor to get the newly chained one. 26018c2ecf20Sopenharmony_ci * Software must keep the last DONE descriptor as a 26028c2ecf20Sopenharmony_ci * holding descriptor - software does so by marking 26038c2ecf20Sopenharmony_ci * it with the STALE flag. 26048c2ecf20Sopenharmony_ci */ 26058c2ecf20Sopenharmony_ci bf_held = NULL; 26068c2ecf20Sopenharmony_ci if (bf->bf_state.stale) { 26078c2ecf20Sopenharmony_ci bf_held = bf; 26088c2ecf20Sopenharmony_ci if (list_is_last(&bf_held->list, &txq->axq_q)) 26098c2ecf20Sopenharmony_ci break; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci bf = list_entry(bf_held->list.next, struct ath_buf, 26128c2ecf20Sopenharmony_ci list); 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci lastbf = bf->bf_lastbf; 26168c2ecf20Sopenharmony_ci ds = lastbf->bf_desc; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 26198c2ecf20Sopenharmony_ci status = ath9k_hw_txprocdesc(ah, ds, &ts); 26208c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 26218c2ecf20Sopenharmony_ci break; 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci /* 26268c2ecf20Sopenharmony_ci * Remove ath_buf's of the same transmit unit from txq, 26278c2ecf20Sopenharmony_ci * however leave the last descriptor back as the holding 26288c2ecf20Sopenharmony_ci * descriptor for hw. 26298c2ecf20Sopenharmony_ci */ 26308c2ecf20Sopenharmony_ci lastbf->bf_state.stale = true; 26318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 26328c2ecf20Sopenharmony_ci if (!list_is_singular(&lastbf->list)) 26338c2ecf20Sopenharmony_ci list_cut_position(&bf_head, 26348c2ecf20Sopenharmony_ci &txq->axq_q, lastbf->list.prev); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci if (bf_held) { 26378c2ecf20Sopenharmony_ci list_del(&bf_held->list); 26388c2ecf20Sopenharmony_ci ath_tx_return_buffer(sc, bf_held); 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 26448c2ecf20Sopenharmony_ci} 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_civoid ath_tx_tasklet(struct ath_softc *sc) 26478c2ecf20Sopenharmony_ci{ 26488c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 26498c2ecf20Sopenharmony_ci u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; 26508c2ecf20Sopenharmony_ci int i; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci rcu_read_lock(); 26538c2ecf20Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 26548c2ecf20Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) 26558c2ecf20Sopenharmony_ci ath_tx_processq(sc, &sc->tx.txq[i]); 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci rcu_read_unlock(); 26588c2ecf20Sopenharmony_ci} 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_civoid ath_tx_edma_tasklet(struct ath_softc *sc) 26618c2ecf20Sopenharmony_ci{ 26628c2ecf20Sopenharmony_ci struct ath_tx_status ts; 26638c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 26648c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 26658c2ecf20Sopenharmony_ci struct ath_txq *txq; 26668c2ecf20Sopenharmony_ci struct ath_buf *bf, *lastbf; 26678c2ecf20Sopenharmony_ci struct list_head bf_head; 26688c2ecf20Sopenharmony_ci struct list_head *fifo_list; 26698c2ecf20Sopenharmony_ci int status; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci rcu_read_lock(); 26728c2ecf20Sopenharmony_ci for (;;) { 26738c2ecf20Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 26748c2ecf20Sopenharmony_ci break; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); 26778c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 26788c2ecf20Sopenharmony_ci break; 26798c2ecf20Sopenharmony_ci if (status == -EIO) { 26808c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "Error processing tx status\n"); 26818c2ecf20Sopenharmony_ci break; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci /* Process beacon completions separately */ 26858c2ecf20Sopenharmony_ci if (ts.qid == sc->beacon.beaconq) { 26868c2ecf20Sopenharmony_ci sc->beacon.tx_processed = true; 26878c2ecf20Sopenharmony_ci sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 26908c2ecf20Sopenharmony_ci ath_chanctx_event(sc, NULL, 26918c2ecf20Sopenharmony_ci ATH_CHANCTX_EVENT_BEACON_SENT); 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci ath9k_csa_update(sc); 26958c2ecf20Sopenharmony_ci continue; 26968c2ecf20Sopenharmony_ci } 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci txq = &sc->tx.txq[ts.qid]; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci fifo_list = &txq->txq_fifo[txq->txq_tailidx]; 27058c2ecf20Sopenharmony_ci if (list_empty(fifo_list)) { 27068c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 27078c2ecf20Sopenharmony_ci break; 27088c2ecf20Sopenharmony_ci } 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci bf = list_first_entry(fifo_list, struct ath_buf, list); 27118c2ecf20Sopenharmony_ci if (bf->bf_state.stale) { 27128c2ecf20Sopenharmony_ci list_del(&bf->list); 27138c2ecf20Sopenharmony_ci ath_tx_return_buffer(sc, bf); 27148c2ecf20Sopenharmony_ci bf = list_first_entry(fifo_list, struct ath_buf, list); 27158c2ecf20Sopenharmony_ci } 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci lastbf = bf->bf_lastbf; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 27208c2ecf20Sopenharmony_ci if (list_is_last(&lastbf->list, fifo_list)) { 27218c2ecf20Sopenharmony_ci list_splice_tail_init(fifo_list, &bf_head); 27228c2ecf20Sopenharmony_ci INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci if (!list_empty(&txq->axq_q)) { 27258c2ecf20Sopenharmony_ci struct list_head bf_q; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 27288c2ecf20Sopenharmony_ci txq->axq_link = NULL; 27298c2ecf20Sopenharmony_ci list_splice_tail_init(&txq->axq_q, &bf_q); 27308c2ecf20Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, true); 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci } else { 27338c2ecf20Sopenharmony_ci lastbf->bf_state.stale = true; 27348c2ecf20Sopenharmony_ci if (bf != lastbf) 27358c2ecf20Sopenharmony_ci list_cut_position(&bf_head, fifo_list, 27368c2ecf20Sopenharmony_ci lastbf->list.prev); 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 27408c2ecf20Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci rcu_read_unlock(); 27438c2ecf20Sopenharmony_ci} 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci/*****************/ 27468c2ecf20Sopenharmony_ci/* Init, Cleanup */ 27478c2ecf20Sopenharmony_ci/*****************/ 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_cistatic int ath_txstatus_setup(struct ath_softc *sc, int size) 27508c2ecf20Sopenharmony_ci{ 27518c2ecf20Sopenharmony_ci struct ath_descdma *dd = &sc->txsdma; 27528c2ecf20Sopenharmony_ci u8 txs_len = sc->sc_ah->caps.txs_len; 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci dd->dd_desc_len = size * txs_len; 27558c2ecf20Sopenharmony_ci dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, 27568c2ecf20Sopenharmony_ci &dd->dd_desc_paddr, GFP_KERNEL); 27578c2ecf20Sopenharmony_ci if (!dd->dd_desc) 27588c2ecf20Sopenharmony_ci return -ENOMEM; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci return 0; 27618c2ecf20Sopenharmony_ci} 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_cistatic int ath_tx_edma_init(struct ath_softc *sc) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci int err; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE); 27688c2ecf20Sopenharmony_ci if (!err) 27698c2ecf20Sopenharmony_ci ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc, 27708c2ecf20Sopenharmony_ci sc->txsdma.dd_desc_paddr, 27718c2ecf20Sopenharmony_ci ATH_TXSTATUS_RING_SIZE); 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci return err; 27748c2ecf20Sopenharmony_ci} 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ciint ath_tx_init(struct ath_softc *sc, int nbufs) 27778c2ecf20Sopenharmony_ci{ 27788c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 27798c2ecf20Sopenharmony_ci int error = 0; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci spin_lock_init(&sc->tx.txbuflock); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, 27848c2ecf20Sopenharmony_ci "tx", nbufs, 1, 1); 27858c2ecf20Sopenharmony_ci if (error != 0) { 27868c2ecf20Sopenharmony_ci ath_err(common, 27878c2ecf20Sopenharmony_ci "Failed to allocate tx descriptors: %d\n", error); 27888c2ecf20Sopenharmony_ci return error; 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, 27928c2ecf20Sopenharmony_ci "beacon", ATH_BCBUF, 1, 1); 27938c2ecf20Sopenharmony_ci if (error != 0) { 27948c2ecf20Sopenharmony_ci ath_err(common, 27958c2ecf20Sopenharmony_ci "Failed to allocate beacon descriptors: %d\n", error); 27968c2ecf20Sopenharmony_ci return error; 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) 28008c2ecf20Sopenharmony_ci error = ath_tx_edma_init(sc); 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci return error; 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_civoid ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) 28068c2ecf20Sopenharmony_ci{ 28078c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 28088c2ecf20Sopenharmony_ci int tidno, acno; 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 28118c2ecf20Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 28128c2ecf20Sopenharmony_ci tid->an = an; 28138c2ecf20Sopenharmony_ci tid->tidno = tidno; 28148c2ecf20Sopenharmony_ci tid->seq_start = tid->seq_next = 0; 28158c2ecf20Sopenharmony_ci tid->baw_size = WME_MAX_BA; 28168c2ecf20Sopenharmony_ci tid->baw_head = tid->baw_tail = 0; 28178c2ecf20Sopenharmony_ci tid->active = false; 28188c2ecf20Sopenharmony_ci tid->clear_ps_filter = true; 28198c2ecf20Sopenharmony_ci __skb_queue_head_init(&tid->retry_q); 28208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tid->list); 28218c2ecf20Sopenharmony_ci acno = TID_TO_WME_AC(tidno); 28228c2ecf20Sopenharmony_ci tid->txq = sc->tx.txq_map[acno]; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci if (!an->sta) 28258c2ecf20Sopenharmony_ci break; /* just one multicast ath_atx_tid */ 28268c2ecf20Sopenharmony_ci } 28278c2ecf20Sopenharmony_ci} 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_civoid ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) 28308c2ecf20Sopenharmony_ci{ 28318c2ecf20Sopenharmony_ci struct ath_atx_tid *tid; 28328c2ecf20Sopenharmony_ci struct ath_txq *txq; 28338c2ecf20Sopenharmony_ci int tidno; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci rcu_read_lock(); 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 28388c2ecf20Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 28398c2ecf20Sopenharmony_ci txq = tid->txq; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci ath_txq_lock(sc, txq); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci if (!list_empty(&tid->list)) 28448c2ecf20Sopenharmony_ci list_del_init(&tid->list); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci ath_tid_drain(sc, txq, tid); 28478c2ecf20Sopenharmony_ci tid->active = false; 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci ath_txq_unlock(sc, txq); 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci if (!an->sta) 28528c2ecf20Sopenharmony_ci break; /* just one multicast ath_atx_tid */ 28538c2ecf20Sopenharmony_ci } 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci rcu_read_unlock(); 28568c2ecf20Sopenharmony_ci} 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_TX99 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ciint ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, 28618c2ecf20Sopenharmony_ci struct ath_tx_control *txctl) 28628c2ecf20Sopenharmony_ci{ 28638c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 28648c2ecf20Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 28658c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 28668c2ecf20Sopenharmony_ci struct ath_buf *bf; 28678c2ecf20Sopenharmony_ci int padpos, padsize; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 28708c2ecf20Sopenharmony_ci padsize = padpos & 3; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci if (padsize && skb->len > padpos) { 28738c2ecf20Sopenharmony_ci if (skb_headroom(skb) < padsize) { 28748c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, 28758c2ecf20Sopenharmony_ci "tx99 padding failed\n"); 28768c2ecf20Sopenharmony_ci return -EINVAL; 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci skb_push(skb, padsize); 28808c2ecf20Sopenharmony_ci memmove(skb->data, skb->data + padsize, padpos); 28818c2ecf20Sopenharmony_ci } 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci fi->keyix = ATH9K_TXKEYIX_INVALID; 28848c2ecf20Sopenharmony_ci fi->framelen = skb->len + FCS_LEN; 28858c2ecf20Sopenharmony_ci fi->keytype = ATH9K_KEY_TYPE_CLEAR; 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txctl->txq, NULL, skb); 28888c2ecf20Sopenharmony_ci if (!bf) { 28898c2ecf20Sopenharmony_ci ath_dbg(common, XMIT, "tx99 buffer setup failed\n"); 28908c2ecf20Sopenharmony_ci return -EINVAL; 28918c2ecf20Sopenharmony_ci } 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci ath_set_rates(sc->tx99_vif, NULL, bf); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); 28968c2ecf20Sopenharmony_ci ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci ath_tx_send_normal(sc, txctl->txq, NULL, skb); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci return 0; 29018c2ecf20Sopenharmony_ci} 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH9K_TX99 */ 2904