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