162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1862306a36Sopenharmony_ci#include "ath9k.h" 1962306a36Sopenharmony_ci#include "ar9003_mac.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define BITS_PER_BYTE 8 2262306a36Sopenharmony_ci#define OFDM_PLCP_BITS 22 2362306a36Sopenharmony_ci#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 2462306a36Sopenharmony_ci#define L_STF 8 2562306a36Sopenharmony_ci#define L_LTF 8 2662306a36Sopenharmony_ci#define L_SIG 4 2762306a36Sopenharmony_ci#define HT_SIG 8 2862306a36Sopenharmony_ci#define HT_STF 4 2962306a36Sopenharmony_ci#define HT_LTF(_ns) (4 * (_ns)) 3062306a36Sopenharmony_ci#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */ 3162306a36Sopenharmony_ci#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */ 3262306a36Sopenharmony_ci#define TIME_SYMBOLS(t) ((t) >> 2) 3362306a36Sopenharmony_ci#define TIME_SYMBOLS_HALFGI(t) (((t) * 5 - 4) / 18) 3462306a36Sopenharmony_ci#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) 3562306a36Sopenharmony_ci#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Shifts in ar5008_phy.c and ar9003_phy.c are equal for all revisions */ 3862306a36Sopenharmony_ci#define ATH9K_PWRTBL_11NA_OFDM_SHIFT 0 3962306a36Sopenharmony_ci#define ATH9K_PWRTBL_11NG_OFDM_SHIFT 4 4062306a36Sopenharmony_ci#define ATH9K_PWRTBL_11NA_HT_SHIFT 8 4162306a36Sopenharmony_ci#define ATH9K_PWRTBL_11NG_HT_SHIFT 12 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic u16 bits_per_symbol[][2] = { 4562306a36Sopenharmony_ci /* 20MHz 40MHz */ 4662306a36Sopenharmony_ci { 26, 54 }, /* 0: BPSK */ 4762306a36Sopenharmony_ci { 52, 108 }, /* 1: QPSK 1/2 */ 4862306a36Sopenharmony_ci { 78, 162 }, /* 2: QPSK 3/4 */ 4962306a36Sopenharmony_ci { 104, 216 }, /* 3: 16-QAM 1/2 */ 5062306a36Sopenharmony_ci { 156, 324 }, /* 4: 16-QAM 3/4 */ 5162306a36Sopenharmony_ci { 208, 432 }, /* 5: 64-QAM 2/3 */ 5262306a36Sopenharmony_ci { 234, 486 }, /* 6: 64-QAM 3/4 */ 5362306a36Sopenharmony_ci { 260, 540 }, /* 7: 64-QAM 5/6 */ 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, 5762306a36Sopenharmony_ci struct ath_atx_tid *tid, struct sk_buff *skb); 5862306a36Sopenharmony_cistatic void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, 5962306a36Sopenharmony_ci int tx_flags, struct ath_txq *txq, 6062306a36Sopenharmony_ci struct ieee80211_sta *sta); 6162306a36Sopenharmony_cistatic void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 6262306a36Sopenharmony_ci struct ath_txq *txq, struct list_head *bf_q, 6362306a36Sopenharmony_ci struct ieee80211_sta *sta, 6462306a36Sopenharmony_ci struct ath_tx_status *ts, int txok); 6562306a36Sopenharmony_cistatic void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, 6662306a36Sopenharmony_ci struct list_head *head, bool internal); 6762306a36Sopenharmony_cistatic void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, 6862306a36Sopenharmony_ci struct ath_tx_status *ts, int nframes, int nbad, 6962306a36Sopenharmony_ci int txok); 7062306a36Sopenharmony_cistatic void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 7162306a36Sopenharmony_ci struct ath_buf *bf); 7262306a36Sopenharmony_cistatic struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, 7362306a36Sopenharmony_ci struct ath_txq *txq, 7462306a36Sopenharmony_ci struct ath_atx_tid *tid, 7562306a36Sopenharmony_ci struct sk_buff *skb); 7662306a36Sopenharmony_cistatic int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, 7762306a36Sopenharmony_ci struct ath_tx_control *txctl); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cienum { 8062306a36Sopenharmony_ci MCS_HT20, 8162306a36Sopenharmony_ci MCS_HT20_SGI, 8262306a36Sopenharmony_ci MCS_HT40, 8362306a36Sopenharmony_ci MCS_HT40_SGI, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/*********************/ 8762306a36Sopenharmony_ci/* Aggregation logic */ 8862306a36Sopenharmony_ci/*********************/ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 9362306a36Sopenharmony_ci struct ieee80211_sta *sta = info->status.status_driver_data[0]; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | 9662306a36Sopenharmony_ci IEEE80211_TX_STATUS_EOSP)) { 9762306a36Sopenharmony_ci ieee80211_tx_status(hw, skb); 9862306a36Sopenharmony_ci return; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (sta) 10262306a36Sopenharmony_ci ieee80211_tx_status_noskb(hw, sta, info); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci dev_kfree_skb(skb); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) 10862306a36Sopenharmony_ci __releases(&txq->axq_lock) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 11162306a36Sopenharmony_ci struct sk_buff_head q; 11262306a36Sopenharmony_ci struct sk_buff *skb; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci __skb_queue_head_init(&q); 11562306a36Sopenharmony_ci skb_queue_splice_init(&txq->complete_q, &q); 11662306a36Sopenharmony_ci spin_unlock_bh(&txq->axq_lock); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci while ((skb = __skb_dequeue(&q))) 11962306a36Sopenharmony_ci ath_tx_status(hw, skb); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct ieee80211_txq *queue = 12562306a36Sopenharmony_ci container_of((void *)tid, struct ieee80211_txq, drv_priv); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ieee80211_schedule_txq(sc->hw, queue); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_civoid ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 13362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 13462306a36Sopenharmony_ci struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; 13562306a36Sopenharmony_ci struct ath_txq *txq = tid->txq; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", 13862306a36Sopenharmony_ci queue->sta ? queue->sta->addr : queue->vif->addr, 13962306a36Sopenharmony_ci tid->tidno); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci ath_txq_lock(sc, txq); 14262306a36Sopenharmony_ci ath_txq_schedule(sc, txq); 14362306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic struct ath_frame_info *get_frame_info(struct sk_buff *skb) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 14962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ath_frame_info) > 15062306a36Sopenharmony_ci sizeof(tx_info->status.status_driver_data)); 15162306a36Sopenharmony_ci return (struct ath_frame_info *) &tx_info->status.status_driver_data[0]; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci if (!tid->an->sta) 15762306a36Sopenharmony_ci return; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, 16062306a36Sopenharmony_ci seqno << IEEE80211_SEQ_SEQ_SHIFT); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf, 16462306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct ieee80211_sta_rates *ratetbl; 16762306a36Sopenharmony_ci u8 i; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!sta) 17062306a36Sopenharmony_ci return false; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ratetbl = rcu_dereference(sta->rates); 17362306a36Sopenharmony_ci if (!ratetbl) 17462306a36Sopenharmony_ci return false; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (tx_info->control.rates[0].idx < 0 || 17762306a36Sopenharmony_ci tx_info->control.rates[0].count == 0) 17862306a36Sopenharmony_ci { 17962306a36Sopenharmony_ci i = 0; 18062306a36Sopenharmony_ci } else { 18162306a36Sopenharmony_ci bf->rates[0] = tx_info->control.rates[0]; 18262306a36Sopenharmony_ci i = 1; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for ( ; i < IEEE80211_TX_MAX_RATES; i++) { 18662306a36Sopenharmony_ci bf->rates[i].idx = ratetbl->rate[i].idx; 18762306a36Sopenharmony_ci bf->rates[i].flags = ratetbl->rate[i].flags; 18862306a36Sopenharmony_ci if (tx_info->control.use_rts) 18962306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count_rts; 19062306a36Sopenharmony_ci else if (tx_info->control.use_cts_prot) 19162306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count_cts; 19262306a36Sopenharmony_ci else 19362306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return true; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, 20062306a36Sopenharmony_ci struct ath_buf *bf) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (!ath_merge_ratetbl(sta, bf, tx_info)) 20762306a36Sopenharmony_ci ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, 20862306a36Sopenharmony_ci ARRAY_SIZE(bf->rates)); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, 21262306a36Sopenharmony_ci struct sk_buff *skb) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 21562306a36Sopenharmony_ci int q = fi->txq; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (q < 0) 21862306a36Sopenharmony_ci return; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci txq = sc->tx.txq_map[q]; 22162306a36Sopenharmony_ci if (WARN_ON(--txq->pending_frames < 0)) 22262306a36Sopenharmony_ci txq->pending_frames = 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic struct ath_atx_tid * 22762306a36Sopenharmony_ciath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK; 23062306a36Sopenharmony_ci return ATH_AN_2_TID(an, tidno); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int 23462306a36Sopenharmony_ciath_tid_pull(struct ath_atx_tid *tid, struct sk_buff **skbuf) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv); 23762306a36Sopenharmony_ci struct ath_softc *sc = tid->an->sc; 23862306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 23962306a36Sopenharmony_ci struct ath_tx_control txctl = { 24062306a36Sopenharmony_ci .txq = tid->txq, 24162306a36Sopenharmony_ci .sta = tid->an->sta, 24262306a36Sopenharmony_ci }; 24362306a36Sopenharmony_ci struct sk_buff *skb; 24462306a36Sopenharmony_ci struct ath_frame_info *fi; 24562306a36Sopenharmony_ci int q, ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci skb = ieee80211_tx_dequeue(hw, txq); 24862306a36Sopenharmony_ci if (!skb) 24962306a36Sopenharmony_ci return -ENOENT; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = ath_tx_prepare(hw, skb, &txctl); 25262306a36Sopenharmony_ci if (ret) { 25362306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 25462306a36Sopenharmony_ci return ret; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci q = skb_get_queue_mapping(skb); 25862306a36Sopenharmony_ci if (tid->txq == sc->tx.txq_map[q]) { 25962306a36Sopenharmony_ci fi = get_frame_info(skb); 26062306a36Sopenharmony_ci fi->txq = q; 26162306a36Sopenharmony_ci ++tid->txq->pending_frames; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci *skbuf = skb; 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int ath_tid_dequeue(struct ath_atx_tid *tid, 26962306a36Sopenharmony_ci struct sk_buff **skb) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci int ret = 0; 27262306a36Sopenharmony_ci *skb = __skb_dequeue(&tid->retry_q); 27362306a36Sopenharmony_ci if (!*skb) 27462306a36Sopenharmony_ci ret = ath_tid_pull(tid, skb); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct ath_txq *txq = tid->txq; 28262306a36Sopenharmony_ci struct sk_buff *skb; 28362306a36Sopenharmony_ci struct ath_buf *bf; 28462306a36Sopenharmony_ci struct list_head bf_head; 28562306a36Sopenharmony_ci struct ath_tx_status ts; 28662306a36Sopenharmony_ci struct ath_frame_info *fi; 28762306a36Sopenharmony_ci bool sendbar = false; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci while ((skb = __skb_dequeue(&tid->retry_q))) { 29462306a36Sopenharmony_ci fi = get_frame_info(skb); 29562306a36Sopenharmony_ci bf = fi->bf; 29662306a36Sopenharmony_ci if (!bf) { 29762306a36Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 29862306a36Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 29962306a36Sopenharmony_ci continue; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (fi->baw_tracked) { 30362306a36Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 30462306a36Sopenharmony_ci sendbar = true; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 30862306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (sendbar) { 31262306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 31362306a36Sopenharmony_ci ath_send_bar(tid, tid->seq_start); 31462306a36Sopenharmony_ci ath_txq_lock(sc, txq); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 31962306a36Sopenharmony_ci struct ath_buf *bf) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 32262306a36Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 32362306a36Sopenharmony_ci int index, cindex; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!fi->baw_tracked) 32662306a36Sopenharmony_ci return; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci index = ATH_BA_INDEX(tid->seq_start, seqno); 32962306a36Sopenharmony_ci cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci __clear_bit(cindex, tid->tx_buf); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) { 33462306a36Sopenharmony_ci INCR(tid->seq_start, IEEE80211_SEQ_MAX); 33562306a36Sopenharmony_ci INCR(tid->baw_head, ATH_TID_MAX_BUFS); 33662306a36Sopenharmony_ci if (tid->bar_index >= 0) 33762306a36Sopenharmony_ci tid->bar_index--; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, 34262306a36Sopenharmony_ci struct ath_buf *bf) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 34562306a36Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 34662306a36Sopenharmony_ci int index, cindex; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (fi->baw_tracked) 34962306a36Sopenharmony_ci return; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci index = ATH_BA_INDEX(tid->seq_start, seqno); 35262306a36Sopenharmony_ci cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); 35362306a36Sopenharmony_ci __set_bit(cindex, tid->tx_buf); 35462306a36Sopenharmony_ci fi->baw_tracked = 1; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (index >= ((tid->baw_tail - tid->baw_head) & 35762306a36Sopenharmony_ci (ATH_TID_MAX_BUFS - 1))) { 35862306a36Sopenharmony_ci tid->baw_tail = cindex; 35962306a36Sopenharmony_ci INCR(tid->baw_tail, ATH_TID_MAX_BUFS); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, 36462306a36Sopenharmony_ci struct ath_atx_tid *tid) 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct sk_buff *skb; 36862306a36Sopenharmony_ci struct ath_buf *bf; 36962306a36Sopenharmony_ci struct list_head bf_head; 37062306a36Sopenharmony_ci struct ath_tx_status ts; 37162306a36Sopenharmony_ci struct ath_frame_info *fi; 37262306a36Sopenharmony_ci int ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 37562306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci while ((ret = ath_tid_dequeue(tid, &skb)) == 0) { 37862306a36Sopenharmony_ci fi = get_frame_info(skb); 37962306a36Sopenharmony_ci bf = fi->bf; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (!bf) { 38262306a36Sopenharmony_ci ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL); 38362306a36Sopenharmony_ci continue; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 38762306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, 39262306a36Sopenharmony_ci struct sk_buff *skb, int count) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 39562306a36Sopenharmony_ci struct ath_buf *bf = fi->bf; 39662306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 39762306a36Sopenharmony_ci int prev = fi->retries; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_retries); 40062306a36Sopenharmony_ci fi->retries += count; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (prev > 0) 40362306a36Sopenharmony_ci return; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 40662306a36Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); 40762306a36Sopenharmony_ci dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, 40862306a36Sopenharmony_ci sizeof(*hdr), DMA_TO_DEVICE); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct ath_buf *bf = NULL; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci spin_lock_bh(&sc->tx.txbuflock); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (unlikely(list_empty(&sc->tx.txbuf))) { 41862306a36Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 41962306a36Sopenharmony_ci return NULL; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); 42362306a36Sopenharmony_ci list_del(&bf->list); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return bf; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci spin_lock_bh(&sc->tx.txbuflock); 43362306a36Sopenharmony_ci list_add_tail(&bf->list, &sc->tx.txbuf); 43462306a36Sopenharmony_ci spin_unlock_bh(&sc->tx.txbuflock); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct ath_buf *tbf; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci tbf = ath_tx_get_buffer(sc); 44262306a36Sopenharmony_ci if (WARN_ON(!tbf)) 44362306a36Sopenharmony_ci return NULL; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ATH_TXBUF_RESET(tbf); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci tbf->bf_mpdu = bf->bf_mpdu; 44862306a36Sopenharmony_ci tbf->bf_buf_addr = bf->bf_buf_addr; 44962306a36Sopenharmony_ci memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); 45062306a36Sopenharmony_ci tbf->bf_state = bf->bf_state; 45162306a36Sopenharmony_ci tbf->bf_state.stale = false; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return tbf; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, 45762306a36Sopenharmony_ci struct ath_tx_status *ts, int txok, 45862306a36Sopenharmony_ci int *nframes, int *nbad) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci u16 seq_st = 0; 46162306a36Sopenharmony_ci u32 ba[WME_BA_BMP_SIZE >> 5]; 46262306a36Sopenharmony_ci int ba_index; 46362306a36Sopenharmony_ci int isaggr = 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci *nbad = 0; 46662306a36Sopenharmony_ci *nframes = 0; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci isaggr = bf_isaggr(bf); 46962306a36Sopenharmony_ci memset(ba, 0, WME_BA_BMP_SIZE >> 3); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (isaggr) { 47262306a36Sopenharmony_ci seq_st = ts->ts_seqnum; 47362306a36Sopenharmony_ci memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci while (bf) { 47762306a36Sopenharmony_ci ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci (*nframes)++; 48062306a36Sopenharmony_ci if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) 48162306a36Sopenharmony_ci (*nbad)++; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci bf = bf->bf_next; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, 48962306a36Sopenharmony_ci struct ath_buf *bf, struct list_head *bf_q, 49062306a36Sopenharmony_ci struct ieee80211_sta *sta, 49162306a36Sopenharmony_ci struct ath_atx_tid *tid, 49262306a36Sopenharmony_ci struct ath_tx_status *ts, int txok) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct ath_node *an = NULL; 49562306a36Sopenharmony_ci struct sk_buff *skb; 49662306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 49762306a36Sopenharmony_ci struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; 49862306a36Sopenharmony_ci struct list_head bf_head; 49962306a36Sopenharmony_ci struct sk_buff_head bf_pending; 50062306a36Sopenharmony_ci u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first; 50162306a36Sopenharmony_ci u32 ba[WME_BA_BMP_SIZE >> 5]; 50262306a36Sopenharmony_ci int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; 50362306a36Sopenharmony_ci bool rc_update = true, isba; 50462306a36Sopenharmony_ci struct ieee80211_tx_rate rates[4]; 50562306a36Sopenharmony_ci struct ath_frame_info *fi; 50662306a36Sopenharmony_ci int nframes; 50762306a36Sopenharmony_ci bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); 50862306a36Sopenharmony_ci int i, retries; 50962306a36Sopenharmony_ci int bar_index = -1; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci skb = bf->bf_mpdu; 51262306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci memcpy(rates, bf->rates, sizeof(rates)); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci retries = ts->ts_longretry + 1; 51762306a36Sopenharmony_ci for (i = 0; i < ts->ts_rateindex; i++) 51862306a36Sopenharmony_ci retries += rates[i].count; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (!sta) { 52162306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 52262306a36Sopenharmony_ci while (bf) { 52362306a36Sopenharmony_ci bf_next = bf->bf_next; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!bf->bf_state.stale || bf_next != NULL) 52662306a36Sopenharmony_ci list_move_tail(&bf->list, &bf_head); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, 0); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci bf = bf_next; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci return; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 53662306a36Sopenharmony_ci seq_first = tid->seq_start; 53762306a36Sopenharmony_ci isba = ts->ts_flags & ATH9K_TX_BA; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* 54062306a36Sopenharmony_ci * The hardware occasionally sends a tx status for the wrong TID. 54162306a36Sopenharmony_ci * In this case, the BA status cannot be considered valid and all 54262306a36Sopenharmony_ci * subframes need to be retransmitted 54362306a36Sopenharmony_ci * 54462306a36Sopenharmony_ci * Only BlockAcks have a TID and therefore normal Acks cannot be 54562306a36Sopenharmony_ci * checked 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (isba && tid->tidno != ts->tid) 54862306a36Sopenharmony_ci txok = false; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci isaggr = bf_isaggr(bf); 55162306a36Sopenharmony_ci memset(ba, 0, WME_BA_BMP_SIZE >> 3); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (isaggr && txok) { 55462306a36Sopenharmony_ci if (ts->ts_flags & ATH9K_TX_BA) { 55562306a36Sopenharmony_ci seq_st = ts->ts_seqnum; 55662306a36Sopenharmony_ci memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); 55762306a36Sopenharmony_ci } else { 55862306a36Sopenharmony_ci /* 55962306a36Sopenharmony_ci * AR5416 can become deaf/mute when BA 56062306a36Sopenharmony_ci * issue happens. Chip needs to be reset. 56162306a36Sopenharmony_ci * But AP code may have sychronization issues 56262306a36Sopenharmony_ci * when perform internal reset in this routine. 56362306a36Sopenharmony_ci * Only enable reset in STA mode for now. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) 56662306a36Sopenharmony_ci needreset = 1; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci __skb_queue_head_init(&bf_pending); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); 57362306a36Sopenharmony_ci while (bf) { 57462306a36Sopenharmony_ci u16 seqno = bf->bf_state.seqno; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci txfail = txpending = sendbar = 0; 57762306a36Sopenharmony_ci bf_next = bf->bf_next; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci skb = bf->bf_mpdu; 58062306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 58162306a36Sopenharmony_ci fi = get_frame_info(skb); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno) || 58462306a36Sopenharmony_ci !tid->active) { 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * Outside of the current BlockAck window, 58762306a36Sopenharmony_ci * maybe part of a previous session 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci txfail = 1; 59062306a36Sopenharmony_ci } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { 59162306a36Sopenharmony_ci /* transmit completion, subframe is 59262306a36Sopenharmony_ci * acked by block ack */ 59362306a36Sopenharmony_ci acked_cnt++; 59462306a36Sopenharmony_ci } else if (!isaggr && txok) { 59562306a36Sopenharmony_ci /* transmit completion */ 59662306a36Sopenharmony_ci acked_cnt++; 59762306a36Sopenharmony_ci } else if (flush) { 59862306a36Sopenharmony_ci txpending = 1; 59962306a36Sopenharmony_ci } else if (fi->retries < ATH_MAX_SW_RETRIES) { 60062306a36Sopenharmony_ci if (txok || !an->sleeping) 60162306a36Sopenharmony_ci ath_tx_set_retry(sc, txq, bf->bf_mpdu, 60262306a36Sopenharmony_ci retries); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci txpending = 1; 60562306a36Sopenharmony_ci } else { 60662306a36Sopenharmony_ci txfail = 1; 60762306a36Sopenharmony_ci txfail_cnt++; 60862306a36Sopenharmony_ci bar_index = max_t(int, bar_index, 60962306a36Sopenharmony_ci ATH_BA_INDEX(seq_first, seqno)); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * Make sure the last desc is reclaimed if it 61462306a36Sopenharmony_ci * not a holding desc. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 61762306a36Sopenharmony_ci if (bf_next != NULL || !bf_last->bf_state.stale) 61862306a36Sopenharmony_ci list_move_tail(&bf->list, &bf_head); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (!txpending) { 62162306a36Sopenharmony_ci /* 62262306a36Sopenharmony_ci * complete the acked-ones/xretried ones; update 62362306a36Sopenharmony_ci * block-ack window 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { 62862306a36Sopenharmony_ci memcpy(tx_info->control.rates, rates, sizeof(rates)); 62962306a36Sopenharmony_ci ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); 63062306a36Sopenharmony_ci rc_update = false; 63162306a36Sopenharmony_ci if (bf == bf->bf_lastbf) 63262306a36Sopenharmony_ci ath_dynack_sample_tx_ts(sc->sc_ah, 63362306a36Sopenharmony_ci bf->bf_mpdu, 63462306a36Sopenharmony_ci ts, sta); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts, 63862306a36Sopenharmony_ci !txfail); 63962306a36Sopenharmony_ci } else { 64062306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) { 64162306a36Sopenharmony_ci tx_info->flags &= ~IEEE80211_TX_STATUS_EOSP; 64262306a36Sopenharmony_ci ieee80211_sta_eosp(sta); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci /* retry the un-acked ones */ 64562306a36Sopenharmony_ci if (bf->bf_next == NULL && bf_last->bf_state.stale) { 64662306a36Sopenharmony_ci struct ath_buf *tbf; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci tbf = ath_clone_txbuf(sc, bf_last); 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * Update tx baw and complete the 65162306a36Sopenharmony_ci * frame with failed status if we 65262306a36Sopenharmony_ci * run out of tx buf. 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci if (!tbf) { 65562306a36Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, 65862306a36Sopenharmony_ci &bf_head, NULL, ts, 65962306a36Sopenharmony_ci 0); 66062306a36Sopenharmony_ci bar_index = max_t(int, bar_index, 66162306a36Sopenharmony_ci ATH_BA_INDEX(seq_first, seqno)); 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci fi->bf = tbf; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* 66962306a36Sopenharmony_ci * Put this buffer to the temporary pending 67062306a36Sopenharmony_ci * queue to retain ordering 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci __skb_queue_tail(&bf_pending, skb); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci bf = bf_next; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* prepend un-acked frames to the beginning of the pending frame queue */ 67962306a36Sopenharmony_ci if (!skb_queue_empty(&bf_pending)) { 68062306a36Sopenharmony_ci if (an->sleeping) 68162306a36Sopenharmony_ci ieee80211_sta_set_buffered(sta, tid->tidno, true); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci skb_queue_splice_tail(&bf_pending, &tid->retry_q); 68462306a36Sopenharmony_ci if (!an->sleeping) { 68562306a36Sopenharmony_ci ath_tx_queue_tid(sc, tid); 68662306a36Sopenharmony_ci if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) 68762306a36Sopenharmony_ci tid->clear_ps_filter = true; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (bar_index >= 0) { 69262306a36Sopenharmony_ci u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq)) 69562306a36Sopenharmony_ci tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 69862306a36Sopenharmony_ci ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1)); 69962306a36Sopenharmony_ci ath_txq_lock(sc, txq); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (needreset) 70362306a36Sopenharmony_ci ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic bool bf_is_ampdu_not_probing(struct ath_buf *bf) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); 70962306a36Sopenharmony_ci return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic void ath_tx_count_airtime(struct ath_softc *sc, 71362306a36Sopenharmony_ci struct ieee80211_sta *sta, 71462306a36Sopenharmony_ci struct ath_buf *bf, 71562306a36Sopenharmony_ci struct ath_tx_status *ts, 71662306a36Sopenharmony_ci u8 tid) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci u32 airtime = 0; 71962306a36Sopenharmony_ci int i; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci airtime += ts->duration * (ts->ts_longretry + 1); 72262306a36Sopenharmony_ci for(i = 0; i < ts->ts_rateindex; i++) { 72362306a36Sopenharmony_ci int rate_dur = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, i); 72462306a36Sopenharmony_ci airtime += rate_dur * bf->rates[i].count; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ieee80211_sta_register_airtime(sta, tid, airtime, 0); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, 73162306a36Sopenharmony_ci struct ath_tx_status *ts, struct ath_buf *bf, 73262306a36Sopenharmony_ci struct list_head *bf_head) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 73562306a36Sopenharmony_ci struct ieee80211_tx_info *info; 73662306a36Sopenharmony_ci struct ieee80211_sta *sta; 73762306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 73862306a36Sopenharmony_ci struct ath_atx_tid *tid = NULL; 73962306a36Sopenharmony_ci bool txok, flush; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci txok = !(ts->ts_status & ATH9K_TXERR_MASK); 74262306a36Sopenharmony_ci flush = !!(ts->ts_status & ATH9K_TX_FLUSH); 74362306a36Sopenharmony_ci txq->axq_tx_inprogress = false; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci txq->axq_depth--; 74662306a36Sopenharmony_ci if (bf_is_ampdu_not_probing(bf)) 74762306a36Sopenharmony_ci txq->axq_ampdu_depth--; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, 75062306a36Sopenharmony_ci ts->ts_rateindex); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; 75362306a36Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); 75462306a36Sopenharmony_ci if (sta) { 75562306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 75662306a36Sopenharmony_ci tid = ath_get_skb_tid(sc, an, bf->bf_mpdu); 75762306a36Sopenharmony_ci ath_tx_count_airtime(sc, sta, bf, ts, tid->tidno); 75862306a36Sopenharmony_ci if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) 75962306a36Sopenharmony_ci tid->clear_ps_filter = true; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (!bf_isampdu(bf)) { 76362306a36Sopenharmony_ci if (!flush) { 76462306a36Sopenharmony_ci info = IEEE80211_SKB_CB(bf->bf_mpdu); 76562306a36Sopenharmony_ci memcpy(info->control.rates, bf->rates, 76662306a36Sopenharmony_ci sizeof(info->control.rates)); 76762306a36Sopenharmony_ci ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); 76862306a36Sopenharmony_ci ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts, 76962306a36Sopenharmony_ci sta); 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); 77262306a36Sopenharmony_ci } else 77362306a36Sopenharmony_ci ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (!flush) 77662306a36Sopenharmony_ci ath_txq_schedule(sc, txq); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic bool ath_lookup_legacy(struct ath_buf *bf) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct sk_buff *skb; 78262306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 78362306a36Sopenharmony_ci struct ieee80211_tx_rate *rates; 78462306a36Sopenharmony_ci int i; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci skb = bf->bf_mpdu; 78762306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 78862306a36Sopenharmony_ci rates = tx_info->control.rates; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 79162306a36Sopenharmony_ci if (!rates[i].count || rates[i].idx < 0) 79262306a36Sopenharmony_ci break; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) 79562306a36Sopenharmony_ci return true; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return false; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, 80262306a36Sopenharmony_ci struct ath_atx_tid *tid) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct sk_buff *skb; 80562306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 80662306a36Sopenharmony_ci struct ieee80211_tx_rate *rates; 80762306a36Sopenharmony_ci u32 max_4ms_framelen, frmlen; 80862306a36Sopenharmony_ci u16 aggr_limit, bt_aggr_limit, legacy = 0; 80962306a36Sopenharmony_ci int q = tid->txq->mac80211_qnum; 81062306a36Sopenharmony_ci int i; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci skb = bf->bf_mpdu; 81362306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 81462306a36Sopenharmony_ci rates = bf->rates; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Find the lowest frame length among the rate series that will have a 81862306a36Sopenharmony_ci * 4ms (or TXOP limited) transmit duration. 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 82362306a36Sopenharmony_ci int modeidx; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (!rates[i].count) 82662306a36Sopenharmony_ci continue; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { 82962306a36Sopenharmony_ci legacy = 1; 83062306a36Sopenharmony_ci break; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 83462306a36Sopenharmony_ci modeidx = MCS_HT40; 83562306a36Sopenharmony_ci else 83662306a36Sopenharmony_ci modeidx = MCS_HT20; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) 83962306a36Sopenharmony_ci modeidx++; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci frmlen = sc->tx.max_aggr_framelen[q][modeidx][rates[i].idx]; 84262306a36Sopenharmony_ci max_4ms_framelen = min(max_4ms_framelen, frmlen); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* 84662306a36Sopenharmony_ci * limit aggregate size by the minimum rate if rate selected is 84762306a36Sopenharmony_ci * not a probe rate, if rate selected is a probe rate then 84862306a36Sopenharmony_ci * avoid aggregation of this packet. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) 85162306a36Sopenharmony_ci return 0; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* 85662306a36Sopenharmony_ci * Override the default aggregation limit for BTCOEX. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ci bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen); 85962306a36Sopenharmony_ci if (bt_aggr_limit) 86062306a36Sopenharmony_ci aggr_limit = bt_aggr_limit; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (tid->an->maxampdu) 86362306a36Sopenharmony_ci aggr_limit = min(aggr_limit, tid->an->maxampdu); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return aggr_limit; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/* 86962306a36Sopenharmony_ci * Returns the number of delimiters to be added to 87062306a36Sopenharmony_ci * meet the minimum required mpdudensity. 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_cistatic int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, 87362306a36Sopenharmony_ci struct ath_buf *bf, u16 frmlen, 87462306a36Sopenharmony_ci bool first_subfrm) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci#define FIRST_DESC_NDELIMS 60 87762306a36Sopenharmony_ci u32 nsymbits, nsymbols; 87862306a36Sopenharmony_ci u16 minlen; 87962306a36Sopenharmony_ci u8 flags, rix; 88062306a36Sopenharmony_ci int width, streams, half_gi, ndelim, mindelim; 88162306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Select standard number of delimiters based on frame length alone */ 88462306a36Sopenharmony_ci ndelim = ATH_AGGR_GET_NDELIM(frmlen); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* 88762306a36Sopenharmony_ci * If encryption enabled, hardware requires some more padding between 88862306a36Sopenharmony_ci * subframes. 88962306a36Sopenharmony_ci * TODO - this could be improved to be dependent on the rate. 89062306a36Sopenharmony_ci * The hardware can keep up at lower rates, but not higher rates 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci if ((fi->keyix != ATH9K_TXKEYIX_INVALID) && 89362306a36Sopenharmony_ci !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) 89462306a36Sopenharmony_ci ndelim += ATH_AGGR_ENCRYPTDELIM; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* 89762306a36Sopenharmony_ci * Add delimiter when using RTS/CTS with aggregation 89862306a36Sopenharmony_ci * and non enterprise AR9003 card 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ci if (first_subfrm && !AR_SREV_9580_10_OR_LATER(sc->sc_ah) && 90162306a36Sopenharmony_ci (sc->sc_ah->ent_mode & AR_ENT_OTP_MIN_PKT_SIZE_DISABLE)) 90262306a36Sopenharmony_ci ndelim = max(ndelim, FIRST_DESC_NDELIMS); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * Convert desired mpdu density from microeconds to bytes based 90662306a36Sopenharmony_ci * on highest rate in rate series (i.e. first rate) to determine 90762306a36Sopenharmony_ci * required minimum length for subframe. Take into account 90862306a36Sopenharmony_ci * whether high rate is 20 or 40Mhz and half or full GI. 90962306a36Sopenharmony_ci * 91062306a36Sopenharmony_ci * If there is no mpdu density restriction, no further calculation 91162306a36Sopenharmony_ci * is needed. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (tid->an->mpdudensity == 0) 91562306a36Sopenharmony_ci return ndelim; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci rix = bf->rates[0].idx; 91862306a36Sopenharmony_ci flags = bf->rates[0].flags; 91962306a36Sopenharmony_ci width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; 92062306a36Sopenharmony_ci half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (half_gi) 92362306a36Sopenharmony_ci nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity); 92462306a36Sopenharmony_ci else 92562306a36Sopenharmony_ci nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (nsymbols == 0) 92862306a36Sopenharmony_ci nsymbols = 1; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci streams = HT_RC_2_STREAMS(rix); 93162306a36Sopenharmony_ci nsymbits = bits_per_symbol[rix % 8][width] * streams; 93262306a36Sopenharmony_ci minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (frmlen < minlen) { 93562306a36Sopenharmony_ci mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ; 93662306a36Sopenharmony_ci ndelim = max(mindelim, ndelim); 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci return ndelim; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic int 94362306a36Sopenharmony_ciath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, 94462306a36Sopenharmony_ci struct ath_atx_tid *tid, struct ath_buf **buf) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 94762306a36Sopenharmony_ci struct ath_frame_info *fi; 94862306a36Sopenharmony_ci struct ath_buf *bf; 94962306a36Sopenharmony_ci struct sk_buff *skb, *first_skb = NULL; 95062306a36Sopenharmony_ci u16 seqno; 95162306a36Sopenharmony_ci int ret; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci while (1) { 95462306a36Sopenharmony_ci ret = ath_tid_dequeue(tid, &skb); 95562306a36Sopenharmony_ci if (ret < 0) 95662306a36Sopenharmony_ci return ret; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci fi = get_frame_info(skb); 95962306a36Sopenharmony_ci bf = fi->bf; 96062306a36Sopenharmony_ci if (!fi->bf) 96162306a36Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txq, tid, skb); 96262306a36Sopenharmony_ci else 96362306a36Sopenharmony_ci bf->bf_state.stale = false; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (!bf) { 96662306a36Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 96762306a36Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 96862306a36Sopenharmony_ci continue; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci bf->bf_next = NULL; 97262306a36Sopenharmony_ci bf->bf_lastbf = bf; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 97562306a36Sopenharmony_ci tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | 97662306a36Sopenharmony_ci IEEE80211_TX_STATUS_EOSP); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* 97962306a36Sopenharmony_ci * No aggregation session is running, but there may be frames 98062306a36Sopenharmony_ci * from a previous session or a failed attempt in the queue. 98162306a36Sopenharmony_ci * Send them out as normal data frames 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_ci if (!tid->active) 98462306a36Sopenharmony_ci tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { 98762306a36Sopenharmony_ci bf->bf_state.bf_type = 0; 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; 99262306a36Sopenharmony_ci seqno = bf->bf_state.seqno; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* do not step over block-ack window */ 99562306a36Sopenharmony_ci if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { 99662306a36Sopenharmony_ci __skb_queue_tail(&tid->retry_q, skb); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* If there are other skbs in the retry q, they are 99962306a36Sopenharmony_ci * probably within the BAW, so loop immediately to get 100062306a36Sopenharmony_ci * one of them. Otherwise the queue can get stuck. */ 100162306a36Sopenharmony_ci if (!skb_queue_is_first(&tid->retry_q, skb) && 100262306a36Sopenharmony_ci !WARN_ON(skb == first_skb)) { 100362306a36Sopenharmony_ci if(!first_skb) /* infinite loop prevention */ 100462306a36Sopenharmony_ci first_skb = skb; 100562306a36Sopenharmony_ci continue; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci return -EINPROGRESS; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { 101162306a36Sopenharmony_ci struct ath_tx_status ts = {}; 101262306a36Sopenharmony_ci struct list_head bf_head; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 101562306a36Sopenharmony_ci list_add(&bf->list, &bf_head); 101662306a36Sopenharmony_ci ath_tx_update_baw(sc, tid, bf); 101762306a36Sopenharmony_ci ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); 101862306a36Sopenharmony_ci continue; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (bf_isampdu(bf)) 102262306a36Sopenharmony_ci ath_tx_addto_baw(sc, tid, bf); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci *buf = bf; 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int 103262306a36Sopenharmony_ciath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, 103362306a36Sopenharmony_ci struct ath_atx_tid *tid, struct list_head *bf_q, 103462306a36Sopenharmony_ci struct ath_buf *bf_first) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) 103762306a36Sopenharmony_ci struct ath_buf *bf = bf_first, *bf_prev = NULL; 103862306a36Sopenharmony_ci int nframes = 0, ndelim, ret; 103962306a36Sopenharmony_ci u16 aggr_limit = 0, al = 0, bpad = 0, 104062306a36Sopenharmony_ci al_delta, h_baw = tid->baw_size / 2; 104162306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 104262306a36Sopenharmony_ci struct ath_frame_info *fi; 104362306a36Sopenharmony_ci struct sk_buff *skb; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci bf = bf_first; 104762306a36Sopenharmony_ci aggr_limit = ath_lookup_rate(sc, bf, tid); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci while (bf) 105062306a36Sopenharmony_ci { 105162306a36Sopenharmony_ci skb = bf->bf_mpdu; 105262306a36Sopenharmony_ci fi = get_frame_info(skb); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* do not exceed aggregation limit */ 105562306a36Sopenharmony_ci al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; 105662306a36Sopenharmony_ci if (nframes) { 105762306a36Sopenharmony_ci if (aggr_limit < al + bpad + al_delta || 105862306a36Sopenharmony_ci ath_lookup_legacy(bf) || nframes >= h_baw) 105962306a36Sopenharmony_ci goto stop; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 106262306a36Sopenharmony_ci if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || 106362306a36Sopenharmony_ci !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) 106462306a36Sopenharmony_ci goto stop; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* add padding for previous frame to aggregation length */ 106862306a36Sopenharmony_ci al += bpad + al_delta; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* 107162306a36Sopenharmony_ci * Get the delimiters needed to meet the MPDU 107262306a36Sopenharmony_ci * density for this node. 107362306a36Sopenharmony_ci */ 107462306a36Sopenharmony_ci ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen, 107562306a36Sopenharmony_ci !nframes); 107662306a36Sopenharmony_ci bpad = PADBYTES(al_delta) + (ndelim << 2); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci nframes++; 107962306a36Sopenharmony_ci bf->bf_next = NULL; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* link buffers of this frame to the aggregate */ 108262306a36Sopenharmony_ci bf->bf_state.ndelim = ndelim; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci list_add_tail(&bf->list, bf_q); 108562306a36Sopenharmony_ci if (bf_prev) 108662306a36Sopenharmony_ci bf_prev->bf_next = bf; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci bf_prev = bf; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 109162306a36Sopenharmony_ci if (ret < 0) 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci goto finish; 109562306a36Sopenharmony_cistop: 109662306a36Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 109762306a36Sopenharmony_cifinish: 109862306a36Sopenharmony_ci bf = bf_first; 109962306a36Sopenharmony_ci bf->bf_lastbf = bf_prev; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (bf == bf_prev) { 110262306a36Sopenharmony_ci al = get_frame_info(bf->bf_mpdu)->framelen; 110362306a36Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU; 110462306a36Sopenharmony_ci } else { 110562306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_aggr); 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci return al; 110962306a36Sopenharmony_ci#undef PADBYTES 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci/* 111362306a36Sopenharmony_ci * rix - rate index 111462306a36Sopenharmony_ci * pktlen - total bytes (delims + data + fcs + pads + pad delims) 111562306a36Sopenharmony_ci * width - 0 for 20 MHz, 1 for 40 MHz 111662306a36Sopenharmony_ci * half_gi - to use 4us v/s 3.6 us for symbol time 111762306a36Sopenharmony_ci */ 111862306a36Sopenharmony_ciu32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, 111962306a36Sopenharmony_ci int width, int half_gi, bool shortPreamble) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci u32 nbits, nsymbits, duration, nsymbols; 112262306a36Sopenharmony_ci int streams; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* find number of symbols: PLCP + data */ 112562306a36Sopenharmony_ci streams = HT_RC_2_STREAMS(rix); 112662306a36Sopenharmony_ci nbits = (pktlen << 3) + OFDM_PLCP_BITS; 112762306a36Sopenharmony_ci nsymbits = bits_per_symbol[rix % 8][width] * streams; 112862306a36Sopenharmony_ci nsymbols = (nbits + nsymbits - 1) / nsymbits; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (!half_gi) 113162306a36Sopenharmony_ci duration = SYMBOL_TIME(nsymbols); 113262306a36Sopenharmony_ci else 113362306a36Sopenharmony_ci duration = SYMBOL_TIME_HALFGI(nsymbols); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* addup duration for legacy/ht training and signal fields */ 113662306a36Sopenharmony_ci duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return duration; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci int streams = HT_RC_2_STREAMS(mcs); 114462306a36Sopenharmony_ci int symbols, bits; 114562306a36Sopenharmony_ci int bytes = 0; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 114862306a36Sopenharmony_ci symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); 114962306a36Sopenharmony_ci bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; 115062306a36Sopenharmony_ci bits -= OFDM_PLCP_BITS; 115162306a36Sopenharmony_ci bytes = bits / 8; 115262306a36Sopenharmony_ci if (bytes > 65532) 115362306a36Sopenharmony_ci bytes = 65532; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return bytes; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_civoid ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci u16 *cur_ht20, *cur_ht20_sgi, *cur_ht40, *cur_ht40_sgi; 116162306a36Sopenharmony_ci int mcs; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* 4ms is the default (and maximum) duration */ 116462306a36Sopenharmony_ci if (!txop || txop > 4096) 116562306a36Sopenharmony_ci txop = 4096; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci cur_ht20 = sc->tx.max_aggr_framelen[queue][MCS_HT20]; 116862306a36Sopenharmony_ci cur_ht20_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT20_SGI]; 116962306a36Sopenharmony_ci cur_ht40 = sc->tx.max_aggr_framelen[queue][MCS_HT40]; 117062306a36Sopenharmony_ci cur_ht40_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT40_SGI]; 117162306a36Sopenharmony_ci for (mcs = 0; mcs < 32; mcs++) { 117262306a36Sopenharmony_ci cur_ht20[mcs] = ath_max_framelen(txop, mcs, false, false); 117362306a36Sopenharmony_ci cur_ht20_sgi[mcs] = ath_max_framelen(txop, mcs, false, true); 117462306a36Sopenharmony_ci cur_ht40[mcs] = ath_max_framelen(txop, mcs, true, false); 117562306a36Sopenharmony_ci cur_ht40_sgi[mcs] = ath_max_framelen(txop, mcs, true, true); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, 118062306a36Sopenharmony_ci u8 rateidx, bool is_40, bool is_cck, bool is_mcs) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci u8 max_power; 118362306a36Sopenharmony_ci struct sk_buff *skb; 118462306a36Sopenharmony_ci struct ath_frame_info *fi; 118562306a36Sopenharmony_ci struct ieee80211_tx_info *info; 118662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 118762306a36Sopenharmony_ci bool is_2ghz, is_5ghz, use_stbc; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (sc->tx99_state || !ah->tpc_enabled) 119062306a36Sopenharmony_ci return MAX_RATE_POWER; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci skb = bf->bf_mpdu; 119362306a36Sopenharmony_ci fi = get_frame_info(skb); 119462306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci is_2ghz = info->band == NL80211_BAND_2GHZ; 119762306a36Sopenharmony_ci is_5ghz = info->band == NL80211_BAND_5GHZ; 119862306a36Sopenharmony_ci use_stbc = is_mcs && rateidx < 8 && (info->flags & 119962306a36Sopenharmony_ci IEEE80211_TX_CTL_STBC); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (is_mcs) 120262306a36Sopenharmony_ci rateidx += is_5ghz ? ATH9K_PWRTBL_11NA_HT_SHIFT 120362306a36Sopenharmony_ci : ATH9K_PWRTBL_11NG_HT_SHIFT; 120462306a36Sopenharmony_ci else if (is_2ghz && !is_cck) 120562306a36Sopenharmony_ci rateidx += ATH9K_PWRTBL_11NG_OFDM_SHIFT; 120662306a36Sopenharmony_ci else 120762306a36Sopenharmony_ci rateidx += ATH9K_PWRTBL_11NA_OFDM_SHIFT; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (!AR_SREV_9300_20_OR_LATER(ah)) { 121062306a36Sopenharmony_ci int txpower = fi->tx_power; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (is_40) { 121362306a36Sopenharmony_ci u8 power_ht40delta; 121462306a36Sopenharmony_ci struct ar5416_eeprom_def *eep = &ah->eeprom.def; 121562306a36Sopenharmony_ci u16 eeprom_rev = ah->eep_ops->get_eeprom_rev(ah); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (eeprom_rev >= AR5416_EEP_MINOR_VER_2) { 121862306a36Sopenharmony_ci struct modal_eep_header *pmodal; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci pmodal = &eep->modalHeader[is_2ghz]; 122162306a36Sopenharmony_ci power_ht40delta = pmodal->ht40PowerIncForPdadc; 122262306a36Sopenharmony_ci } else { 122362306a36Sopenharmony_ci power_ht40delta = 2; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci txpower += power_ht40delta; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (AR_SREV_9287(ah) || AR_SREV_9285(ah) || 122962306a36Sopenharmony_ci AR_SREV_9271(ah)) { 123062306a36Sopenharmony_ci txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB; 123162306a36Sopenharmony_ci } else if (AR_SREV_9280_20_OR_LATER(ah)) { 123262306a36Sopenharmony_ci s8 power_offset; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci power_offset = ah->eep_ops->get_eeprom(ah, 123562306a36Sopenharmony_ci EEP_PWR_TABLE_OFFSET); 123662306a36Sopenharmony_ci txpower -= 2 * power_offset; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (OLC_FOR_AR9280_20_LATER(ah) && is_cck) 124062306a36Sopenharmony_ci txpower -= 2; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci txpower = max(txpower, 0); 124362306a36Sopenharmony_ci max_power = min_t(u8, ah->tx_power[rateidx], txpower); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* XXX: clamp minimum TX power at 1 for AR9160 since if 124662306a36Sopenharmony_ci * max_power is set to 0, frames are transmitted at max 124762306a36Sopenharmony_ci * TX power 124862306a36Sopenharmony_ci */ 124962306a36Sopenharmony_ci if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) 125062306a36Sopenharmony_ci max_power = 1; 125162306a36Sopenharmony_ci } else if (!bf->bf_state.bfs_paprd) { 125262306a36Sopenharmony_ci if (use_stbc) 125362306a36Sopenharmony_ci max_power = min_t(u8, ah->tx_power_stbc[rateidx], 125462306a36Sopenharmony_ci fi->tx_power); 125562306a36Sopenharmony_ci else 125662306a36Sopenharmony_ci max_power = min_t(u8, ah->tx_power[rateidx], 125762306a36Sopenharmony_ci fi->tx_power); 125862306a36Sopenharmony_ci } else { 125962306a36Sopenharmony_ci max_power = ah->paprd_training_power; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci return max_power; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, 126662306a36Sopenharmony_ci struct ath_tx_info *info, int len, bool rts) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 126962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 127062306a36Sopenharmony_ci struct sk_buff *skb; 127162306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 127262306a36Sopenharmony_ci struct ieee80211_tx_rate *rates; 127362306a36Sopenharmony_ci const struct ieee80211_rate *rate; 127462306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 127562306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); 127662306a36Sopenharmony_ci u32 rts_thresh = sc->hw->wiphy->rts_threshold; 127762306a36Sopenharmony_ci int i; 127862306a36Sopenharmony_ci u8 rix = 0; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci skb = bf->bf_mpdu; 128162306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(skb); 128262306a36Sopenharmony_ci rates = bf->rates; 128362306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* set dur_update_en for l-sig computation except for PS-Poll frames */ 128662306a36Sopenharmony_ci info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); 128762306a36Sopenharmony_ci info->rtscts_rate = fi->rtscts_rate; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bf->rates); i++) { 129062306a36Sopenharmony_ci bool is_40, is_sgi, is_sp, is_cck; 129162306a36Sopenharmony_ci int phy; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (!rates[i].count || (rates[i].idx < 0)) 129462306a36Sopenharmony_ci break; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci rix = rates[i].idx; 129762306a36Sopenharmony_ci info->rates[i].Tries = rates[i].count; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* 130062306a36Sopenharmony_ci * Handle RTS threshold for unaggregated HT frames. 130162306a36Sopenharmony_ci */ 130262306a36Sopenharmony_ci if (bf_isampdu(bf) && !bf_isaggr(bf) && 130362306a36Sopenharmony_ci (rates[i].flags & IEEE80211_TX_RC_MCS) && 130462306a36Sopenharmony_ci unlikely(rts_thresh != (u32) -1)) { 130562306a36Sopenharmony_ci if (!rts_thresh || (len > rts_thresh)) 130662306a36Sopenharmony_ci rts = true; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { 131062306a36Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; 131162306a36Sopenharmony_ci info->flags |= ATH9K_TXDESC_RTSENA; 131262306a36Sopenharmony_ci } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 131362306a36Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; 131462306a36Sopenharmony_ci info->flags |= ATH9K_TXDESC_CTSENA; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 131862306a36Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_2040; 131962306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) 132062306a36Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); 132362306a36Sopenharmony_ci is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); 132462306a36Sopenharmony_ci is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_MCS) { 132762306a36Sopenharmony_ci /* MCS rates */ 132862306a36Sopenharmony_ci info->rates[i].Rate = rix | 0x80; 132962306a36Sopenharmony_ci info->rates[i].ChSel = ath_txchainmask_reduction(sc, 133062306a36Sopenharmony_ci ah->txchainmask, info->rates[i].Rate); 133162306a36Sopenharmony_ci info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len, 133262306a36Sopenharmony_ci is_40, is_sgi, is_sp); 133362306a36Sopenharmony_ci if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) 133462306a36Sopenharmony_ci info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; 133562306a36Sopenharmony_ci if (rix >= 8 && fi->dyn_smps) { 133662306a36Sopenharmony_ci info->rates[i].RateFlags |= 133762306a36Sopenharmony_ci ATH9K_RATESERIES_RTS_CTS; 133862306a36Sopenharmony_ci info->flags |= ATH9K_TXDESC_CTSENA; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, 134262306a36Sopenharmony_ci is_40, false, true); 134362306a36Sopenharmony_ci continue; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* legacy rates */ 134762306a36Sopenharmony_ci rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; 134862306a36Sopenharmony_ci if ((tx_info->band == NL80211_BAND_2GHZ) && 134962306a36Sopenharmony_ci !(rate->flags & IEEE80211_RATE_ERP_G)) 135062306a36Sopenharmony_ci phy = WLAN_RC_PHY_CCK; 135162306a36Sopenharmony_ci else 135262306a36Sopenharmony_ci phy = WLAN_RC_PHY_OFDM; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci info->rates[i].Rate = rate->hw_value; 135562306a36Sopenharmony_ci if (rate->hw_value_short) { 135662306a36Sopenharmony_ci if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 135762306a36Sopenharmony_ci info->rates[i].Rate |= rate->hw_value_short; 135862306a36Sopenharmony_ci } else { 135962306a36Sopenharmony_ci is_sp = false; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (bf->bf_state.bfs_paprd) 136362306a36Sopenharmony_ci info->rates[i].ChSel = ah->txchainmask; 136462306a36Sopenharmony_ci else 136562306a36Sopenharmony_ci info->rates[i].ChSel = ath_txchainmask_reduction(sc, 136662306a36Sopenharmony_ci ah->txchainmask, info->rates[i].Rate); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, 136962306a36Sopenharmony_ci phy, rate->bitrate * 100, len, rix, is_sp); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci is_cck = IS_CCK_RATE(info->rates[i].Rate); 137262306a36Sopenharmony_ci info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false, 137362306a36Sopenharmony_ci is_cck, false); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ 137762306a36Sopenharmony_ci if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit)) 137862306a36Sopenharmony_ci info->flags &= ~ATH9K_TXDESC_RTSENA; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ 138162306a36Sopenharmony_ci if (info->flags & ATH9K_TXDESC_RTSENA) 138262306a36Sopenharmony_ci info->flags &= ~ATH9K_TXDESC_CTSENA; 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 138862306a36Sopenharmony_ci enum ath9k_pkt_type htype; 138962306a36Sopenharmony_ci __le16 fc; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 139262306a36Sopenharmony_ci fc = hdr->frame_control; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (ieee80211_is_beacon(fc)) 139562306a36Sopenharmony_ci htype = ATH9K_PKT_TYPE_BEACON; 139662306a36Sopenharmony_ci else if (ieee80211_is_probe_resp(fc)) 139762306a36Sopenharmony_ci htype = ATH9K_PKT_TYPE_PROBE_RESP; 139862306a36Sopenharmony_ci else if (ieee80211_is_atim(fc)) 139962306a36Sopenharmony_ci htype = ATH9K_PKT_TYPE_ATIM; 140062306a36Sopenharmony_ci else if (ieee80211_is_pspoll(fc)) 140162306a36Sopenharmony_ci htype = ATH9K_PKT_TYPE_PSPOLL; 140262306a36Sopenharmony_ci else 140362306a36Sopenharmony_ci htype = ATH9K_PKT_TYPE_NORMAL; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci return htype; 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, 140962306a36Sopenharmony_ci struct ath_txq *txq, int len) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 141262306a36Sopenharmony_ci struct ath_buf *bf_first = NULL; 141362306a36Sopenharmony_ci struct ath_tx_info info; 141462306a36Sopenharmony_ci u32 rts_thresh = sc->hw->wiphy->rts_threshold; 141562306a36Sopenharmony_ci bool rts = false; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 141862306a36Sopenharmony_ci info.is_first = true; 141962306a36Sopenharmony_ci info.is_last = true; 142062306a36Sopenharmony_ci info.qcu = txq->axq_qnum; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci while (bf) { 142362306a36Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 142462306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 142562306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 142662306a36Sopenharmony_ci bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci info.type = get_hw_packet_type(skb); 142962306a36Sopenharmony_ci if (bf->bf_next) 143062306a36Sopenharmony_ci info.link = bf->bf_next->bf_daddr; 143162306a36Sopenharmony_ci else 143262306a36Sopenharmony_ci info.link = (sc->tx99_state) ? bf->bf_daddr : 0; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (!bf_first) { 143562306a36Sopenharmony_ci bf_first = bf; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if (!sc->tx99_state) 143862306a36Sopenharmony_ci info.flags = ATH9K_TXDESC_INTREQ; 143962306a36Sopenharmony_ci if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) || 144062306a36Sopenharmony_ci txq == sc->tx.uapsdq) 144162306a36Sopenharmony_ci info.flags |= ATH9K_TXDESC_CLRDMASK; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) 144462306a36Sopenharmony_ci info.flags |= ATH9K_TXDESC_NOACK; 144562306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_LDPC) 144662306a36Sopenharmony_ci info.flags |= ATH9K_TXDESC_LDPC; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (bf->bf_state.bfs_paprd) 144962306a36Sopenharmony_ci info.flags |= (u32) bf->bf_state.bfs_paprd << 145062306a36Sopenharmony_ci ATH9K_TXDESC_PAPRD_S; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* 145362306a36Sopenharmony_ci * mac80211 doesn't handle RTS threshold for HT because 145462306a36Sopenharmony_ci * the decision has to be taken based on AMPDU length 145562306a36Sopenharmony_ci * and aggregation is done entirely inside ath9k. 145662306a36Sopenharmony_ci * Set the RTS/CTS flag for the first subframe based 145762306a36Sopenharmony_ci * on the threshold. 145862306a36Sopenharmony_ci */ 145962306a36Sopenharmony_ci if (aggr && (bf == bf_first) && 146062306a36Sopenharmony_ci unlikely(rts_thresh != (u32) -1)) { 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * "len" is the size of the entire AMPDU. 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_ci if (!rts_thresh || (len > rts_thresh)) 146562306a36Sopenharmony_ci rts = true; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (!aggr) 146962306a36Sopenharmony_ci len = fi->framelen; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci ath_buf_set_rate(sc, bf, &info, len, rts); 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci info.buf_addr[0] = bf->bf_buf_addr; 147562306a36Sopenharmony_ci info.buf_len[0] = skb->len; 147662306a36Sopenharmony_ci info.pkt_len = fi->framelen; 147762306a36Sopenharmony_ci info.keyix = fi->keyix; 147862306a36Sopenharmony_ci info.keytype = fi->keytype; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (aggr) { 148162306a36Sopenharmony_ci if (bf == bf_first) 148262306a36Sopenharmony_ci info.aggr = AGGR_BUF_FIRST; 148362306a36Sopenharmony_ci else if (bf == bf_first->bf_lastbf) 148462306a36Sopenharmony_ci info.aggr = AGGR_BUF_LAST; 148562306a36Sopenharmony_ci else 148662306a36Sopenharmony_ci info.aggr = AGGR_BUF_MIDDLE; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci info.ndelim = bf->bf_state.ndelim; 148962306a36Sopenharmony_ci info.aggr_len = len; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (bf == bf_first->bf_lastbf) 149362306a36Sopenharmony_ci bf_first = NULL; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); 149662306a36Sopenharmony_ci bf = bf->bf_next; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic void 150162306a36Sopenharmony_ciath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, 150262306a36Sopenharmony_ci struct ath_atx_tid *tid, struct list_head *bf_q, 150362306a36Sopenharmony_ci struct ath_buf *bf_first) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct ath_buf *bf = bf_first, *bf_prev = NULL; 150662306a36Sopenharmony_ci int nframes = 0, ret; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci do { 150962306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci nframes++; 151262306a36Sopenharmony_ci list_add_tail(&bf->list, bf_q); 151362306a36Sopenharmony_ci if (bf_prev) 151462306a36Sopenharmony_ci bf_prev->bf_next = bf; 151562306a36Sopenharmony_ci bf_prev = bf; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (nframes >= 2) 151862306a36Sopenharmony_ci break; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 152162306a36Sopenharmony_ci if (ret < 0) 152262306a36Sopenharmony_ci break; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 152562306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 152662306a36Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 152762306a36Sopenharmony_ci break; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 153162306a36Sopenharmony_ci } while (1); 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, 153562306a36Sopenharmony_ci struct ath_atx_tid *tid) 153662306a36Sopenharmony_ci{ 153762306a36Sopenharmony_ci struct ath_buf *bf = NULL; 153862306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info; 153962306a36Sopenharmony_ci struct list_head bf_q; 154062306a36Sopenharmony_ci int aggr_len = 0, ret; 154162306a36Sopenharmony_ci bool aggr; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); 154662306a36Sopenharmony_ci if (ret < 0) 154762306a36Sopenharmony_ci return ret; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); 155062306a36Sopenharmony_ci aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); 155162306a36Sopenharmony_ci if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || 155262306a36Sopenharmony_ci (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { 155362306a36Sopenharmony_ci __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); 155462306a36Sopenharmony_ci return -EBUSY; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 155862306a36Sopenharmony_ci if (aggr) 155962306a36Sopenharmony_ci aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); 156062306a36Sopenharmony_ci else 156162306a36Sopenharmony_ci ath_tx_form_burst(sc, txq, tid, &bf_q, bf); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (list_empty(&bf_q)) 156462306a36Sopenharmony_ci return -EAGAIN; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (tid->clear_ps_filter || tid->an->no_ps_filter) { 156762306a36Sopenharmony_ci tid->clear_ps_filter = false; 156862306a36Sopenharmony_ci tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, aggr_len); 157262306a36Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, false); 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ciint ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, 157762306a36Sopenharmony_ci u16 tid, u16 *ssn) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 158062306a36Sopenharmony_ci struct ath_atx_tid *txtid; 158162306a36Sopenharmony_ci struct ath_txq *txq; 158262306a36Sopenharmony_ci struct ath_node *an; 158362306a36Sopenharmony_ci u8 density; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 158862306a36Sopenharmony_ci txtid = ATH_AN_2_TID(an, tid); 158962306a36Sopenharmony_ci txq = txtid->txq; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci ath_txq_lock(sc, txq); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* update ampdu factor/density, they may have changed. This may happen 159462306a36Sopenharmony_ci * in HT IBSS when a beacon with HT-info is received after the station 159562306a36Sopenharmony_ci * has already been added. 159662306a36Sopenharmony_ci */ 159762306a36Sopenharmony_ci if (sta->deflink.ht_cap.ht_supported) { 159862306a36Sopenharmony_ci an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 159962306a36Sopenharmony_ci sta->deflink.ht_cap.ampdu_factor)) - 1; 160062306a36Sopenharmony_ci density = ath9k_parse_mpdudensity(sta->deflink.ht_cap.ampdu_density); 160162306a36Sopenharmony_ci an->mpdudensity = density; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci txtid->active = true; 160562306a36Sopenharmony_ci *ssn = txtid->seq_start = txtid->seq_next; 160662306a36Sopenharmony_ci txtid->bar_index = -1; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); 160962306a36Sopenharmony_ci txtid->baw_head = txtid->baw_tail = 0; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return 0; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_civoid ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 161962306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 162062306a36Sopenharmony_ci struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); 162162306a36Sopenharmony_ci struct ath_txq *txq = txtid->txq; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci ath_txq_lock(sc, txq); 162662306a36Sopenharmony_ci txtid->active = false; 162762306a36Sopenharmony_ci ath_tx_flush_tid(sc, txtid); 162862306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 162962306a36Sopenharmony_ci} 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_civoid ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, 163262306a36Sopenharmony_ci struct ath_node *an) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 163562306a36Sopenharmony_ci struct ath_atx_tid *tid; 163662306a36Sopenharmony_ci int tidno; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 164162306a36Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (!skb_queue_empty(&tid->retry_q)) 164462306a36Sopenharmony_ci ieee80211_sta_set_buffered(sta, tid->tidno, true); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_civoid ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 165262306a36Sopenharmony_ci struct ath_atx_tid *tid; 165362306a36Sopenharmony_ci struct ath_txq *txq; 165462306a36Sopenharmony_ci int tidno; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci ath_dbg(common, XMIT, "%s called\n", __func__); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 165962306a36Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 166062306a36Sopenharmony_ci txq = tid->txq; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci ath_txq_lock(sc, txq); 166362306a36Sopenharmony_ci tid->clear_ps_filter = true; 166462306a36Sopenharmony_ci if (!skb_queue_empty(&tid->retry_q)) { 166562306a36Sopenharmony_ci ath_tx_queue_tid(sc, tid); 166662306a36Sopenharmony_ci ath_txq_schedule(sc, txq); 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic void 167562306a36Sopenharmony_ciath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 167862306a36Sopenharmony_ci u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); 167962306a36Sopenharmony_ci u16 mask_val = mask * val; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; 168262306a36Sopenharmony_ci if ((hdr->frame_control & mask) != mask_val) { 168362306a36Sopenharmony_ci hdr->frame_control = (hdr->frame_control & ~mask) | mask_val; 168462306a36Sopenharmony_ci dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, 168562306a36Sopenharmony_ci sizeof(*hdr), DMA_TO_DEVICE); 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_civoid ath9k_release_buffered_frames(struct ieee80211_hw *hw, 169062306a36Sopenharmony_ci struct ieee80211_sta *sta, 169162306a36Sopenharmony_ci u16 tids, int nframes, 169262306a36Sopenharmony_ci enum ieee80211_frame_release_type reason, 169362306a36Sopenharmony_ci bool more_data) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 169662306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 169762306a36Sopenharmony_ci struct ath_txq *txq = sc->tx.uapsdq; 169862306a36Sopenharmony_ci struct ieee80211_tx_info *info; 169962306a36Sopenharmony_ci struct list_head bf_q; 170062306a36Sopenharmony_ci struct ath_buf *bf_tail = NULL, *bf = NULL; 170162306a36Sopenharmony_ci int i, ret; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 170462306a36Sopenharmony_ci for (i = 0; tids && nframes; i++, tids >>= 1) { 170562306a36Sopenharmony_ci struct ath_atx_tid *tid; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci if (!(tids & 1)) 170862306a36Sopenharmony_ci continue; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci tid = ATH_AN_2_TID(an, i); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci ath_txq_lock(sc, tid->txq); 171362306a36Sopenharmony_ci while (nframes > 0) { 171462306a36Sopenharmony_ci ret = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, 171562306a36Sopenharmony_ci tid, &bf); 171662306a36Sopenharmony_ci if (ret < 0) 171762306a36Sopenharmony_ci break; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci ath9k_set_moredata(sc, bf, true); 172062306a36Sopenharmony_ci list_add_tail(&bf->list, &bf_q); 172162306a36Sopenharmony_ci ath_set_rates(tid->an->vif, tid->an->sta, bf); 172262306a36Sopenharmony_ci if (bf_isampdu(bf)) 172362306a36Sopenharmony_ci bf->bf_state.bf_type &= ~BUF_AGGR; 172462306a36Sopenharmony_ci if (bf_tail) 172562306a36Sopenharmony_ci bf_tail->bf_next = bf; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci bf_tail = bf; 172862306a36Sopenharmony_ci nframes--; 172962306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, a_queued_hw); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (an->sta && skb_queue_empty(&tid->retry_q)) 173262306a36Sopenharmony_ci ieee80211_sta_set_buffered(an->sta, i, false); 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci ath_txq_unlock_complete(sc, tid->txq); 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (list_empty(&bf_q)) 173862306a36Sopenharmony_ci return; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci if (!more_data) 174162306a36Sopenharmony_ci ath9k_set_moredata(sc, bf_tail, false); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci info = IEEE80211_SKB_CB(bf_tail->bf_mpdu); 174462306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STATUS_EOSP; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci bf = list_first_entry(&bf_q, struct ath_buf, list); 174762306a36Sopenharmony_ci ath_txq_lock(sc, txq); 174862306a36Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, 0); 174962306a36Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, false); 175062306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci/********************/ 175462306a36Sopenharmony_ci/* Queue Management */ 175562306a36Sopenharmony_ci/********************/ 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistruct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) 175862306a36Sopenharmony_ci{ 175962306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 176062306a36Sopenharmony_ci struct ath9k_tx_queue_info qi; 176162306a36Sopenharmony_ci static const int subtype_txq_to_hwq[] = { 176262306a36Sopenharmony_ci [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, 176362306a36Sopenharmony_ci [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, 176462306a36Sopenharmony_ci [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, 176562306a36Sopenharmony_ci [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, 176662306a36Sopenharmony_ci }; 176762306a36Sopenharmony_ci int axq_qnum, i; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci memset(&qi, 0, sizeof(qi)); 177062306a36Sopenharmony_ci qi.tqi_subtype = subtype_txq_to_hwq[subtype]; 177162306a36Sopenharmony_ci qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; 177262306a36Sopenharmony_ci qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; 177362306a36Sopenharmony_ci qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; 177462306a36Sopenharmony_ci qi.tqi_physCompBuf = 0; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci /* 177762306a36Sopenharmony_ci * Enable interrupts only for EOL and DESC conditions. 177862306a36Sopenharmony_ci * We mark tx descriptors to receive a DESC interrupt 177962306a36Sopenharmony_ci * when a tx queue gets deep; otherwise waiting for the 178062306a36Sopenharmony_ci * EOL to reap descriptors. Note that this is done to 178162306a36Sopenharmony_ci * reduce interrupt load and this only defers reaping 178262306a36Sopenharmony_ci * descriptors, never transmitting frames. Aside from 178362306a36Sopenharmony_ci * reducing interrupts this also permits more concurrency. 178462306a36Sopenharmony_ci * The only potential downside is if the tx queue backs 178562306a36Sopenharmony_ci * up in which case the top half of the kernel may backup 178662306a36Sopenharmony_ci * due to a lack of tx descriptors. 178762306a36Sopenharmony_ci * 178862306a36Sopenharmony_ci * The UAPSD queue is an exception, since we take a desc- 178962306a36Sopenharmony_ci * based intr on the EOSP frames. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 179262306a36Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; 179362306a36Sopenharmony_ci } else { 179462306a36Sopenharmony_ci if (qtype == ATH9K_TX_QUEUE_UAPSD) 179562306a36Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; 179662306a36Sopenharmony_ci else 179762306a36Sopenharmony_ci qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | 179862306a36Sopenharmony_ci TXQ_FLAG_TXDESCINT_ENABLE; 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); 180162306a36Sopenharmony_ci if (axq_qnum == -1) { 180262306a36Sopenharmony_ci /* 180362306a36Sopenharmony_ci * NB: don't print a message, this happens 180462306a36Sopenharmony_ci * normally on parts with too few tx queues 180562306a36Sopenharmony_ci */ 180662306a36Sopenharmony_ci return NULL; 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, axq_qnum)) { 180962306a36Sopenharmony_ci struct ath_txq *txq = &sc->tx.txq[axq_qnum]; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci txq->axq_qnum = axq_qnum; 181262306a36Sopenharmony_ci txq->mac80211_qnum = -1; 181362306a36Sopenharmony_ci txq->axq_link = NULL; 181462306a36Sopenharmony_ci __skb_queue_head_init(&txq->complete_q); 181562306a36Sopenharmony_ci INIT_LIST_HEAD(&txq->axq_q); 181662306a36Sopenharmony_ci spin_lock_init(&txq->axq_lock); 181762306a36Sopenharmony_ci txq->axq_depth = 0; 181862306a36Sopenharmony_ci txq->axq_ampdu_depth = 0; 181962306a36Sopenharmony_ci txq->axq_tx_inprogress = false; 182062306a36Sopenharmony_ci sc->tx.txqsetup |= 1<<axq_qnum; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci txq->txq_headidx = txq->txq_tailidx = 0; 182362306a36Sopenharmony_ci for (i = 0; i < ATH_TXFIFO_DEPTH; i++) 182462306a36Sopenharmony_ci INIT_LIST_HEAD(&txq->txq_fifo[i]); 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci return &sc->tx.txq[axq_qnum]; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ciint ath_txq_update(struct ath_softc *sc, int qnum, 183062306a36Sopenharmony_ci struct ath9k_tx_queue_info *qinfo) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 183362306a36Sopenharmony_ci int error = 0; 183462306a36Sopenharmony_ci struct ath9k_tx_queue_info qi; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci ath9k_hw_get_txq_props(ah, qnum, &qi); 183962306a36Sopenharmony_ci qi.tqi_aifs = qinfo->tqi_aifs; 184062306a36Sopenharmony_ci qi.tqi_cwmin = qinfo->tqi_cwmin; 184162306a36Sopenharmony_ci qi.tqi_cwmax = qinfo->tqi_cwmax; 184262306a36Sopenharmony_ci qi.tqi_burstTime = qinfo->tqi_burstTime; 184362306a36Sopenharmony_ci qi.tqi_readyTime = qinfo->tqi_readyTime; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 184662306a36Sopenharmony_ci ath_err(ath9k_hw_common(sc->sc_ah), 184762306a36Sopenharmony_ci "Unable to update hardware queue %u!\n", qnum); 184862306a36Sopenharmony_ci error = -EIO; 184962306a36Sopenharmony_ci } else { 185062306a36Sopenharmony_ci ath9k_hw_resettxqueue(ah, qnum); 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci return error; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ciint ath_cabq_update(struct ath_softc *sc) 185762306a36Sopenharmony_ci{ 185862306a36Sopenharmony_ci struct ath9k_tx_queue_info qi; 185962306a36Sopenharmony_ci struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; 186062306a36Sopenharmony_ci int qnum = sc->beacon.cabq->axq_qnum; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * 186562306a36Sopenharmony_ci ATH_CABQ_READY_TIME) / 100; 186662306a36Sopenharmony_ci ath_txq_update(sc, qnum, &qi); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci return 0; 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_cistatic void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, 187262306a36Sopenharmony_ci struct list_head *list) 187362306a36Sopenharmony_ci{ 187462306a36Sopenharmony_ci struct ath_buf *bf, *lastbf; 187562306a36Sopenharmony_ci struct list_head bf_head; 187662306a36Sopenharmony_ci struct ath_tx_status ts; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 187962306a36Sopenharmony_ci ts.ts_status = ATH9K_TX_FLUSH; 188062306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci while (!list_empty(list)) { 188362306a36Sopenharmony_ci bf = list_first_entry(list, struct ath_buf, list); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (bf->bf_state.stale) { 188662306a36Sopenharmony_ci list_del(&bf->list); 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci ath_tx_return_buffer(sc, bf); 188962306a36Sopenharmony_ci continue; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci lastbf = bf->bf_lastbf; 189362306a36Sopenharmony_ci list_cut_position(&bf_head, list, &lastbf->list); 189462306a36Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci/* 189962306a36Sopenharmony_ci * Drain a given TX queue (could be Beacon or Data) 190062306a36Sopenharmony_ci * 190162306a36Sopenharmony_ci * This assumes output has been stopped and 190262306a36Sopenharmony_ci * we do not need to block ath_tx_tasklet. 190362306a36Sopenharmony_ci */ 190462306a36Sopenharmony_civoid ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) 190562306a36Sopenharmony_ci{ 190662306a36Sopenharmony_ci rcu_read_lock(); 190762306a36Sopenharmony_ci ath_txq_lock(sc, txq); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 191062306a36Sopenharmony_ci int idx = txq->txq_tailidx; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci while (!list_empty(&txq->txq_fifo[idx])) { 191362306a36Sopenharmony_ci ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci INCR(idx, ATH_TXFIFO_DEPTH); 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci txq->txq_tailidx = idx; 191862306a36Sopenharmony_ci } 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci txq->axq_link = NULL; 192162306a36Sopenharmony_ci txq->axq_tx_inprogress = false; 192262306a36Sopenharmony_ci ath_drain_txq_list(sc, txq, &txq->axq_q); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 192562306a36Sopenharmony_ci rcu_read_unlock(); 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cibool ath_drain_all_txq(struct ath_softc *sc) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 193162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 193262306a36Sopenharmony_ci struct ath_txq *txq; 193362306a36Sopenharmony_ci int i; 193462306a36Sopenharmony_ci u32 npend = 0; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci if (test_bit(ATH_OP_INVALID, &common->op_flags)) 193762306a36Sopenharmony_ci return true; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci ath9k_hw_abort_tx_dma(ah); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci /* Check if any queue remains active */ 194262306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 194362306a36Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 194462306a36Sopenharmony_ci continue; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (!sc->tx.txq[i].axq_depth) 194762306a36Sopenharmony_ci continue; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum)) 195062306a36Sopenharmony_ci npend |= BIT(i); 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (npend) { 195462306a36Sopenharmony_ci RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); 195562306a36Sopenharmony_ci ath_dbg(common, RESET, 195662306a36Sopenharmony_ci "Failed to stop TX DMA, queues=0x%03x!\n", npend); 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 196062306a36Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 196162306a36Sopenharmony_ci continue; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci txq = &sc->tx.txq[i]; 196462306a36Sopenharmony_ci ath_draintxq(sc, txq); 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci return !npend; 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_civoid ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) 197162306a36Sopenharmony_ci{ 197262306a36Sopenharmony_ci ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); 197362306a36Sopenharmony_ci sc->tx.txqsetup &= ~(1<<txq->axq_qnum); 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci/* For each acq entry, for each tid, try to schedule packets 197762306a36Sopenharmony_ci * for transmit until ampdu_depth has reached min Q depth. 197862306a36Sopenharmony_ci */ 197962306a36Sopenharmony_civoid ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) 198062306a36Sopenharmony_ci{ 198162306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 198262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 198362306a36Sopenharmony_ci struct ieee80211_txq *queue; 198462306a36Sopenharmony_ci struct ath_atx_tid *tid; 198562306a36Sopenharmony_ci int ret; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (txq->mac80211_qnum < 0) 198862306a36Sopenharmony_ci return; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 199162306a36Sopenharmony_ci return; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci ieee80211_txq_schedule_start(hw, txq->mac80211_qnum); 199462306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 199562306a36Sopenharmony_ci rcu_read_lock(); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (sc->cur_chan->stopped) 199862306a36Sopenharmony_ci goto out; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci while ((queue = ieee80211_next_txq(hw, txq->mac80211_qnum))) { 200162306a36Sopenharmony_ci bool force; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci tid = (struct ath_atx_tid *)queue->drv_priv; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci ret = ath_tx_sched_aggr(sc, txq, tid); 200662306a36Sopenharmony_ci ath_dbg(common, QUEUE, "ath_tx_sched_aggr returned %d\n", ret); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci force = !skb_queue_empty(&tid->retry_q); 200962306a36Sopenharmony_ci ieee80211_return_txq(hw, queue, force); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ciout: 201362306a36Sopenharmony_ci rcu_read_unlock(); 201462306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 201562306a36Sopenharmony_ci ieee80211_txq_schedule_end(hw, txq->mac80211_qnum); 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_civoid ath_txq_schedule_all(struct ath_softc *sc) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct ath_txq *txq; 202162306a36Sopenharmony_ci int i; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 202462306a36Sopenharmony_ci txq = sc->tx.txq_map[i]; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci spin_lock_bh(&txq->axq_lock); 202762306a36Sopenharmony_ci ath_txq_schedule(sc, txq); 202862306a36Sopenharmony_ci spin_unlock_bh(&txq->axq_lock); 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci} 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci/***********/ 203362306a36Sopenharmony_ci/* TX, DMA */ 203462306a36Sopenharmony_ci/***********/ 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci/* 203762306a36Sopenharmony_ci * Insert a chain of ath_buf (descriptors) on a txq and 203862306a36Sopenharmony_ci * assume the descriptors are already chained together by caller. 203962306a36Sopenharmony_ci */ 204062306a36Sopenharmony_cistatic void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, 204162306a36Sopenharmony_ci struct list_head *head, bool internal) 204262306a36Sopenharmony_ci{ 204362306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 204462306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 204562306a36Sopenharmony_ci struct ath_buf *bf, *bf_last; 204662306a36Sopenharmony_ci bool puttxbuf = false; 204762306a36Sopenharmony_ci bool edma; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci /* 205062306a36Sopenharmony_ci * Insert the frame on the outbound list and 205162306a36Sopenharmony_ci * pass it on to the hardware. 205262306a36Sopenharmony_ci */ 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (list_empty(head)) 205562306a36Sopenharmony_ci return; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); 205862306a36Sopenharmony_ci bf = list_first_entry(head, struct ath_buf, list); 205962306a36Sopenharmony_ci bf_last = list_entry(head->prev, struct ath_buf, list); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci ath_dbg(common, QUEUE, "qnum: %d, txq depth: %d\n", 206262306a36Sopenharmony_ci txq->axq_qnum, txq->axq_depth); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) { 206562306a36Sopenharmony_ci list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]); 206662306a36Sopenharmony_ci INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); 206762306a36Sopenharmony_ci puttxbuf = true; 206862306a36Sopenharmony_ci } else { 206962306a36Sopenharmony_ci list_splice_tail_init(head, &txq->axq_q); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (txq->axq_link) { 207262306a36Sopenharmony_ci ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr); 207362306a36Sopenharmony_ci ath_dbg(common, XMIT, "link[%u] (%p)=%llx (%p)\n", 207462306a36Sopenharmony_ci txq->axq_qnum, txq->axq_link, 207562306a36Sopenharmony_ci ito64(bf->bf_daddr), bf->bf_desc); 207662306a36Sopenharmony_ci } else if (!edma) 207762306a36Sopenharmony_ci puttxbuf = true; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci txq->axq_link = bf_last->bf_desc; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if (puttxbuf) { 208362306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, puttxbuf); 208462306a36Sopenharmony_ci ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 208562306a36Sopenharmony_ci ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n", 208662306a36Sopenharmony_ci txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (!edma || sc->tx99_state) { 209062306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txstart); 209162306a36Sopenharmony_ci ath9k_hw_txstart(ah, txq->axq_qnum); 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci if (!internal) { 209562306a36Sopenharmony_ci while (bf) { 209662306a36Sopenharmony_ci txq->axq_depth++; 209762306a36Sopenharmony_ci if (bf_is_ampdu_not_probing(bf)) 209862306a36Sopenharmony_ci txq->axq_ampdu_depth++; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci bf_last = bf->bf_lastbf; 210162306a36Sopenharmony_ci bf = bf_last->bf_next; 210262306a36Sopenharmony_ci bf_last->bf_next = NULL; 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci } 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_cistatic void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, 210862306a36Sopenharmony_ci struct ath_atx_tid *tid, struct sk_buff *skb) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 211162306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 211262306a36Sopenharmony_ci struct list_head bf_head; 211362306a36Sopenharmony_ci struct ath_buf *bf = fi->bf; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 211662306a36Sopenharmony_ci list_add_tail(&bf->list, &bf_head); 211762306a36Sopenharmony_ci bf->bf_state.bf_type = 0; 211862306a36Sopenharmony_ci if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { 211962306a36Sopenharmony_ci bf->bf_state.bf_type = BUF_AMPDU; 212062306a36Sopenharmony_ci ath_tx_addto_baw(sc, tid, bf); 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci bf->bf_next = NULL; 212462306a36Sopenharmony_ci bf->bf_lastbf = bf; 212562306a36Sopenharmony_ci ath_tx_fill_desc(sc, bf, txq, fi->framelen); 212662306a36Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_head, false); 212762306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, queued); 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic void setup_frame_info(struct ieee80211_hw *hw, 213162306a36Sopenharmony_ci struct ieee80211_sta *sta, 213262306a36Sopenharmony_ci struct sk_buff *skb, 213362306a36Sopenharmony_ci int framelen) 213462306a36Sopenharmony_ci{ 213562306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 213662306a36Sopenharmony_ci struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; 213762306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 213862306a36Sopenharmony_ci const struct ieee80211_rate *rate; 213962306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 214062306a36Sopenharmony_ci struct ath_node *an = NULL; 214162306a36Sopenharmony_ci enum ath9k_key_type keytype; 214262306a36Sopenharmony_ci bool short_preamble = false; 214362306a36Sopenharmony_ci u8 txpower; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci /* 214662306a36Sopenharmony_ci * We check if Short Preamble is needed for the CTS rate by 214762306a36Sopenharmony_ci * checking the BSS's global flag. 214862306a36Sopenharmony_ci * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. 214962306a36Sopenharmony_ci */ 215062306a36Sopenharmony_ci if (tx_info->control.vif && 215162306a36Sopenharmony_ci tx_info->control.vif->bss_conf.use_short_preamble) 215262306a36Sopenharmony_ci short_preamble = true; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci rate = ieee80211_get_rts_cts_rate(hw, tx_info); 215562306a36Sopenharmony_ci keytype = ath9k_cmn_get_hw_crypto_keytype(skb); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (sta) 215862306a36Sopenharmony_ci an = (struct ath_node *) sta->drv_priv; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci if (tx_info->control.vif) { 216162306a36Sopenharmony_ci struct ieee80211_vif *vif = tx_info->control.vif; 216262306a36Sopenharmony_ci if (vif->bss_conf.txpower == INT_MIN) 216362306a36Sopenharmony_ci goto nonvifpower; 216462306a36Sopenharmony_ci txpower = 2 * vif->bss_conf.txpower; 216562306a36Sopenharmony_ci } else { 216662306a36Sopenharmony_ci struct ath_softc *sc; 216762306a36Sopenharmony_ci nonvifpower: 216862306a36Sopenharmony_ci sc = hw->priv; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci txpower = sc->cur_chan->cur_txpower; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci memset(fi, 0, sizeof(*fi)); 217462306a36Sopenharmony_ci fi->txq = -1; 217562306a36Sopenharmony_ci if (hw_key) 217662306a36Sopenharmony_ci fi->keyix = hw_key->hw_key_idx; 217762306a36Sopenharmony_ci else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) 217862306a36Sopenharmony_ci fi->keyix = an->ps_key; 217962306a36Sopenharmony_ci else 218062306a36Sopenharmony_ci fi->keyix = ATH9K_TXKEYIX_INVALID; 218162306a36Sopenharmony_ci fi->dyn_smps = sta && sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC; 218262306a36Sopenharmony_ci fi->keytype = keytype; 218362306a36Sopenharmony_ci fi->framelen = framelen; 218462306a36Sopenharmony_ci fi->tx_power = txpower; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci if (!rate) 218762306a36Sopenharmony_ci return; 218862306a36Sopenharmony_ci fi->rtscts_rate = rate->hw_value; 218962306a36Sopenharmony_ci if (short_preamble) 219062306a36Sopenharmony_ci fi->rtscts_rate |= rate->hw_value_short; 219162306a36Sopenharmony_ci} 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ciu8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 219662306a36Sopenharmony_ci struct ath9k_channel *curchan = ah->curchan; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && IS_CHAN_5GHZ(curchan) && 219962306a36Sopenharmony_ci (chainmask == 0x7) && (rate < 0x90)) 220062306a36Sopenharmony_ci return 0x3; 220162306a36Sopenharmony_ci else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) && 220262306a36Sopenharmony_ci IS_CCK_RATE(rate)) 220362306a36Sopenharmony_ci return 0x2; 220462306a36Sopenharmony_ci else 220562306a36Sopenharmony_ci return chainmask; 220662306a36Sopenharmony_ci} 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci/* 220962306a36Sopenharmony_ci * Assign a descriptor (and sequence number if necessary, 221062306a36Sopenharmony_ci * and map buffer for DMA. Frees skb on error 221162306a36Sopenharmony_ci */ 221262306a36Sopenharmony_cistatic struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, 221362306a36Sopenharmony_ci struct ath_txq *txq, 221462306a36Sopenharmony_ci struct ath_atx_tid *tid, 221562306a36Sopenharmony_ci struct sk_buff *skb) 221662306a36Sopenharmony_ci{ 221762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 221862306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 221962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 222062306a36Sopenharmony_ci struct ath_buf *bf; 222162306a36Sopenharmony_ci int fragno; 222262306a36Sopenharmony_ci u16 seqno; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci bf = ath_tx_get_buffer(sc); 222562306a36Sopenharmony_ci if (!bf) { 222662306a36Sopenharmony_ci ath_dbg(common, XMIT, "TX buffers are full\n"); 222762306a36Sopenharmony_ci return NULL; 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci ATH_TXBUF_RESET(bf); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (tid && ieee80211_is_data_present(hdr->frame_control)) { 223362306a36Sopenharmony_ci fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; 223462306a36Sopenharmony_ci seqno = tid->seq_next; 223562306a36Sopenharmony_ci hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci if (fragno) 223862306a36Sopenharmony_ci hdr->seq_ctrl |= cpu_to_le16(fragno); 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci if (!ieee80211_has_morefrags(hdr->frame_control)) 224162306a36Sopenharmony_ci INCR(tid->seq_next, IEEE80211_SEQ_MAX); 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci bf->bf_state.seqno = seqno; 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci bf->bf_mpdu = skb; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, 224962306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 225062306a36Sopenharmony_ci if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 225162306a36Sopenharmony_ci bf->bf_mpdu = NULL; 225262306a36Sopenharmony_ci bf->bf_buf_addr = 0; 225362306a36Sopenharmony_ci ath_err(ath9k_hw_common(sc->sc_ah), 225462306a36Sopenharmony_ci "dma_mapping_error() on TX\n"); 225562306a36Sopenharmony_ci ath_tx_return_buffer(sc, bf); 225662306a36Sopenharmony_ci return NULL; 225762306a36Sopenharmony_ci } 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci fi->bf = bf; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci return bf; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_civoid ath_assign_seq(struct ath_common *common, struct sk_buff *skb) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 226762306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 226862306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 226962306a36Sopenharmony_ci struct ath_vif *avp; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) 227262306a36Sopenharmony_ci return; 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci if (!vif) 227562306a36Sopenharmony_ci return; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci avp = (struct ath_vif *)vif->drv_priv; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) 228062306a36Sopenharmony_ci avp->seq_no += 0x10; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 228362306a36Sopenharmony_ci hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_cistatic int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, 228762306a36Sopenharmony_ci struct ath_tx_control *txctl) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 229062306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 229162306a36Sopenharmony_ci struct ieee80211_sta *sta = txctl->sta; 229262306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 229362306a36Sopenharmony_ci struct ath_vif *avp; 229462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 229562306a36Sopenharmony_ci int frmlen = skb->len + FCS_LEN; 229662306a36Sopenharmony_ci int padpos, padsize; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci /* NOTE: sta can be NULL according to net/mac80211.h */ 229962306a36Sopenharmony_ci if (sta) 230062306a36Sopenharmony_ci txctl->an = (struct ath_node *)sta->drv_priv; 230162306a36Sopenharmony_ci else if (vif && ieee80211_is_data(hdr->frame_control)) { 230262306a36Sopenharmony_ci avp = (void *)vif->drv_priv; 230362306a36Sopenharmony_ci txctl->an = &avp->mcast_node; 230462306a36Sopenharmony_ci } 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci if (info->control.hw_key) 230762306a36Sopenharmony_ci frmlen += info->control.hw_key->icv_len; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci if ((vif && vif->type != NL80211_IFTYPE_AP && 231262306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_AP_VLAN) || 231362306a36Sopenharmony_ci !ieee80211_is_data(hdr->frame_control)) 231462306a36Sopenharmony_ci info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* Add the padding after the header if this is not already done */ 231762306a36Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 231862306a36Sopenharmony_ci padsize = padpos & 3; 231962306a36Sopenharmony_ci if (padsize && skb->len > padpos) { 232062306a36Sopenharmony_ci if (skb_headroom(skb) < padsize) 232162306a36Sopenharmony_ci return -ENOMEM; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci skb_push(skb, padsize); 232462306a36Sopenharmony_ci memmove(skb->data, skb->data + padsize, padpos); 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci setup_frame_info(hw, sta, skb, frmlen); 232862306a36Sopenharmony_ci return 0; 232962306a36Sopenharmony_ci} 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci/* Upon failure caller should free skb */ 233362306a36Sopenharmony_ciint ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, 233462306a36Sopenharmony_ci struct ath_tx_control *txctl) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 233762306a36Sopenharmony_ci struct ieee80211_sta *sta = txctl->sta; 233862306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 233962306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 234062306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 234162306a36Sopenharmony_ci struct ath_txq *txq = txctl->txq; 234262306a36Sopenharmony_ci struct ath_atx_tid *tid = NULL; 234362306a36Sopenharmony_ci struct ath_node *an = NULL; 234462306a36Sopenharmony_ci struct ath_buf *bf; 234562306a36Sopenharmony_ci bool ps_resp; 234662306a36Sopenharmony_ci int q, ret; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci ret = ath_tx_prepare(hw, skb, txctl); 235162306a36Sopenharmony_ci if (ret) 235262306a36Sopenharmony_ci return ret; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* 235562306a36Sopenharmony_ci * At this point, the vif, hw_key and sta pointers in the tx control 235662306a36Sopenharmony_ci * info are no longer valid (overwritten by the ath_frame_info data. 235762306a36Sopenharmony_ci */ 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci q = skb_get_queue_mapping(skb); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci if (ps_resp) 236262306a36Sopenharmony_ci txq = sc->tx.uapsdq; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci if (txctl->sta) { 236562306a36Sopenharmony_ci an = (struct ath_node *) sta->drv_priv; 236662306a36Sopenharmony_ci tid = ath_get_skb_tid(sc, an, skb); 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci ath_txq_lock(sc, txq); 237062306a36Sopenharmony_ci if (txq == sc->tx.txq_map[q]) { 237162306a36Sopenharmony_ci fi->txq = q; 237262306a36Sopenharmony_ci ++txq->pending_frames; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txq, tid, skb); 237662306a36Sopenharmony_ci if (!bf) { 237762306a36Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 237862306a36Sopenharmony_ci if (txctl->paprd) 237962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 238062306a36Sopenharmony_ci else 238162306a36Sopenharmony_ci ieee80211_free_txskb(sc->hw, skb); 238262306a36Sopenharmony_ci goto out; 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci bf->bf_state.bfs_paprd = txctl->paprd; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (txctl->paprd) 238862306a36Sopenharmony_ci bf->bf_state.bfs_paprd_timestamp = jiffies; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci ath_set_rates(vif, sta, bf); 239162306a36Sopenharmony_ci ath_tx_send_normal(sc, txq, tid, skb); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ciout: 239462306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci return 0; 239762306a36Sopenharmony_ci} 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_civoid ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 240062306a36Sopenharmony_ci struct sk_buff *skb) 240162306a36Sopenharmony_ci{ 240262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 240362306a36Sopenharmony_ci struct ath_tx_control txctl = { 240462306a36Sopenharmony_ci .txq = sc->beacon.cabq 240562306a36Sopenharmony_ci }; 240662306a36Sopenharmony_ci struct ath_tx_info info = {}; 240762306a36Sopenharmony_ci struct ath_buf *bf_tail = NULL; 240862306a36Sopenharmony_ci struct ath_buf *bf; 240962306a36Sopenharmony_ci LIST_HEAD(bf_q); 241062306a36Sopenharmony_ci int duration = 0; 241162306a36Sopenharmony_ci int max_duration; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci max_duration = 241462306a36Sopenharmony_ci sc->cur_chan->beacon.beacon_interval * 1000 * 241562306a36Sopenharmony_ci sc->cur_chan->beacon.dtim_period / ATH_BCBUF; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci do { 241862306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (ath_tx_prepare(hw, skb, &txctl)) 242162306a36Sopenharmony_ci break; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txctl.txq, NULL, skb); 242462306a36Sopenharmony_ci if (!bf) 242562306a36Sopenharmony_ci break; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci bf->bf_lastbf = bf; 242862306a36Sopenharmony_ci ath_set_rates(vif, NULL, bf); 242962306a36Sopenharmony_ci ath_buf_set_rate(sc, bf, &info, fi->framelen, false); 243062306a36Sopenharmony_ci duration += info.rates[0].PktDuration; 243162306a36Sopenharmony_ci if (bf_tail) 243262306a36Sopenharmony_ci bf_tail->bf_next = bf; 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci list_add_tail(&bf->list, &bf_q); 243562306a36Sopenharmony_ci bf_tail = bf; 243662306a36Sopenharmony_ci skb = NULL; 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci if (duration > max_duration) 243962306a36Sopenharmony_ci break; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci skb = ieee80211_get_buffered_bc(hw, vif); 244262306a36Sopenharmony_ci } while(skb); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci if (skb) 244562306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci if (list_empty(&bf_q)) 244862306a36Sopenharmony_ci return; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci bf = list_last_entry(&bf_q, struct ath_buf, list); 245162306a36Sopenharmony_ci ath9k_set_moredata(sc, bf, false); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci bf = list_first_entry(&bf_q, struct ath_buf, list); 245462306a36Sopenharmony_ci ath_txq_lock(sc, txctl.txq); 245562306a36Sopenharmony_ci ath_tx_fill_desc(sc, bf, txctl.txq, 0); 245662306a36Sopenharmony_ci ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false); 245762306a36Sopenharmony_ci TX_STAT_INC(sc, txctl.txq->axq_qnum, queued); 245862306a36Sopenharmony_ci ath_txq_unlock(sc, txctl.txq); 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci/*****************/ 246262306a36Sopenharmony_ci/* TX Completion */ 246362306a36Sopenharmony_ci/*****************/ 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_cistatic void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, 246662306a36Sopenharmony_ci int tx_flags, struct ath_txq *txq, 246762306a36Sopenharmony_ci struct ieee80211_sta *sta) 246862306a36Sopenharmony_ci{ 246962306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 247062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 247162306a36Sopenharmony_ci struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; 247262306a36Sopenharmony_ci int padpos, padsize; 247362306a36Sopenharmony_ci unsigned long flags; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci if (sc->sc_ah->caldata) 247862306a36Sopenharmony_ci set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (!(tx_flags & ATH_TX_ERROR)) { 248162306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) 248262306a36Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 248362306a36Sopenharmony_ci else 248462306a36Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_ACK; 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 248862306a36Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 248962306a36Sopenharmony_ci padsize = padpos & 3; 249062306a36Sopenharmony_ci if (padsize && skb->len>padpos+padsize) { 249162306a36Sopenharmony_ci /* 249262306a36Sopenharmony_ci * Remove MAC header padding before giving the frame back to 249362306a36Sopenharmony_ci * mac80211. 249462306a36Sopenharmony_ci */ 249562306a36Sopenharmony_ci memmove(skb->data + padsize, skb->data, padpos); 249662306a36Sopenharmony_ci skb_pull(skb, padsize); 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 250162306a36Sopenharmony_ci if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) { 250262306a36Sopenharmony_ci sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; 250362306a36Sopenharmony_ci ath_dbg(common, PS, 250462306a36Sopenharmony_ci "Going back to sleep after having received TX status (0x%lx)\n", 250562306a36Sopenharmony_ci sc->ps_flags & (PS_WAIT_FOR_BEACON | 250662306a36Sopenharmony_ci PS_WAIT_FOR_CAB | 250762306a36Sopenharmony_ci PS_WAIT_FOR_PSPOLL_DATA | 250862306a36Sopenharmony_ci PS_WAIT_FOR_TX_ACK)); 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci ath_txq_skb_done(sc, txq, skb); 251362306a36Sopenharmony_ci tx_info->status.status_driver_data[0] = sta; 251462306a36Sopenharmony_ci __skb_queue_tail(&txq->complete_q, skb); 251562306a36Sopenharmony_ci} 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_cistatic void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 251862306a36Sopenharmony_ci struct ath_txq *txq, struct list_head *bf_q, 251962306a36Sopenharmony_ci struct ieee80211_sta *sta, 252062306a36Sopenharmony_ci struct ath_tx_status *ts, int txok) 252162306a36Sopenharmony_ci{ 252262306a36Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 252362306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 252462306a36Sopenharmony_ci unsigned long flags; 252562306a36Sopenharmony_ci int tx_flags = 0; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (!txok) 252862306a36Sopenharmony_ci tx_flags |= ATH_TX_ERROR; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci if (ts->ts_status & ATH9K_TXERR_FILT) 253162306a36Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); 253462306a36Sopenharmony_ci bf->bf_buf_addr = 0; 253562306a36Sopenharmony_ci if (sc->tx99_state) 253662306a36Sopenharmony_ci goto skip_tx_complete; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci if (bf->bf_state.bfs_paprd) { 253962306a36Sopenharmony_ci if (time_after(jiffies, 254062306a36Sopenharmony_ci bf->bf_state.bfs_paprd_timestamp + 254162306a36Sopenharmony_ci msecs_to_jiffies(ATH_PAPRD_TIMEOUT))) 254262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 254362306a36Sopenharmony_ci else 254462306a36Sopenharmony_ci complete(&sc->paprd_complete); 254562306a36Sopenharmony_ci } else { 254662306a36Sopenharmony_ci ath_debug_stat_tx(sc, bf, ts, txq, tx_flags); 254762306a36Sopenharmony_ci ath_tx_complete(sc, skb, tx_flags, txq, sta); 254862306a36Sopenharmony_ci } 254962306a36Sopenharmony_ciskip_tx_complete: 255062306a36Sopenharmony_ci /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't 255162306a36Sopenharmony_ci * accidentally reference it later. 255262306a36Sopenharmony_ci */ 255362306a36Sopenharmony_ci bf->bf_mpdu = NULL; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci /* 255662306a36Sopenharmony_ci * Return the list of ath_buf of this mpdu to free queue 255762306a36Sopenharmony_ci */ 255862306a36Sopenharmony_ci spin_lock_irqsave(&sc->tx.txbuflock, flags); 255962306a36Sopenharmony_ci list_splice_tail_init(bf_q, &sc->tx.txbuf); 256062306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->tx.txbuflock, flags); 256162306a36Sopenharmony_ci} 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_cistatic void ath_clear_tx_status(struct ieee80211_tx_info *tx_info) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci void *ptr = &tx_info->status; 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci memset(ptr + sizeof(tx_info->status.rates), 0, 256862306a36Sopenharmony_ci sizeof(tx_info->status) - 256962306a36Sopenharmony_ci sizeof(tx_info->status.rates) - 257062306a36Sopenharmony_ci sizeof(tx_info->status.status_driver_data)); 257162306a36Sopenharmony_ci} 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, 257462306a36Sopenharmony_ci struct ath_tx_status *ts, int nframes, int nbad, 257562306a36Sopenharmony_ci int txok) 257662306a36Sopenharmony_ci{ 257762306a36Sopenharmony_ci struct sk_buff *skb = bf->bf_mpdu; 257862306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 257962306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 258062306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 258162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 258262306a36Sopenharmony_ci u8 i, tx_rateindex; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci ath_clear_tx_status(tx_info); 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci if (txok) 258762306a36Sopenharmony_ci tx_info->status.ack_signal = ts->ts_rssi; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci tx_rateindex = ts->ts_rateindex; 259062306a36Sopenharmony_ci WARN_ON(tx_rateindex >= hw->max_rates); 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 259362306a36Sopenharmony_ci tx_info->flags |= IEEE80211_TX_STAT_AMPDU; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci BUG_ON(nbad > nframes); 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci tx_info->status.ampdu_len = nframes; 259862306a36Sopenharmony_ci tx_info->status.ampdu_ack_len = nframes - nbad; 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci for (i = tx_rateindex + 1; i < hw->max_rates; i++) { 260362306a36Sopenharmony_ci tx_info->status.rates[i].count = 0; 260462306a36Sopenharmony_ci tx_info->status.rates[i].idx = -1; 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && 260862306a36Sopenharmony_ci (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { 260962306a36Sopenharmony_ci /* 261062306a36Sopenharmony_ci * If an underrun error is seen assume it as an excessive 261162306a36Sopenharmony_ci * retry only if max frame trigger level has been reached 261262306a36Sopenharmony_ci * (2 KB for single stream, and 4 KB for dual stream). 261362306a36Sopenharmony_ci * Adjust the long retry as if the frame was tried 261462306a36Sopenharmony_ci * hw->max_rate_tries times to affect how rate control updates 261562306a36Sopenharmony_ci * PER for the failed rate. 261662306a36Sopenharmony_ci * In case of congestion on the bus penalizing this type of 261762306a36Sopenharmony_ci * underruns should help hardware actually transmit new frames 261862306a36Sopenharmony_ci * successfully by eventually preferring slower rates. 261962306a36Sopenharmony_ci * This itself should also alleviate congestion on the bus. 262062306a36Sopenharmony_ci */ 262162306a36Sopenharmony_ci if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | 262262306a36Sopenharmony_ci ATH9K_TX_DELIM_UNDERRUN)) && 262362306a36Sopenharmony_ci ieee80211_is_data(hdr->frame_control) && 262462306a36Sopenharmony_ci ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) 262562306a36Sopenharmony_ci tx_info->status.rates[tx_rateindex].count = 262662306a36Sopenharmony_ci hw->max_rate_tries; 262762306a36Sopenharmony_ci } 262862306a36Sopenharmony_ci} 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_cistatic void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) 263162306a36Sopenharmony_ci{ 263262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 263362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 263462306a36Sopenharmony_ci struct ath_buf *bf, *lastbf, *bf_held = NULL; 263562306a36Sopenharmony_ci struct list_head bf_head; 263662306a36Sopenharmony_ci struct ath_desc *ds; 263762306a36Sopenharmony_ci struct ath_tx_status ts; 263862306a36Sopenharmony_ci int status; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci ath_dbg(common, QUEUE, "tx queue %d (%x), link %p\n", 264162306a36Sopenharmony_ci txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), 264262306a36Sopenharmony_ci txq->axq_link); 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci ath_txq_lock(sc, txq); 264562306a36Sopenharmony_ci for (;;) { 264662306a36Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci if (list_empty(&txq->axq_q)) { 265062306a36Sopenharmony_ci txq->axq_link = NULL; 265162306a36Sopenharmony_ci ath_txq_schedule(sc, txq); 265262306a36Sopenharmony_ci break; 265362306a36Sopenharmony_ci } 265462306a36Sopenharmony_ci bf = list_first_entry(&txq->axq_q, struct ath_buf, list); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci /* 265762306a36Sopenharmony_ci * There is a race condition that a BH gets scheduled 265862306a36Sopenharmony_ci * after sw writes TxE and before hw re-load the last 265962306a36Sopenharmony_ci * descriptor to get the newly chained one. 266062306a36Sopenharmony_ci * Software must keep the last DONE descriptor as a 266162306a36Sopenharmony_ci * holding descriptor - software does so by marking 266262306a36Sopenharmony_ci * it with the STALE flag. 266362306a36Sopenharmony_ci */ 266462306a36Sopenharmony_ci bf_held = NULL; 266562306a36Sopenharmony_ci if (bf->bf_state.stale) { 266662306a36Sopenharmony_ci bf_held = bf; 266762306a36Sopenharmony_ci if (list_is_last(&bf_held->list, &txq->axq_q)) 266862306a36Sopenharmony_ci break; 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci bf = list_entry(bf_held->list.next, struct ath_buf, 267162306a36Sopenharmony_ci list); 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci lastbf = bf->bf_lastbf; 267562306a36Sopenharmony_ci ds = lastbf->bf_desc; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci memset(&ts, 0, sizeof(ts)); 267862306a36Sopenharmony_ci status = ath9k_hw_txprocdesc(ah, ds, &ts); 267962306a36Sopenharmony_ci if (status == -EINPROGRESS) 268062306a36Sopenharmony_ci break; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci /* 268562306a36Sopenharmony_ci * Remove ath_buf's of the same transmit unit from txq, 268662306a36Sopenharmony_ci * however leave the last descriptor back as the holding 268762306a36Sopenharmony_ci * descriptor for hw. 268862306a36Sopenharmony_ci */ 268962306a36Sopenharmony_ci lastbf->bf_state.stale = true; 269062306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 269162306a36Sopenharmony_ci if (!list_is_singular(&lastbf->list)) 269262306a36Sopenharmony_ci list_cut_position(&bf_head, 269362306a36Sopenharmony_ci &txq->axq_q, lastbf->list.prev); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (bf_held) { 269662306a36Sopenharmony_ci list_del(&bf_held->list); 269762306a36Sopenharmony_ci ath_tx_return_buffer(sc, bf_held); 269862306a36Sopenharmony_ci } 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 270162306a36Sopenharmony_ci } 270262306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 270362306a36Sopenharmony_ci} 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_civoid ath_tx_tasklet(struct ath_softc *sc) 270662306a36Sopenharmony_ci{ 270762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 270862306a36Sopenharmony_ci u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; 270962306a36Sopenharmony_ci int i; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci rcu_read_lock(); 271262306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 271362306a36Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) 271462306a36Sopenharmony_ci ath_tx_processq(sc, &sc->tx.txq[i]); 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci rcu_read_unlock(); 271762306a36Sopenharmony_ci} 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_civoid ath_tx_edma_tasklet(struct ath_softc *sc) 272062306a36Sopenharmony_ci{ 272162306a36Sopenharmony_ci struct ath_tx_status ts; 272262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 272362306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 272462306a36Sopenharmony_ci struct ath_txq *txq; 272562306a36Sopenharmony_ci struct ath_buf *bf, *lastbf; 272662306a36Sopenharmony_ci struct list_head bf_head; 272762306a36Sopenharmony_ci struct list_head *fifo_list; 272862306a36Sopenharmony_ci int status; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci rcu_read_lock(); 273162306a36Sopenharmony_ci for (;;) { 273262306a36Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) 273362306a36Sopenharmony_ci break; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); 273662306a36Sopenharmony_ci if (status == -EINPROGRESS) 273762306a36Sopenharmony_ci break; 273862306a36Sopenharmony_ci if (status == -EIO) { 273962306a36Sopenharmony_ci ath_dbg(common, XMIT, "Error processing tx status\n"); 274062306a36Sopenharmony_ci break; 274162306a36Sopenharmony_ci } 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci /* Process beacon completions separately */ 274462306a36Sopenharmony_ci if (ts.qid == sc->beacon.beaconq) { 274562306a36Sopenharmony_ci sc->beacon.tx_processed = true; 274662306a36Sopenharmony_ci sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 274962306a36Sopenharmony_ci ath_chanctx_event(sc, NULL, 275062306a36Sopenharmony_ci ATH_CHANCTX_EVENT_BEACON_SENT); 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci ath9k_csa_update(sc); 275462306a36Sopenharmony_ci continue; 275562306a36Sopenharmony_ci } 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci txq = &sc->tx.txq[ts.qid]; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci ath_txq_lock(sc, txq); 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci fifo_list = &txq->txq_fifo[txq->txq_tailidx]; 276462306a36Sopenharmony_ci if (list_empty(fifo_list)) { 276562306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 276662306a36Sopenharmony_ci break; 276762306a36Sopenharmony_ci } 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci bf = list_first_entry(fifo_list, struct ath_buf, list); 277062306a36Sopenharmony_ci if (bf->bf_state.stale) { 277162306a36Sopenharmony_ci list_del(&bf->list); 277262306a36Sopenharmony_ci ath_tx_return_buffer(sc, bf); 277362306a36Sopenharmony_ci bf = list_first_entry(fifo_list, struct ath_buf, list); 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci lastbf = bf->bf_lastbf; 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_head); 277962306a36Sopenharmony_ci if (list_is_last(&lastbf->list, fifo_list)) { 278062306a36Sopenharmony_ci list_splice_tail_init(fifo_list, &bf_head); 278162306a36Sopenharmony_ci INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci if (!list_empty(&txq->axq_q)) { 278462306a36Sopenharmony_ci struct list_head bf_q; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci INIT_LIST_HEAD(&bf_q); 278762306a36Sopenharmony_ci txq->axq_link = NULL; 278862306a36Sopenharmony_ci list_splice_tail_init(&txq->axq_q, &bf_q); 278962306a36Sopenharmony_ci ath_tx_txqaddbuf(sc, txq, &bf_q, true); 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci } else { 279262306a36Sopenharmony_ci lastbf->bf_state.stale = true; 279362306a36Sopenharmony_ci if (bf != lastbf) 279462306a36Sopenharmony_ci list_cut_position(&bf_head, fifo_list, 279562306a36Sopenharmony_ci lastbf->list.prev); 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); 279962306a36Sopenharmony_ci ath_txq_unlock_complete(sc, txq); 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci rcu_read_unlock(); 280262306a36Sopenharmony_ci} 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci/*****************/ 280562306a36Sopenharmony_ci/* Init, Cleanup */ 280662306a36Sopenharmony_ci/*****************/ 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_cistatic int ath_txstatus_setup(struct ath_softc *sc, int size) 280962306a36Sopenharmony_ci{ 281062306a36Sopenharmony_ci struct ath_descdma *dd = &sc->txsdma; 281162306a36Sopenharmony_ci u8 txs_len = sc->sc_ah->caps.txs_len; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci dd->dd_desc_len = size * txs_len; 281462306a36Sopenharmony_ci dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, 281562306a36Sopenharmony_ci &dd->dd_desc_paddr, GFP_KERNEL); 281662306a36Sopenharmony_ci if (!dd->dd_desc) 281762306a36Sopenharmony_ci return -ENOMEM; 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci return 0; 282062306a36Sopenharmony_ci} 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_cistatic int ath_tx_edma_init(struct ath_softc *sc) 282362306a36Sopenharmony_ci{ 282462306a36Sopenharmony_ci int err; 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE); 282762306a36Sopenharmony_ci if (!err) 282862306a36Sopenharmony_ci ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc, 282962306a36Sopenharmony_ci sc->txsdma.dd_desc_paddr, 283062306a36Sopenharmony_ci ATH_TXSTATUS_RING_SIZE); 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci return err; 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ciint ath_tx_init(struct ath_softc *sc, int nbufs) 283662306a36Sopenharmony_ci{ 283762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 283862306a36Sopenharmony_ci int error = 0; 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci spin_lock_init(&sc->tx.txbuflock); 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, 284362306a36Sopenharmony_ci "tx", nbufs, 1, 1); 284462306a36Sopenharmony_ci if (error != 0) { 284562306a36Sopenharmony_ci ath_err(common, 284662306a36Sopenharmony_ci "Failed to allocate tx descriptors: %d\n", error); 284762306a36Sopenharmony_ci return error; 284862306a36Sopenharmony_ci } 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, 285162306a36Sopenharmony_ci "beacon", ATH_BCBUF, 1, 1); 285262306a36Sopenharmony_ci if (error != 0) { 285362306a36Sopenharmony_ci ath_err(common, 285462306a36Sopenharmony_ci "Failed to allocate beacon descriptors: %d\n", error); 285562306a36Sopenharmony_ci return error; 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) 285962306a36Sopenharmony_ci error = ath_tx_edma_init(sc); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci return error; 286262306a36Sopenharmony_ci} 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_civoid ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) 286562306a36Sopenharmony_ci{ 286662306a36Sopenharmony_ci struct ath_atx_tid *tid; 286762306a36Sopenharmony_ci int tidno, acno; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 287062306a36Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 287162306a36Sopenharmony_ci tid->an = an; 287262306a36Sopenharmony_ci tid->tidno = tidno; 287362306a36Sopenharmony_ci tid->seq_start = tid->seq_next = 0; 287462306a36Sopenharmony_ci tid->baw_size = WME_MAX_BA; 287562306a36Sopenharmony_ci tid->baw_head = tid->baw_tail = 0; 287662306a36Sopenharmony_ci tid->active = false; 287762306a36Sopenharmony_ci tid->clear_ps_filter = true; 287862306a36Sopenharmony_ci __skb_queue_head_init(&tid->retry_q); 287962306a36Sopenharmony_ci INIT_LIST_HEAD(&tid->list); 288062306a36Sopenharmony_ci acno = TID_TO_WME_AC(tidno); 288162306a36Sopenharmony_ci tid->txq = sc->tx.txq_map[acno]; 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci if (!an->sta) 288462306a36Sopenharmony_ci break; /* just one multicast ath_atx_tid */ 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci} 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_civoid ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) 288962306a36Sopenharmony_ci{ 289062306a36Sopenharmony_ci struct ath_atx_tid *tid; 289162306a36Sopenharmony_ci struct ath_txq *txq; 289262306a36Sopenharmony_ci int tidno; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci rcu_read_lock(); 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { 289762306a36Sopenharmony_ci tid = ath_node_to_tid(an, tidno); 289862306a36Sopenharmony_ci txq = tid->txq; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci ath_txq_lock(sc, txq); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (!list_empty(&tid->list)) 290362306a36Sopenharmony_ci list_del_init(&tid->list); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci ath_tid_drain(sc, txq, tid); 290662306a36Sopenharmony_ci tid->active = false; 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci if (!an->sta) 291162306a36Sopenharmony_ci break; /* just one multicast ath_atx_tid */ 291262306a36Sopenharmony_ci } 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci rcu_read_unlock(); 291562306a36Sopenharmony_ci} 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_TX99 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ciint ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, 292062306a36Sopenharmony_ci struct ath_tx_control *txctl) 292162306a36Sopenharmony_ci{ 292262306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 292362306a36Sopenharmony_ci struct ath_frame_info *fi = get_frame_info(skb); 292462306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 292562306a36Sopenharmony_ci struct ath_buf *bf; 292662306a36Sopenharmony_ci int padpos, padsize; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci padpos = ieee80211_hdrlen(hdr->frame_control); 292962306a36Sopenharmony_ci padsize = padpos & 3; 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci if (padsize && skb->len > padpos) { 293262306a36Sopenharmony_ci if (skb_headroom(skb) < padsize) { 293362306a36Sopenharmony_ci ath_dbg(common, XMIT, 293462306a36Sopenharmony_ci "tx99 padding failed\n"); 293562306a36Sopenharmony_ci return -EINVAL; 293662306a36Sopenharmony_ci } 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci skb_push(skb, padsize); 293962306a36Sopenharmony_ci memmove(skb->data, skb->data + padsize, padpos); 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci fi->keyix = ATH9K_TXKEYIX_INVALID; 294362306a36Sopenharmony_ci fi->framelen = skb->len + FCS_LEN; 294462306a36Sopenharmony_ci fi->keytype = ATH9K_KEY_TYPE_CLEAR; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci bf = ath_tx_setup_buffer(sc, txctl->txq, NULL, skb); 294762306a36Sopenharmony_ci if (!bf) { 294862306a36Sopenharmony_ci ath_dbg(common, XMIT, "tx99 buffer setup failed\n"); 294962306a36Sopenharmony_ci return -EINVAL; 295062306a36Sopenharmony_ci } 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci ath_set_rates(sc->tx99_vif, NULL, bf); 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); 295562306a36Sopenharmony_ci ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci ath_tx_send_normal(sc, txctl->txq, NULL, skb); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci return 0; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci#endif /* CONFIG_ATH9K_TX99 */ 2963