linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/13] ath9k: remove bfs_seqno from struct ath_buf_state
@ 2010-11-14 14:20 Felix Fietkau
  2010-11-14 14:20 ` [PATCH 02/13] ath9k: remove bfs_tidno " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 -
 drivers/net/wireless/ath/ath9k/xmit.c  |   44 ++++++++++++++++++++-----------
 2 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5ec99eb..332c2c4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -105,7 +105,6 @@ enum buffer_type {
 #define bf_al           	bf_state.bfs_al
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
-#define bf_seqno        	bf_state.bfs_seqno
 #define bf_tidno        	bf_state.bfs_tidno
 #define bf_keyix                bf_state.bfs_keyix
 #define bf_keytype      	bf_state.bfs_keytype
@@ -221,7 +220,6 @@ struct ath_buf_state {
 	int bfs_nframes;
 	u16 bfs_al;
 	u16 bfs_frmlen;
-	int bfs_seqno;
 	int bfs_tidno;
 	int bfs_retries;
 	u8 bf_type;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index dc648a5..e84c9c2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -140,6 +140,12 @@ unlock:
 	spin_unlock_bh(&txq->axq_lock);
 }
 
+static u16 ath_frame_seqno(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
 	struct ath_txq *txq = tid->ac->txq;
@@ -157,7 +163,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 		list_move_tail(&bf->list, &bf_head);
 
 		if (bf_isretried(bf)) {
-			ath_tx_update_baw(sc, tid, bf->bf_seqno);
+			ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
 		} else {
 			ath_tx_send_normal(sc, txq, tid, &bf_head);
@@ -184,14 +190,11 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
 }
 
 static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
-			     struct ath_buf *bf)
+			     u16 seqno)
 {
 	int index, cindex;
 
-	if (bf_isretried(bf))
-		return;
-
-	index  = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
+	index  = ATH_BA_INDEX(tid->seq_start, seqno);
 	cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
 	__set_bit(cindex, tid->tx_buf);
 
@@ -215,6 +218,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 	struct ath_buf *bf;
 	struct list_head bf_head;
 	struct ath_tx_status ts;
+	u16 bf_seqno;
 
 	memset(&ts, 0, sizeof(ts));
 	INIT_LIST_HEAD(&bf_head);
@@ -226,8 +230,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
 		list_move_tail(&bf->list, &bf_head);
 
+		bf_seqno = ath_frame_seqno(bf->bf_mpdu);
 		if (bf_isretried(bf))
-			ath_tx_update_baw(sc, tid, bf->bf_seqno);
+			ath_tx_update_baw(sc, tid, bf_seqno);
 
 		spin_unlock(&txq->axq_lock);
 		ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
@@ -316,6 +321,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
 	bool rc_update = true;
 	struct ieee80211_tx_rate rates[4];
+	u16 bf_seqno;
 	int nframes;
 
 	skb = bf->bf_mpdu;
@@ -392,8 +398,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 		skb = bf->bf_mpdu;
 		tx_info = IEEE80211_SKB_CB(skb);
+		bf_seqno = ath_frame_seqno(skb);
 
-		if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
+		if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
 			/* transmit completion, subframe is
 			 * acked by block ack */
 			acked_cnt++;
@@ -442,7 +449,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			 * block-ack window
 			 */
 			spin_lock_bh(&txq->axq_lock);
-			ath_tx_update_baw(sc, tid, bf->bf_seqno);
+			ath_tx_update_baw(sc, tid, bf_seqno);
 			spin_unlock_bh(&txq->axq_lock);
 
 			if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
@@ -471,7 +478,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 					if (!tbf) {
 						spin_lock_bh(&txq->axq_lock);
 						ath_tx_update_baw(sc, tid,
-								bf->bf_seqno);
+								bf_seqno);
 						spin_unlock_bh(&txq->axq_lock);
 
 						bf->bf_state.bf_type |=
@@ -674,14 +681,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		al_delta, h_baw = tid->baw_size / 2;
 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
 	struct ieee80211_tx_info *tx_info;
+	u16 bf_seqno;
 
 	bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
 
 	do {
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
+		bf_seqno = ath_frame_seqno(bf->bf_mpdu);
 
 		/* do not step over block-ack window */
-		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
+		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
 			status = ATH_AGGR_BAW_CLOSED;
 			break;
 		}
@@ -726,7 +735,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
 
 		/* link buffers of this frame to the aggregate */
-		ath_tx_addto_baw(sc, tid, bf);
+		if (!bf_isretried(bf))
+			ath_tx_addto_baw(sc, tid, bf_seqno);
 		ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
 		list_move_tail(&bf->list, bf_q);
 		if (bf_prev) {
@@ -1288,10 +1298,12 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 			      struct ath_tx_control *txctl)
 {
 	struct ath_buf *bf;
+	u16 bf_seqno;
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
 	bf->bf_state.bf_type |= BUF_AMPDU;
 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
+	bf_seqno = ath_frame_seqno(bf->bf_mpdu);
 
 	/*
 	 * Do not queue to h/w when any of the following conditions is true:
@@ -1301,7 +1313,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 	 * - h/w queue depth exceeds low water mark
 	 */
 	if (!list_empty(&tid->buf_q) || tid->paused ||
-	    !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
+	    !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
 	    txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
 		/*
 		 * Add this frame to software queue for scheduling later
@@ -1313,7 +1325,8 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 	}
 
 	/* Add sub-frame to BAW */
-	ath_tx_addto_baw(sc, tid, bf);
+	if (!bf_isretried(bf))
+		ath_tx_addto_baw(sc, tid, bf_seqno);
 
 	/* Queue to h/w without aggregation */
 	bf->bf_nframes = 1;
@@ -1394,7 +1407,6 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
 	 */
 	tid = ATH_AN_2_TID(an, bf->bf_tidno);
 	hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
-	bf->bf_seqno = tid->seq_next;
 	INCR(tid->seq_next, IEEE80211_SEQ_MAX);
 }
 
@@ -1903,7 +1915,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
 	}
 
 	while (bf) {
-		ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
+		ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
 		if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
 			nbad++;
 
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 02/13] ath9k: remove bfs_tidno from struct ath_buf_state
  2010-11-14 14:20 [PATCH 01/13] ath9k: remove bfs_seqno from struct ath_buf_state Felix Fietkau
@ 2010-11-14 14:20 ` Felix Fietkau
  2010-11-14 14:20   ` [PATCH 03/13] ath9k: remove bfs_keytype " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 --
 drivers/net/wireless/ath/ath9k/xmit.c  |   25 +++++++++++++------------
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 332c2c4..05fe1c1 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -105,7 +105,6 @@ enum buffer_type {
 #define bf_al           	bf_state.bfs_al
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
-#define bf_tidno        	bf_state.bfs_tidno
 #define bf_keyix                bf_state.bfs_keyix
 #define bf_keytype      	bf_state.bfs_keytype
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
@@ -220,7 +219,6 @@ struct ath_buf_state {
 	int bfs_nframes;
 	u16 bfs_al;
 	u16 bfs_frmlen;
-	int bfs_tidno;
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e84c9c2..c7097a5 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -323,6 +323,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	struct ieee80211_tx_rate rates[4];
 	u16 bf_seqno;
 	int nframes;
+	u8 tidno;
 
 	skb = bf->bf_mpdu;
 	hdr = (struct ieee80211_hdr *)skb->data;
@@ -358,14 +359,15 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	}
 
 	an = (struct ath_node *)sta->drv_priv;
-	tid = ATH_AN_2_TID(an, bf->bf_tidno);
+	tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+	tid = ATH_AN_2_TID(an, tidno);
 
 	/*
 	 * The hardware occasionally sends a tx status for the wrong TID.
 	 * In this case, the BA status cannot be considered valid and all
 	 * subframes need to be retransmitted
 	 */
-	if (bf->bf_tidno != ts->tid)
+	if (tidno != ts->tid)
 		txok = false;
 
 	isaggr = bf_isaggr(bf);
@@ -1386,7 +1388,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
 	struct ath_node *an;
 	struct ath_atx_tid *tid;
 	__le16 fc;
-	u8 *qc;
+	u8 tidno;
 
 	if (!tx_info->control.sta)
 		return;
@@ -1394,18 +1396,13 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
 	an = (struct ath_node *)tx_info->control.sta->drv_priv;
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
-
-	if (ieee80211_is_data_qos(fc)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		bf->bf_tidno = qc[0] & 0xf;
-	}
+	tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 
 	/*
-	 * For HT capable stations, we save tidno for later use.
-	 * We also override seqno set by upper layer with the one
+	 * Override seqno set by upper layer with the one
 	 * in tx aggregation state.
 	 */
-	tid = ATH_AN_2_TID(an, bf->bf_tidno);
+	tid = ATH_AN_2_TID(an, tidno);
 	hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
 	INCR(tid->seq_next, IEEE80211_SEQ_MAX);
 }
@@ -1647,6 +1644,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	struct ath_hw *ah = sc->sc_ah;
 	int frm_type;
 	__le16 fc;
+	u8 tidno;
 
 	frm_type = get_hw_packet_type(skb);
 	fc = hdr->frame_control;
@@ -1673,7 +1671,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
 	    tx_info->control.sta) {
 		an = (struct ath_node *)tx_info->control.sta->drv_priv;
-		tid = ATH_AN_2_TID(an, bf->bf_tidno);
+		tidno = ieee80211_get_qos_ctl(hdr)[0] &
+			IEEE80211_QOS_CTL_TID_MASK;
+		tid = ATH_AN_2_TID(an, tidno);
+
 
 		WARN_ON(tid->ac->txq != txctl->txq);
 		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 03/13] ath9k: remove bfs_keytype from struct ath_buf_state
  2010-11-14 14:20 ` [PATCH 02/13] ath9k: remove bfs_tidno " Felix Fietkau
@ 2010-11-14 14:20   ` Felix Fietkau
  2010-11-14 14:20     ` [PATCH 04/13] ath9k: remove bfs_paprd_timestamp " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 --
 drivers/net/wireless/ath/ath9k/xmit.c  |    9 +++++----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 05fe1c1..7316459 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -106,7 +106,6 @@ enum buffer_type {
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
 #define bf_keyix                bf_state.bfs_keyix
-#define bf_keytype      	bf_state.bfs_keytype
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
 #define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
@@ -224,7 +223,6 @@ struct ath_buf_state {
 	u8 bfs_paprd;
 	unsigned long bfs_paprd_timestamp;
 	u32 bfs_keyix;
-	enum ath9k_key_type bfs_keytype;
 	enum ath9k_internal_frame_type bfs_ftype;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c7097a5..6e0467c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -630,7 +630,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	 * TODO - this could be improved to be dependent on the rate.
 	 *      The hardware can keep up at lower rates, but not higher rates
 	 */
-	if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
+	if (tx_info->control.hw_key)
 		ndelim += ATH_AGGR_ENCRYPTDELIM;
 
 	/*
@@ -1604,8 +1604,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 
 	bf->bf_flags = setup_tx_flags(skb);
 
-	bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
-	if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
+	if (tx_info->control.hw_key) {
 		bf->bf_frmlen += tx_info->control.hw_key->icv_len;
 		bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
 	} else {
@@ -1642,6 +1641,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	struct ath_desc *ds;
 	struct ath_atx_tid *tid;
 	struct ath_hw *ah = sc->sc_ah;
+	enum ath9k_key_type keytype;
 	int frm_type;
 	__le16 fc;
 	u8 tidno;
@@ -1655,8 +1655,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	ds = bf->bf_desc;
 	ath9k_hw_set_desc_link(ah, ds, 0);
 
+	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 	ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
-			       bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
+			       bf->bf_keyix, keytype, bf->bf_flags);
 
 	ath9k_hw_filltxdesc(ah, ds,
 			    skb->len,	/* segment length */
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 04/13] ath9k: remove bfs_paprd_timestamp from struct ath_buf_state
  2010-11-14 14:20   ` [PATCH 03/13] ath9k: remove bfs_keytype " Felix Fietkau
@ 2010-11-14 14:20     ` Felix Fietkau
  2010-11-14 14:20       ` [PATCH 05/13] ath9k: remove bfs_keyix " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 +-
 drivers/net/wireless/ath/ath9k/main.c  |    2 ++
 drivers/net/wireless/ath/ath9k/xmit.c  |    7 +------
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7316459..9106d41 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -221,7 +221,6 @@ struct ath_buf_state {
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
-	unsigned long bfs_paprd_timestamp;
 	u32 bfs_keyix;
 	enum ath9k_internal_frame_type bfs_ftype;
 };
@@ -598,6 +597,7 @@ struct ath_softc {
 	struct work_struct paprd_work;
 	struct work_struct hw_check_work;
 	struct completion paprd_complete;
+	bool paprd_pending;
 
 	u32 intrstatus;
 	u32 sc_flags; /* SC_OP_* */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index f8c811a..611797a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -380,6 +380,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 		}
 
 		init_completion(&sc->paprd_complete);
+		sc->paprd_pending = true;
 		ar9003_paprd_setup_gain_table(ah, chain);
 		txctl.paprd = BIT(chain);
 		if (ath_tx_start(hw, skb, &txctl) != 0)
@@ -387,6 +388,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 
 		time_left = wait_for_completion_timeout(&sc->paprd_complete,
 				msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+		sc->paprd_pending = false;
 		if (!time_left) {
 			ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
 				  "Timeout waiting for paprd training on "
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 6e0467c..9f3d23a 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1698,9 +1698,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 		if (bf->bf_state.bfs_paprd)
 			ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
 
-		if (txctl->paprd)
-			bf->bf_state.bfs_paprd_timestamp = jiffies;
-
 		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
 	}
 
@@ -1874,9 +1871,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 	bf->bf_buf_addr = 0;
 
 	if (bf->bf_state.bfs_paprd) {
-		if (time_after(jiffies,
-			       bf->bf_state.bfs_paprd_timestamp +
-			       msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
+		if (!sc->paprd_pending)
 			dev_kfree_skb_any(skb);
 		else
 			complete(&sc->paprd_complete);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 05/13] ath9k: remove bfs_keyix from struct ath_buf_state
  2010-11-14 14:20     ` [PATCH 04/13] ath9k: remove bfs_paprd_timestamp " Felix Fietkau
@ 2010-11-14 14:20       ` Felix Fietkau
  2010-11-14 14:20         ` [PATCH 06/13] ath9k: remove bfs_al " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 --
 drivers/net/wireless/ath/ath9k/xmit.c  |   14 ++++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9106d41..30c18e8 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -105,7 +105,6 @@ enum buffer_type {
 #define bf_al           	bf_state.bfs_al
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
-#define bf_keyix                bf_state.bfs_keyix
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
 #define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
@@ -221,7 +220,6 @@ struct ath_buf_state {
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
-	u32 bfs_keyix;
 	enum ath9k_internal_frame_type bfs_ftype;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 9f3d23a..176d88c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1604,12 +1604,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 
 	bf->bf_flags = setup_tx_flags(skb);
 
-	if (tx_info->control.hw_key) {
+	if (tx_info->control.hw_key)
 		bf->bf_frmlen += tx_info->control.hw_key->icv_len;
-		bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
-	} else {
-		bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
-	}
 
 	bf->bf_mpdu = skb;
 
@@ -1642,6 +1638,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	struct ath_atx_tid *tid;
 	struct ath_hw *ah = sc->sc_ah;
 	enum ath9k_key_type keytype;
+	u32 keyix;
 	int frm_type;
 	__le16 fc;
 	u8 tidno;
@@ -1656,8 +1653,13 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	ath9k_hw_set_desc_link(ah, ds, 0);
 
 	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
+	if (tx_info->control.hw_key)
+		keyix = tx_info->control.hw_key->hw_key_idx;
+	else
+		keyix = ATH9K_TXKEYIX_INVALID;
+
 	ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
-			       bf->bf_keyix, keytype, bf->bf_flags);
+			       keyix, keytype, bf->bf_flags);
 
 	ath9k_hw_filltxdesc(ah, ds,
 			    skb->len,	/* segment length */
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 06/13] ath9k: remove bfs_al from struct ath_buf_state
  2010-11-14 14:20       ` [PATCH 05/13] ath9k: remove bfs_keyix " Felix Fietkau
@ 2010-11-14 14:20         ` Felix Fietkau
  2010-11-14 14:20           ` [PATCH 07/13] ath9k: remove bfs_nframes " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    4 +--
 drivers/net/wireless/ath/ath9k/xmit.c  |   34 ++++++++++++++++----------------
 2 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 30c18e8..d1c714a 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -102,7 +102,6 @@ enum buffer_type {
 };
 
 #define bf_nframes      	bf_state.bfs_nframes
-#define bf_al           	bf_state.bfs_al
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
@@ -215,11 +214,10 @@ struct ath_atx_ac {
 
 struct ath_buf_state {
 	int bfs_nframes;
-	u16 bfs_al;
-	u16 bfs_frmlen;
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
+	u16 bfs_frmlen;
 	enum ath9k_internal_frame_type bfs_ftype;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 176d88c..88efcc1 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -56,7 +56,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 				struct ath_tx_status *ts, int txok, int sendbar);
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 			     struct list_head *head);
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
 static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
 			      struct ath_tx_status *ts, int txok);
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
@@ -674,7 +674,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 					     struct ath_txq *txq,
 					     struct ath_atx_tid *tid,
-					     struct list_head *bf_q)
+					     struct list_head *bf_q,
+					     int *aggr_len)
 {
 #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
 	struct ath_buf *bf, *bf_first, *bf_prev = NULL;
@@ -750,7 +751,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 
 	} while (!list_empty(&tid->buf_q));
 
-	bf_first->bf_al = al;
+	*aggr_len = al;
 	bf_first->bf_nframes = nframes;
 
 	return status;
@@ -763,6 +764,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	struct ath_buf *bf;
 	enum ATH_AGGR_STATUS status;
 	struct list_head bf_q;
+	int aggr_len;
 
 	do {
 		if (list_empty(&tid->buf_q))
@@ -770,7 +772,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 		INIT_LIST_HEAD(&bf_q);
 
-		status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
+		status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
 
 		/*
 		 * no frames picked up to be aggregated;
@@ -786,15 +788,15 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		if (bf->bf_nframes == 1) {
 			bf->bf_state.bf_type &= ~BUF_AGGR;
 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
-			ath_buf_set_rate(sc, bf);
+			ath_buf_set_rate(sc, bf, bf->bf_frmlen);
 			ath_tx_txqaddbuf(sc, txq, &bf_q);
 			continue;
 		}
 
 		/* setup first desc of aggregate */
 		bf->bf_state.bf_type |= BUF_AGGR;
-		ath_buf_set_rate(sc, bf);
-		ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
+		ath_buf_set_rate(sc, bf, aggr_len);
+		ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
 
 		/* anchor last desc of aggregate */
 		ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
@@ -1333,7 +1335,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 	/* Queue to h/w without aggregation */
 	bf->bf_nframes = 1;
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf);
+	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
 	ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
 }
 
@@ -1352,7 +1354,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 
 	bf->bf_nframes = 1;
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf);
+	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
 	ath_tx_txqaddbuf(sc, txq, bf_head);
 	TX_STAT_INC(txq->axq_qnum, queued);
 }
@@ -1430,13 +1432,11 @@ static int setup_tx_flags(struct sk_buff *skb)
  * width  - 0 for 20 MHz, 1 for 40 MHz
  * half_gi - to use 4us v/s 3.6 us for symbol time
  */
-static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
 			    int width, int half_gi, bool shortPreamble)
 {
 	u32 nbits, nsymbits, duration, nsymbols;
-	int streams, pktlen;
-
-	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
+	int streams;
 
 	/* find number of symbols: PLCP + data */
 	streams = HT_RC_2_STREAMS(rix);
@@ -1455,7 +1455,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 	return duration;
 }
 
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath9k_11n_rate_series series[4];
@@ -1518,7 +1518,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 		if (rates[i].flags & IEEE80211_TX_RC_MCS) {
 			/* MCS rates */
 			series[i].Rate = rix | 0x80;
-			series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+			series[i].PktDuration = ath_pkt_duration(sc, rix, len,
 				 is_40, is_sgi, is_sp);
 			if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
 				series[i].RateFlags |= ATH9K_RATESERIES_STBC;
@@ -1542,11 +1542,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 		}
 
 		series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
-			phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
+			phy, rate->bitrate * 100, len, rix, is_sp);
 	}
 
 	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
-	if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
+	if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
 		flags &= ~ATH9K_TXDESC_RTSENA;
 
 	/* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 07/13] ath9k: remove bfs_nframes from struct ath_buf_state
  2010-11-14 14:20         ` [PATCH 06/13] ath9k: remove bfs_al " Felix Fietkau
@ 2010-11-14 14:20           ` Felix Fietkau
  2010-11-14 14:20             ` [PATCH 08/13] ath9k: remove bfs_frmlen " Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 -
 drivers/net/wireless/ath/ath9k/xmit.c  |   97 +++++++++++++++----------------
 2 files changed, 47 insertions(+), 52 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index d1c714a..ddfddbb 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -101,7 +101,6 @@ enum buffer_type {
 	BUF_XRETRY		= BIT(5),
 };
 
-#define bf_nframes      	bf_state.bfs_nframes
 #define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
@@ -213,7 +212,6 @@ struct ath_atx_ac {
 };
 
 struct ath_buf_state {
-	int bfs_nframes;
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 88efcc1..87b79ef 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -57,10 +57,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 			     struct list_head *head);
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
-static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-			      struct ath_tx_status *ts, int txok);
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
-			     int nbad, int txok, bool update_rc);
+			     int nframes, int nbad, int txok, bool update_rc);
 static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
 			      int seqno);
 
@@ -303,6 +301,39 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
 	return tbf;
 }
 
+static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
+			        struct ath_tx_status *ts, int txok,
+			        int *nframes, int *nbad)
+{
+	u16 seq_st = 0;
+	u32 ba[WME_BA_BMP_SIZE >> 5];
+	int ba_index;
+	int isaggr = 0;
+
+	*nbad = 0;
+	*nframes = 0;
+
+	if (bf->bf_lastbf->bf_tx_aborted)
+		return;
+
+	isaggr = bf_isaggr(bf);
+	if (isaggr) {
+		seq_st = ts->ts_seqnum;
+		memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
+	}
+
+	while (bf) {
+		ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
+
+		(*nframes)++;
+		if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
+			(*nbad)++;
+
+		bf = bf->bf_next;
+	}
+}
+
+
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 				 struct ath_buf *bf, struct list_head *bf_q,
 				 struct ath_tx_status *ts, int txok)
@@ -332,7 +363,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	hw = bf->aphy->hw;
 
 	memcpy(rates, tx_info->control.rates, sizeof(rates));
-	nframes = bf->bf_nframes;
 
 	rcu_read_lock();
 
@@ -349,7 +379,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			    !bf->bf_stale || bf_next != NULL)
 				list_move_tail(&bf->list, &bf_head);
 
-			ath_tx_rc_status(bf, ts, 1, 0, false);
+			ath_tx_rc_status(bf, ts, 1, 1, 0, false);
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
 				0, 0);
 
@@ -393,7 +423,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	INIT_LIST_HEAD(&bf_pending);
 	INIT_LIST_HEAD(&bf_head);
 
-	nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
+	ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
 	while (bf) {
 		txfail = txpending = 0;
 		bf_next = bf->bf_next;
@@ -456,11 +486,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 			if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
 				memcpy(tx_info->control.rates, rates, sizeof(rates));
-				bf->bf_nframes = nframes;
-				ath_tx_rc_status(bf, ts, nbad, txok, true);
+				ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
 				rc_update = false;
 			} else {
-				ath_tx_rc_status(bf, ts, nbad, txok, false);
+				ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
 			}
 
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
@@ -485,8 +514,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 						bf->bf_state.bf_type |=
 							BUF_XRETRY;
-						ath_tx_rc_status(bf, ts, nbad,
-								0, false);
+						ath_tx_rc_status(bf, ts, nframes,
+								nbad, 0, false);
 						ath_tx_complete_buf(sc, bf, txq,
 								    &bf_head,
 								    ts, 0, 0);
@@ -752,7 +781,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 	} while (!list_empty(&tid->buf_q));
 
 	*aggr_len = al;
-	bf_first->bf_nframes = nframes;
 
 	return status;
 #undef PADBYTES
@@ -785,7 +813,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
 
 		/* if only one frame, send as non-aggregate */
-		if (bf->bf_nframes == 1) {
+		if (bf == bf->bf_lastbf) {
 			bf->bf_state.bf_type &= ~BUF_AGGR;
 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
 			ath_buf_set_rate(sc, bf, bf->bf_frmlen);
@@ -1333,7 +1361,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 		ath_tx_addto_baw(sc, tid, bf_seqno);
 
 	/* Queue to h/w without aggregation */
-	bf->bf_nframes = 1;
 	bf->bf_lastbf = bf;
 	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
 	ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
@@ -1352,7 +1379,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 	if (tid)
 		INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 
-	bf->bf_nframes = 1;
 	bf->bf_lastbf = bf;
 	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
 	ath_tx_txqaddbuf(sc, txq, bf_head);
@@ -1895,37 +1921,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 	spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
 }
 
-static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-			      struct ath_tx_status *ts, int txok)
-{
-	u16 seq_st = 0;
-	u32 ba[WME_BA_BMP_SIZE >> 5];
-	int ba_index;
-	int nbad = 0;
-	int isaggr = 0;
-
-	if (bf->bf_lastbf->bf_tx_aborted)
-		return 0;
-
-	isaggr = bf_isaggr(bf);
-	if (isaggr) {
-		seq_st = ts->ts_seqnum;
-		memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
-	}
-
-	while (bf) {
-		ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
-		if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
-			nbad++;
-
-		bf = bf->bf_next;
-	}
-
-	return nbad;
-}
-
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
-			     int nbad, int txok, bool update_rc)
+			     int nframes, int nbad, int txok, bool update_rc)
 {
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -1946,10 +1943,10 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
 	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
 		tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 
-		BUG_ON(nbad > bf->bf_nframes);
+		BUG_ON(nbad > nframes);
 
-		tx_info->status.ampdu_len = bf->bf_nframes;
-		tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
+		tx_info->status.ampdu_len = nframes;
+		tx_info->status.ampdu_ack_len = nframes - nbad;
 	}
 
 	if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
@@ -2078,7 +2075,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 			 */
 			if (ts.ts_status & ATH9K_TXERR_XRETRY)
 				bf->bf_state.bf_type |= BUF_XRETRY;
-			ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
+			ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
 		}
 
 		qnum = skb_get_queue_mapping(bf->bf_mpdu);
@@ -2200,7 +2197,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 		if (!bf_isampdu(bf)) {
 			if (txs.ts_status & ATH9K_TXERR_XRETRY)
 				bf->bf_state.bf_type |= BUF_XRETRY;
-			ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
+			ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
 		}
 
 		qnum = skb_get_queue_mapping(bf->bf_mpdu);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 08/13] ath9k: remove bfs_frmlen from struct ath_buf_state
  2010-11-14 14:20           ` [PATCH 07/13] ath9k: remove bfs_nframes " Felix Fietkau
@ 2010-11-14 14:20             ` Felix Fietkau
  2010-11-14 14:20               ` [PATCH 09/13] ath9k: remove bf_tx_aborted from struct ath_buf Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 -
 drivers/net/wireless/ath/ath9k/xmit.c  |   63 +++++++++++++++++++-------------
 2 files changed, 38 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index ddfddbb..944505c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -101,7 +101,6 @@ enum buffer_type {
 	BUF_XRETRY		= BIT(5),
 };
 
-#define bf_frmlen       	bf_state.bfs_frmlen
 #define bf_retries      	bf_state.bfs_retries
 #define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
 #define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
@@ -215,7 +214,6 @@ struct ath_buf_state {
 	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
-	u16 bfs_frmlen;
 	enum ath9k_internal_frame_type bfs_ftype;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 87b79ef..527151e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = {
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 			       struct ath_atx_tid *tid,
-			       struct list_head *bf_head);
+			       struct list_head *bf_head, int frmlen);
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 				struct ath_txq *txq, struct list_head *bf_q,
 				struct ath_tx_status *ts, int txok, int sendbar);
@@ -144,6 +144,26 @@ static u16 ath_frame_seqno(struct sk_buff *skb)
 	return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
 }
 
+static int ath_frame_len(struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	int frmlen = skb->len + FCS_LEN;
+	int padpos, padsize;
+
+	/* Remove the padding size, if any */
+	padpos = ath9k_cmn_padpos(hdr->frame_control);
+	padsize = padpos & 3;
+
+	if (padsize && skb->len > padpos + padsize)
+		frmlen -= padsize;
+
+	if (tx_info->control.hw_key)
+		frmlen += tx_info->control.hw_key->icv_len;
+
+	return frmlen;
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
 	struct ath_txq *txq = tid->ac->txq;
@@ -164,7 +184,8 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 			ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
 		} else {
-			ath_tx_send_normal(sc, txq, tid, &bf_head);
+			ath_tx_send_normal(sc, txq, tid, &bf_head,
+					   ath_frame_len(bf->bf_mpdu));
 		}
 	}
 
@@ -713,6 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		al_delta, h_baw = tid->baw_size / 2;
 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
 	struct ieee80211_tx_info *tx_info;
+	int frmlen;
 	u16 bf_seqno;
 
 	bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
@@ -733,7 +755,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		}
 
 		/* do not exceed aggregation limit */
-		al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
+		frmlen = ath_frame_len(bf->bf_mpdu);
+		al_delta = ATH_AGGR_DELIM_SZ + frmlen;
 
 		if (nframes &&
 		    (aggr_limit < (al + bpad + al_delta + prev_al))) {
@@ -760,7 +783,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		 * Get the delimiters needed to meet the MPDU
 		 * density for this node.
 		 */
-		ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
+		ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen);
 		bpad = PADBYTES(al_delta) + (ndelim << 2);
 
 		bf->bf_next = NULL;
@@ -816,7 +839,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		if (bf == bf->bf_lastbf) {
 			bf->bf_state.bf_type &= ~BUF_AGGR;
 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
-			ath_buf_set_rate(sc, bf, bf->bf_frmlen);
+			ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu));
 			ath_tx_txqaddbuf(sc, txq, &bf_q);
 			continue;
 		}
@@ -1327,7 +1350,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 			      struct list_head *bf_head,
-			      struct ath_tx_control *txctl)
+			      struct ath_tx_control *txctl, int frmlen)
 {
 	struct ath_buf *bf;
 	u16 bf_seqno;
@@ -1362,13 +1385,13 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 
 	/* Queue to h/w without aggregation */
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
+	ath_buf_set_rate(sc, bf, frmlen);
 	ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
 }
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 			       struct ath_atx_tid *tid,
-			       struct list_head *bf_head)
+			       struct list_head *bf_head, int frmlen)
 {
 	struct ath_buf *bf;
 
@@ -1380,7 +1403,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 		INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf, bf->bf_frmlen);
+	ath_buf_set_rate(sc, bf, frmlen);
 	ath_tx_txqaddbuf(sc, txq, bf_head);
 	TX_STAT_INC(txq->axq_qnum, queued);
 }
@@ -1595,12 +1618,10 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ath_buf *bf;
 	int hdrlen;
 	__le16 fc;
-	int padpos, padsize;
 
 	bf = ath_tx_get_buffer(sc);
 	if (!bf) {
@@ -1614,13 +1635,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 	ATH_TXBUF_RESET(bf);
 
 	bf->aphy = aphy;
-	bf->bf_frmlen = skb->len + FCS_LEN;
-	/* Remove the padding size from bf_frmlen, if any */
-	padpos = ath9k_cmn_padpos(hdr->frame_control);
-	padsize = padpos & 3;
-	if (padsize && skb->len>padpos+padsize) {
-		bf->bf_frmlen -= padsize;
-	}
 
 	if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
 		bf->bf_state.bf_type |= BUF_HT;
@@ -1630,9 +1644,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 
 	bf->bf_flags = setup_tx_flags(skb);
 
-	if (tx_info->control.hw_key)
-		bf->bf_frmlen += tx_info->control.hw_key->icv_len;
-
 	bf->bf_mpdu = skb;
 
 	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
@@ -1668,6 +1679,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	int frm_type;
 	__le16 fc;
 	u8 tidno;
+	int frmlen;
 
 	frm_type = get_hw_packet_type(skb);
 	fc = hdr->frame_control;
@@ -1684,7 +1696,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	else
 		keyix = ATH9K_TXKEYIX_INVALID;
 
-	ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
+	frmlen = ath_frame_len(bf->bf_mpdu);
+	ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
 			       keyix, keytype, bf->bf_flags);
 
 	ath9k_hw_filltxdesc(ah, ds,
@@ -1711,13 +1724,13 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 			 * Try aggregation if it's a unicast data frame
 			 * and the destination is HT capable.
 			 */
-			ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
+			ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen);
 		} else {
 			/*
 			 * Send this frame as regular when ADDBA
 			 * exchange is neither complete nor pending.
 			 */
-			ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
+			ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen);
 		}
 	} else {
 		bf->bf_state.bfs_ftype = txctl->frame_type;
@@ -1726,7 +1739,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 		if (bf->bf_state.bfs_paprd)
 			ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
 
-		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
+		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen);
 	}
 
 	spin_unlock_bh(&txctl->txq->axq_lock);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 09/13] ath9k: remove bf_tx_aborted from struct ath_buf
  2010-11-14 14:20             ` [PATCH 08/13] ath9k: remove bfs_frmlen " Felix Fietkau
@ 2010-11-14 14:20               ` Felix Fietkau
  2010-11-14 14:20                 ` [PATCH 10/13] ath9k: clean up code duplication around ath_tx_start Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    1 -
 drivers/net/wireless/ath/ath9k/xmit.c  |   23 +++++++++--------------
 2 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 944505c..224df29 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -227,7 +227,6 @@ struct ath_buf {
 	dma_addr_t bf_daddr;		/* physical addr of desc */
 	dma_addr_t bf_buf_addr;	/* physical addr of data buffer, for DMA */
 	bool bf_stale;
-	bool bf_tx_aborted;
 	u16 bf_flags;
 	struct ath_buf_state bf_state;
 	struct ath_wiphy *aphy;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 527151e..c35033f 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -334,9 +334,6 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 	*nbad = 0;
 	*nframes = 0;
 
-	if (bf->bf_lastbf->bf_tx_aborted)
-		return;
-
 	isaggr = bf_isaggr(bf);
 	if (isaggr) {
 		seq_st = ts->ts_seqnum;
@@ -357,7 +354,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 				 struct ath_buf *bf, struct list_head *bf_q,
-				 struct ath_tx_status *ts, int txok)
+				 struct ath_tx_status *ts, int txok, bool retry)
 {
 	struct ath_node *an = NULL;
 	struct sk_buff *skb;
@@ -461,8 +458,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			/* transmit completion */
 			acked_cnt++;
 		} else {
-			if (!(tid->state & AGGR_CLEANUP) &&
-			    !bf_last->bf_tx_aborted) {
+			if (!(tid->state & AGGR_CLEANUP) && retry) {
 				if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
 					ath_tx_set_retry(sc, txq, bf);
 					txpending = 1;
@@ -1132,8 +1128,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 		}
 
 		lastbf = bf->bf_lastbf;
-		if (!retry_tx)
-			lastbf->bf_tx_aborted = true;
 
 		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 			list_cut_position(&bf_head,
@@ -1150,7 +1144,8 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 		spin_unlock_bh(&txq->axq_lock);
 
 		if (bf_isampdu(bf))
-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
+			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
+					     retry_tx);
 		else
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
 	}
@@ -1171,7 +1166,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 
 			if (bf_isampdu(bf))
 				ath_tx_complete_aggr(sc, txq, bf, &bf_head,
-						     &ts, 0);
+						     &ts, 0, retry_tx);
 			else
 				ath_tx_complete_buf(sc, bf, txq, &bf_head,
 						    &ts, 0, 0);
@@ -1657,8 +1652,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 		return NULL;
 	}
 
-	bf->bf_tx_aborted = false;
-
 	return bf;
 }
 
@@ -2094,7 +2087,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 		qnum = skb_get_queue_mapping(bf->bf_mpdu);
 
 		if (bf_isampdu(bf))
-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
+			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
+					     true);
 		else
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
 
@@ -2216,7 +2210,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 		qnum = skb_get_queue_mapping(bf->bf_mpdu);
 
 		if (bf_isampdu(bf))
-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
+			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
+					     txok, true);
 		else
 			ath_tx_complete_buf(sc, bf, txq, &bf_head,
 					    &txs, txok, 0);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 10/13] ath9k: clean up code duplication around ath_tx_start
  2010-11-14 14:20               ` [PATCH 09/13] ath9k: remove bf_tx_aborted from struct ath_buf Felix Fietkau
@ 2010-11-14 14:20                 ` Felix Fietkau
  2010-11-14 14:20                   ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Felix Fietkau
  0 siblings, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Merge initial processing for the CAB queue and regular tx.
Also move ath_tx_cabq() to beacon.c and make it static.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h  |    1 -
 drivers/net/wireless/ath/ath9k/beacon.c |   19 +++++++++
 drivers/net/wireless/ath/ath9k/main.c   |   25 -----------
 drivers/net/wireless/ath/ath9k/xmit.c   |   67 +++++++++---------------------
 4 files changed, 39 insertions(+), 73 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 224df29..a403fca 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -323,7 +323,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		 struct ath_tx_control *txctl);
 void ath_tx_tasklet(struct ath_softc *sc);
 void ath_tx_edma_tasklet(struct ath_softc *sc);
-void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 		      u16 tid, u16 *ssn);
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 2377376..30724a4 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -109,6 +109,25 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
 				     series, 4, 0);
 }
 
+static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct ath_wiphy *aphy = hw->priv;
+	struct ath_softc *sc = aphy->sc;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_tx_control txctl;
+
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
+	txctl.txq = sc->beacon.cabq;
+
+	ath_print(common, ATH_DBG_XMIT,
+		  "transmitting CABQ packet, skb: %p\n", skb);
+
+	if (ath_tx_start(hw, skb, &txctl) != 0) {
+		ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
+		dev_kfree_skb_any(skb);
+	}
+}
+
 static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif)
 {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 611797a..8464ca3 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1195,12 +1195,10 @@ mutex_unlock:
 static int ath9k_tx(struct ieee80211_hw *hw,
 		    struct sk_buff *skb)
 {
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_tx_control txctl;
-	int padpos, padsize;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 
 	if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
@@ -1251,29 +1249,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
 	}
 
 	memset(&txctl, 0, sizeof(struct ath_tx_control));
-
-	/*
-	 * As a temporary workaround, assign seq# here; this will likely need
-	 * to be cleaned up to work better with Beacon transmission and virtual
-	 * BSSes.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			sc->tx.seq_no += 0x10;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-	}
-
-	/* Add the padding after the header if this is not already done */
-	padpos = ath9k_cmn_padpos(hdr->frame_control);
-	padsize = padpos & 3;
-	if (padsize && skb->len>padpos) {
-		if (skb_headroom(skb) < padsize)
-			return -1;
-		skb_push(skb, padsize);
-		memmove(skb->data, skb->data + padsize, padpos);
-	}
-
 	txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
 
 	ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c35033f..f3f0d1c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1742,41 +1742,14 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		 struct ath_tx_control *txctl)
 {
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_txq *txq = txctl->txq;
 	struct ath_buf *bf;
-	int q;
-
-	bf = ath_tx_setup_buffer(hw, skb);
-	if (unlikely(!bf))
-		return -ENOMEM;
-
-	q = skb_get_queue_mapping(skb);
-	spin_lock_bh(&txq->axq_lock);
-	if (txq == sc->tx.txq_map[q] &&
-	    ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
-		ath_mac80211_stop_queue(sc, q);
-		txq->stopped = 1;
-	}
-	spin_unlock_bh(&txq->axq_lock);
-
-	ath_tx_start_dma(sc, bf, txctl);
-
-	return 0;
-}
-
-void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct ath_wiphy *aphy = hw->priv;
-	struct ath_softc *sc = aphy->sc;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	int padpos, padsize;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ath_tx_control txctl;
-
-	memset(&txctl, 0, sizeof(struct ath_tx_control));
+	int q;
 
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
@@ -1793,30 +1766,30 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
 	/* Add the padding after the header if this is not already done */
 	padpos = ath9k_cmn_padpos(hdr->frame_control);
 	padsize = padpos & 3;
-	if (padsize && skb->len>padpos) {
-		if (skb_headroom(skb) < padsize) {
-			ath_print(common, ATH_DBG_XMIT,
-				  "TX CABQ padding failed\n");
-			dev_kfree_skb_any(skb);
-			return;
-		}
+	if (padsize && skb->len > padpos) {
+		if (skb_headroom(skb) < padsize)
+			return -ENOMEM;
+
 		skb_push(skb, padsize);
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	txctl.txq = sc->beacon.cabq;
-
-	ath_print(common, ATH_DBG_XMIT,
-		  "transmitting CABQ packet, skb: %p\n", skb);
+	bf = ath_tx_setup_buffer(hw, skb);
+	if (unlikely(!bf))
+		return -ENOMEM;
 
-	if (ath_tx_start(hw, skb, &txctl) != 0) {
-		ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
-		goto exit;
+	q = skb_get_queue_mapping(skb);
+	spin_lock_bh(&txq->axq_lock);
+	if (txq == sc->tx.txq_map[q] &&
+	    ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
+		ath_mac80211_stop_queue(sc, q);
+		txq->stopped = 1;
 	}
+	spin_unlock_bh(&txq->axq_lock);
 
-	return;
-exit:
-	dev_kfree_skb_any(skb);
+	ath_tx_start_dma(sc, bf, txctl);
+
+	return 0;
 }
 
 /*****************/
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set
  2010-11-14 14:20                 ` [PATCH 10/13] ath9k: clean up code duplication around ath_tx_start Felix Fietkau
@ 2010-11-14 14:20                   ` Felix Fietkau
  2010-11-14 14:20                     ` [PATCH 12/13] ath9k: more tx setup cleanups Felix Fietkau
  2010-11-15 11:27                     ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Vasanthakumar Thiagarajan
  0 siblings, 2 replies; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

This makes further tx path cleanups easier

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/main.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 8464ca3..50bdb5d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1992,6 +1992,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 	case IEEE80211_AMPDU_RX_STOP:
 		break;
 	case IEEE80211_AMPDU_TX_START:
+		if (!(sc->sc_flags & SC_OP_TXAGGR))
+			return -EOPNOTSUPP;
+
 		ath9k_ps_wakeup(sc);
 		ret = ath_tx_aggr_start(sc, sta, tid, ssn);
 		if (!ret)
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 12/13] ath9k: more tx setup cleanups
  2010-11-14 14:20                   ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Felix Fietkau
@ 2010-11-14 14:20                     ` Felix Fietkau
  2010-11-14 14:20                       ` [PATCH 13/13] ath9k: store frame information used by aggregation inside the skb tx info Felix Fietkau
  2010-11-15 11:27                     ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Vasanthakumar Thiagarajan
  1 sibling, 1 reply; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

- remove the BUF_HT flag, and instead check for IEEE80211_TX_CTL_AMPDU
  before calling ath_tx_send_ampdu.
- remove a few unused variables
- calculate frame length before adding the frame padding
- merge the misnamed ath_tx_start_dma function into ath_tx_start
- remove an unused argument for assign_aggr_tid_seqno

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    4 +-
 drivers/net/wireless/ath/ath9k/xmit.c  |  129 ++++++++++++++-----------------
 2 files changed, 59 insertions(+), 74 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a403fca..ae876f9 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -86,7 +86,6 @@ struct ath_config {
 /**
  * enum buffer_type - Buffer type flags
  *
- * @BUF_HT: Send this buffer using HT capabilities
  * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
  * @BUF_AGGR: Indicates whether the buffer can be aggregated
  *	(used in aggregation scheduling)
@@ -94,7 +93,6 @@ struct ath_config {
  * @BUF_XRETRY: To denote excessive retries of the buffer
  */
 enum buffer_type {
-	BUF_HT			= BIT(1),
 	BUF_AMPDU		= BIT(2),
 	BUF_AGGR		= BIT(3),
 	BUF_RETRY		= BIT(4),
@@ -102,7 +100,6 @@ enum buffer_type {
 };
 
 #define bf_retries      	bf_state.bfs_retries
-#define bf_isht(bf)		(bf->bf_state.bf_type & BUF_HT)
 #define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
 #define bf_isretried(bf)	(bf->bf_state.bf_type & BUF_RETRY)
@@ -265,6 +262,7 @@ struct ath_tx_control {
 	struct ath_txq *txq;
 	int if_id;
 	enum ath9k_internal_frame_type frame_type;
+	int frmlen;
 	u8 paprd;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index f3f0d1c..5eeffae 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1344,13 +1344,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 }
 
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
-			      struct list_head *bf_head,
-			      struct ath_tx_control *txctl, int frmlen)
+			      struct ath_buf *bf, struct ath_tx_control *txctl)
 {
-	struct ath_buf *bf;
+	struct list_head bf_head;
 	u16 bf_seqno;
 
-	bf = list_first_entry(bf_head, struct ath_buf, list);
 	bf->bf_state.bf_type |= BUF_AMPDU;
 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
 	bf_seqno = ath_frame_seqno(bf->bf_mpdu);
@@ -1369,19 +1367,22 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 		 * Add this frame to software queue for scheduling later
 		 * for aggregation.
 		 */
-		list_move_tail(&bf->list, &tid->buf_q);
+		list_add_tail(&bf->list, &tid->buf_q);
 		ath_tx_queue_tid(txctl->txq, tid);
 		return;
 	}
 
+	INIT_LIST_HEAD(&bf_head);
+	list_add(&bf->list, &bf_head);
+
 	/* Add sub-frame to BAW */
 	if (!bf_isretried(bf))
 		ath_tx_addto_baw(sc, tid, bf_seqno);
 
 	/* Queue to h/w without aggregation */
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf, frmlen);
-	ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
+	ath_buf_set_rate(sc, bf, txctl->frmlen);
+	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
 }
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1426,8 +1427,7 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 	return htype;
 }
 
-static void assign_aggr_tid_seqno(struct sk_buff *skb,
-				  struct ath_buf *bf)
+static void assign_aggr_tid_seqno(struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr;
@@ -1608,15 +1608,20 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
 }
 
 static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
-					   struct sk_buff *skb)
+					   struct ath_txq *txq,
+					   struct sk_buff *skb, int frmlen)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
+	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb;
 	struct ath_buf *bf;
-	int hdrlen;
-	__le16 fc;
+	struct ath_desc *ds;
+	enum ath9k_key_type keytype;
+	u32 keyix;
+	int frm_type;
 
 	bf = ath_tx_get_buffer(sc);
 	if (!bf) {
@@ -1624,21 +1629,14 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 		return NULL;
 	}
 
-	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	fc = hdr->frame_control;
-
 	ATH_TXBUF_RESET(bf);
 
-	bf->aphy = aphy;
-
-	if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
-		bf->bf_state.bf_type |= BUF_HT;
-		if (sc->sc_flags & SC_OP_TXAGGR)
-			assign_aggr_tid_seqno(skb, bf);
-	}
+	if (ieee80211_is_data_qos(hdr->frame_control) &&
+		conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR))
+			assign_aggr_tid_seqno(skb);
 
+	bf->aphy = aphy;
 	bf->bf_flags = setup_tx_flags(skb);
-
 	bf->bf_mpdu = skb;
 
 	bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
@@ -1652,33 +1650,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 		return NULL;
 	}
 
-	return bf;
-}
-
-/* FIXME: tx power */
-static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
-			     struct ath_tx_control *txctl)
-{
-	struct sk_buff *skb = bf->bf_mpdu;
-	struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ath_node *an = NULL;
-	struct list_head bf_head;
-	struct ath_desc *ds;
-	struct ath_atx_tid *tid;
-	struct ath_hw *ah = sc->sc_ah;
-	enum ath9k_key_type keytype;
-	u32 keyix;
-	int frm_type;
-	__le16 fc;
-	u8 tidno;
-	int frmlen;
-
 	frm_type = get_hw_packet_type(skb);
-	fc = hdr->frame_control;
-
-	INIT_LIST_HEAD(&bf_head);
-	list_add_tail(&bf->list, &bf_head);
 
 	ds = bf->bf_desc;
 	ath9k_hw_set_desc_link(ah, ds, 0);
@@ -1689,7 +1661,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	else
 		keyix = ATH9K_TXKEYIX_INVALID;
 
-	frmlen = ath_frame_len(bf->bf_mpdu);
 	ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
 			       keyix, keytype, bf->bf_flags);
 
@@ -1699,40 +1670,50 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 			    true,	/* last segment */
 			    ds,		/* first descriptor */
 			    bf->bf_buf_addr,
-			    txctl->txq->axq_qnum);
+			    txq->axq_qnum);
+
+
+	return bf;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+			     struct ath_tx_control *txctl)
+{
+	struct sk_buff *skb = bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ath_node *an = NULL;
+	struct list_head bf_head;
+	struct ath_atx_tid *tid;
+	u8 tidno;
 
 	spin_lock_bh(&txctl->txq->axq_lock);
 
-	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
-	    tx_info->control.sta) {
+	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) {
 		an = (struct ath_node *)tx_info->control.sta->drv_priv;
 		tidno = ieee80211_get_qos_ctl(hdr)[0] &
 			IEEE80211_QOS_CTL_TID_MASK;
 		tid = ATH_AN_2_TID(an, tidno);
 
-
 		WARN_ON(tid->ac->txq != txctl->txq);
-		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-			/*
-			 * Try aggregation if it's a unicast data frame
-			 * and the destination is HT capable.
-			 */
-			ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen);
-		} else {
-			/*
-			 * Send this frame as regular when ADDBA
-			 * exchange is neither complete nor pending.
-			 */
-			ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen);
-		}
+		/*
+		 * Try aggregation if it's a unicast data frame
+		 * and the destination is HT capable.
+		 */
+		ath_tx_send_ampdu(sc, tid, bf, txctl);
 	} else {
+		INIT_LIST_HEAD(&bf_head);
+		list_add_tail(&bf->list, &bf_head);
+
 		bf->bf_state.bfs_ftype = txctl->frame_type;
 		bf->bf_state.bfs_paprd = txctl->paprd;
 
 		if (bf->bf_state.bfs_paprd)
-			ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
+			ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
+						   bf->bf_state.bfs_paprd);
 
-		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen);
+		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen);
 	}
 
 	spin_unlock_bh(&txctl->txq->axq_lock);
@@ -1749,8 +1730,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 	struct ath_txq *txq = txctl->txq;
 	struct ath_buf *bf;
 	int padpos, padsize;
+	int frmlen = skb->len + FCS_LEN;
 	int q;
 
+	if (info->control.hw_key)
+		frmlen += info->control.hw_key->icv_len;
+
+	txctl->frmlen = frmlen;
+
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
 	 * to be cleaned up to work better with Beacon transmission and virtual
@@ -1774,7 +1761,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	bf = ath_tx_setup_buffer(hw, skb);
+	bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen);
 	if (unlikely(!bf))
 		return -ENOMEM;
 
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 13/13] ath9k: store frame information used by aggregation inside the skb tx info
  2010-11-14 14:20                     ` [PATCH 12/13] ath9k: more tx setup cleanups Felix Fietkau
@ 2010-11-14 14:20                       ` Felix Fietkau
  0 siblings, 0 replies; 15+ messages in thread
From: Felix Fietkau @ 2010-11-14 14:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Since the pointers after the rates in the tx info cannot be used anymore
after frames have been queued, this area can be used to store information
that was previously stored in the ath_buf. With these changes, we can delay
the ath_buf assignment in the aggregation code until aggregates are formed.

That will not only make it possible to simplify DMA descriptor setup to
do less rewriting of uncached memory, but will also make it easier to
move aggregation out of the core of the ath9k tx path.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |   15 ++-
 drivers/net/wireless/ath/ath9k/xmit.c  |  203 ++++++++++++++++----------------
 2 files changed, 109 insertions(+), 109 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index ae876f9..9141ee9 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -89,20 +89,16 @@ struct ath_config {
  * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
  * @BUF_AGGR: Indicates whether the buffer can be aggregated
  *	(used in aggregation scheduling)
- * @BUF_RETRY: Indicates whether the buffer is retried
  * @BUF_XRETRY: To denote excessive retries of the buffer
  */
 enum buffer_type {
 	BUF_AMPDU		= BIT(2),
 	BUF_AGGR		= BIT(3),
-	BUF_RETRY		= BIT(4),
 	BUF_XRETRY		= BIT(5),
 };
 
-#define bf_retries      	bf_state.bfs_retries
 #define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
-#define bf_isretried(bf)	(bf->bf_state.bf_type & BUF_RETRY)
 #define bf_isxretried(bf)	(bf->bf_state.bf_type & BUF_XRETRY)
 
 #define ATH_TXSTATUS_RING_SIZE 64
@@ -207,8 +203,15 @@ struct ath_atx_ac {
 	struct list_head tid_q;
 };
 
+struct ath_frame_info {
+	int framelen;
+	u32 keyix;
+	enum ath9k_key_type keytype;
+	u8 retries;
+	u16 seqno;
+};
+
 struct ath_buf_state {
-	int bfs_retries;
 	u8 bf_type;
 	u8 bfs_paprd;
 	enum ath9k_internal_frame_type bfs_ftype;
@@ -260,9 +263,9 @@ struct ath_node {
 
 struct ath_tx_control {
 	struct ath_txq *txq;
+	struct ath_node *an;
 	int if_id;
 	enum ath9k_internal_frame_type frame_type;
-	int frmlen;
 	u8 paprd;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 5eeffae..c63e283 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = {
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 			       struct ath_atx_tid *tid,
-			       struct list_head *bf_head, int frmlen);
+			       struct list_head *bf_head);
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 				struct ath_txq *txq, struct list_head *bf_q,
 				struct ath_tx_status *ts, int txok, int sendbar);
@@ -138,30 +138,12 @@ unlock:
 	spin_unlock_bh(&txq->axq_lock);
 }
 
-static u16 ath_frame_seqno(struct sk_buff *skb)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
-}
-
-static int ath_frame_len(struct sk_buff *skb)
+static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	int frmlen = skb->len + FCS_LEN;
-	int padpos, padsize;
-
-	/* Remove the padding size, if any */
-	padpos = ath9k_cmn_padpos(hdr->frame_control);
-	padsize = padpos & 3;
-
-	if (padsize && skb->len > padpos + padsize)
-		frmlen -= padsize;
-
-	if (tx_info->control.hw_key)
-		frmlen += tx_info->control.hw_key->icv_len;
-
-	return frmlen;
+	BUILD_BUG_ON(sizeof(struct ath_frame_info) >
+		     sizeof(tx_info->rate_driver_data));
+	return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
 }
 
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
@@ -170,6 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 	struct ath_buf *bf;
 	struct list_head bf_head;
 	struct ath_tx_status ts;
+	struct ath_frame_info *fi;
 
 	INIT_LIST_HEAD(&bf_head);
 
@@ -180,12 +163,12 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
 		list_move_tail(&bf->list, &bf_head);
 
-		if (bf_isretried(bf)) {
-			ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
+		fi = get_frame_info(bf->bf_mpdu);
+		if (fi->retries) {
+			ath_tx_update_baw(sc, tid, fi->seqno);
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
 		} else {
-			ath_tx_send_normal(sc, txq, tid, &bf_head,
-					   ath_frame_len(bf->bf_mpdu));
+			ath_tx_send_normal(sc, txq, tid, &bf_head);
 		}
 	}
 
@@ -237,7 +220,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 	struct ath_buf *bf;
 	struct list_head bf_head;
 	struct ath_tx_status ts;
-	u16 bf_seqno;
+	struct ath_frame_info *fi;
 
 	memset(&ts, 0, sizeof(ts));
 	INIT_LIST_HEAD(&bf_head);
@@ -249,9 +232,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
 		list_move_tail(&bf->list, &bf_head);
 
-		bf_seqno = ath_frame_seqno(bf->bf_mpdu);
-		if (bf_isretried(bf))
-			ath_tx_update_baw(sc, tid, bf_seqno);
+		fi = get_frame_info(bf->bf_mpdu);
+		if (fi->retries)
+			ath_tx_update_baw(sc, tid, fi->seqno);
 
 		spin_unlock(&txq->axq_lock);
 		ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
@@ -263,16 +246,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 }
 
 static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
-			     struct ath_buf *bf)
+			     struct sk_buff *skb)
 {
-	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr;
 
-	bf->bf_state.bf_type |= BUF_RETRY;
-	bf->bf_retries++;
 	TX_STAT_INC(txq->axq_qnum, a_retries);
+	if (tx_info->control.rates[4].count++ > 0)
+		return;
 
-	skb = bf->bf_mpdu;
 	hdr = (struct ieee80211_hdr *)skb->data;
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
 }
@@ -326,6 +308,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 			        struct ath_tx_status *ts, int txok,
 			        int *nframes, int *nbad)
 {
+	struct ath_frame_info *fi;
 	u16 seq_st = 0;
 	u32 ba[WME_BA_BMP_SIZE >> 5];
 	int ba_index;
@@ -341,7 +324,8 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 	}
 
 	while (bf) {
-		ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
+		fi = get_frame_info(bf->bf_mpdu);
+		ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
 
 		(*nframes)++;
 		if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
@@ -370,7 +354,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
 	bool rc_update = true;
 	struct ieee80211_tx_rate rates[4];
-	u16 bf_seqno;
+	struct ath_frame_info *fi;
 	int nframes;
 	u8 tidno;
 
@@ -448,9 +432,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 		skb = bf->bf_mpdu;
 		tx_info = IEEE80211_SKB_CB(skb);
-		bf_seqno = ath_frame_seqno(skb);
+		fi = get_frame_info(skb);
 
-		if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
+		if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
 			/* transmit completion, subframe is
 			 * acked by block ack */
 			acked_cnt++;
@@ -459,8 +443,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			acked_cnt++;
 		} else {
 			if (!(tid->state & AGGR_CLEANUP) && retry) {
-				if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
-					ath_tx_set_retry(sc, txq, bf);
+				if (fi->retries < ATH_MAX_SW_RETRIES) {
+					ath_tx_set_retry(sc, txq, bf->bf_mpdu);
 					txpending = 1;
 				} else {
 					bf->bf_state.bf_type |= BUF_XRETRY;
@@ -498,7 +482,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 			 * block-ack window
 			 */
 			spin_lock_bh(&txq->axq_lock);
-			ath_tx_update_baw(sc, tid, bf_seqno);
+			ath_tx_update_baw(sc, tid, fi->seqno);
 			spin_unlock_bh(&txq->axq_lock);
 
 			if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
@@ -525,8 +509,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 					 */
 					if (!tbf) {
 						spin_lock_bh(&txq->axq_lock);
-						ath_tx_update_baw(sc, tid,
-								bf_seqno);
+						ath_tx_update_baw(sc, tid, fi->seqno);
 						spin_unlock_bh(&txq->axq_lock);
 
 						bf->bf_state.bf_type |=
@@ -666,6 +649,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	u16 minlen;
 	u8 flags, rix;
 	int width, streams, half_gi, ndelim, mindelim;
+	struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
 
 	/* Select standard number of delimiters based on frame length alone */
 	ndelim = ATH_AGGR_GET_NDELIM(frmlen);
@@ -676,7 +660,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 	 * TODO - this could be improved to be dependent on the rate.
 	 *      The hardware can keep up at lower rates, but not higher rates
 	 */
-	if (tx_info->control.hw_key)
+	if (fi->keyix != ATH9K_TXKEYIX_INVALID)
 		ndelim += ATH_AGGR_ENCRYPTDELIM;
 
 	/*
@@ -730,17 +714,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		al_delta, h_baw = tid->baw_size / 2;
 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
 	struct ieee80211_tx_info *tx_info;
-	int frmlen;
-	u16 bf_seqno;
+	struct ath_frame_info *fi;
 
 	bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
 
 	do {
 		bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
-		bf_seqno = ath_frame_seqno(bf->bf_mpdu);
+		fi = get_frame_info(bf->bf_mpdu);
 
 		/* do not step over block-ack window */
-		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
+		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
 			status = ATH_AGGR_BAW_CLOSED;
 			break;
 		}
@@ -751,8 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		}
 
 		/* do not exceed aggregation limit */
-		frmlen = ath_frame_len(bf->bf_mpdu);
-		al_delta = ATH_AGGR_DELIM_SZ + frmlen;
+		al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
 
 		if (nframes &&
 		    (aggr_limit < (al + bpad + al_delta + prev_al))) {
@@ -779,15 +761,15 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 		 * Get the delimiters needed to meet the MPDU
 		 * density for this node.
 		 */
-		ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen);
+		ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
 		bpad = PADBYTES(al_delta) + (ndelim << 2);
 
 		bf->bf_next = NULL;
 		ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
 
 		/* link buffers of this frame to the aggregate */
-		if (!bf_isretried(bf))
-			ath_tx_addto_baw(sc, tid, bf_seqno);
+		if (!fi->retries)
+			ath_tx_addto_baw(sc, tid, fi->seqno);
 		ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
 		list_move_tail(&bf->list, bf_q);
 		if (bf_prev) {
@@ -810,6 +792,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 {
 	struct ath_buf *bf;
 	enum ATH_AGGR_STATUS status;
+	struct ath_frame_info *fi;
 	struct list_head bf_q;
 	int aggr_len;
 
@@ -833,9 +816,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 
 		/* if only one frame, send as non-aggregate */
 		if (bf == bf->bf_lastbf) {
+			fi = get_frame_info(bf->bf_mpdu);
+
 			bf->bf_state.bf_type &= ~BUF_AGGR;
 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
-			ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu));
+			ath_buf_set_rate(sc, bf, fi->framelen);
 			ath_tx_txqaddbuf(sc, txq, &bf_q);
 			continue;
 		}
@@ -1346,12 +1331,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 			      struct ath_buf *bf, struct ath_tx_control *txctl)
 {
+	struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
 	struct list_head bf_head;
-	u16 bf_seqno;
 
 	bf->bf_state.bf_type |= BUF_AMPDU;
 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
-	bf_seqno = ath_frame_seqno(bf->bf_mpdu);
 
 	/*
 	 * Do not queue to h/w when any of the following conditions is true:
@@ -1361,7 +1345,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 	 * - h/w queue depth exceeds low water mark
 	 */
 	if (!list_empty(&tid->buf_q) || tid->paused ||
-	    !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
+	    !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
 	    txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
 		/*
 		 * Add this frame to software queue for scheduling later
@@ -1376,19 +1360,20 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 	list_add(&bf->list, &bf_head);
 
 	/* Add sub-frame to BAW */
-	if (!bf_isretried(bf))
-		ath_tx_addto_baw(sc, tid, bf_seqno);
+	if (!fi->retries)
+		ath_tx_addto_baw(sc, tid, fi->seqno);
 
 	/* Queue to h/w without aggregation */
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf, txctl->frmlen);
+	ath_buf_set_rate(sc, bf, fi->framelen);
 	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
 }
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 			       struct ath_atx_tid *tid,
-			       struct list_head *bf_head, int frmlen)
+			       struct list_head *bf_head)
 {
+	struct ath_frame_info *fi;
 	struct ath_buf *bf;
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
@@ -1399,7 +1384,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 		INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 
 	bf->bf_lastbf = bf;
-	ath_buf_set_rate(sc, bf, frmlen);
+	fi = get_frame_info(bf->bf_mpdu);
+	ath_buf_set_rate(sc, bf, fi->framelen);
 	ath_tx_txqaddbuf(sc, txq, bf_head);
 	TX_STAT_INC(txq->axq_qnum, queued);
 }
@@ -1427,30 +1413,49 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 	return htype;
 }
 
-static void assign_aggr_tid_seqno(struct sk_buff *skb)
+static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
+			     int framelen)
 {
+	struct ath_wiphy *aphy = hw->priv;
+	struct ath_softc *sc = aphy->sc;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = tx_info->control.sta;
+	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 	struct ieee80211_hdr *hdr;
+	struct ath_frame_info *fi = get_frame_info(skb);
 	struct ath_node *an;
 	struct ath_atx_tid *tid;
-	__le16 fc;
+	enum ath9k_key_type keytype;
+	u16 seqno = 0;
 	u8 tidno;
 
-	if (!tx_info->control.sta)
-		return;
+	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 
-	an = (struct ath_node *)tx_info->control.sta->drv_priv;
 	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
-	tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+	if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+		conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
 
-	/*
-	 * Override seqno set by upper layer with the one
-	 * in tx aggregation state.
-	 */
-	tid = ATH_AN_2_TID(an, tidno);
-	hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
-	INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+		an = (struct ath_node *) sta->drv_priv;
+		tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+
+		/*
+		 * Override seqno set by upper layer with the one
+		 * in tx aggregation state.
+		 */
+		tid = ATH_AN_2_TID(an, tidno);
+		seqno = tid->seq_next;
+		hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+		INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+	}
+
+	memset(fi, 0, sizeof(*fi));
+	if (hw_key)
+		fi->keyix = hw_key->hw_key_idx;
+	else
+		fi->keyix = ATH9K_TXKEYIX_INVALID;
+	fi->keytype = keytype;
+	fi->framelen = framelen;
+	fi->seqno = seqno;
 }
 
 static int setup_tx_flags(struct sk_buff *skb)
@@ -1609,18 +1614,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
 
 static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 					   struct ath_txq *txq,
-					   struct sk_buff *skb, int frmlen)
+					   struct sk_buff *skb)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb;
+	struct ath_frame_info *fi = get_frame_info(skb);
 	struct ath_buf *bf;
 	struct ath_desc *ds;
-	enum ath9k_key_type keytype;
-	u32 keyix;
 	int frm_type;
 
 	bf = ath_tx_get_buffer(sc);
@@ -1631,10 +1633,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 
 	ATH_TXBUF_RESET(bf);
 
-	if (ieee80211_is_data_qos(hdr->frame_control) &&
-		conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR))
-			assign_aggr_tid_seqno(skb);
-
 	bf->aphy = aphy;
 	bf->bf_flags = setup_tx_flags(skb);
 	bf->bf_mpdu = skb;
@@ -1655,14 +1653,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 	ds = bf->bf_desc;
 	ath9k_hw_set_desc_link(ah, ds, 0);
 
-	keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
-	if (tx_info->control.hw_key)
-		keyix = tx_info->control.hw_key->hw_key_idx;
-	else
-		keyix = ATH9K_TXKEYIX_INVALID;
-
-	ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
-			       keyix, keytype, bf->bf_flags);
+	ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
+			       fi->keyix, fi->keytype, bf->bf_flags);
 
 	ath9k_hw_filltxdesc(ah, ds,
 			    skb->len,	/* segment length */
@@ -1683,18 +1675,16 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ath_node *an = NULL;
 	struct list_head bf_head;
 	struct ath_atx_tid *tid;
 	u8 tidno;
 
 	spin_lock_bh(&txctl->txq->axq_lock);
 
-	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) {
-		an = (struct ath_node *)tx_info->control.sta->drv_priv;
+	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && txctl->an) {
 		tidno = ieee80211_get_qos_ctl(hdr)[0] &
 			IEEE80211_QOS_CTL_TID_MASK;
-		tid = ATH_AN_2_TID(an, tidno);
+		tid = ATH_AN_2_TID(txctl->an, tidno);
 
 		WARN_ON(tid->ac->txq != txctl->txq);
 		/*
@@ -1713,7 +1703,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 			ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
 						   bf->bf_state.bfs_paprd);
 
-		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen);
+		ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
 	}
 
 	spin_unlock_bh(&txctl->txq->axq_lock);
@@ -1725,6 +1715,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = info->control.sta;
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 	struct ath_txq *txq = txctl->txq;
@@ -1733,11 +1724,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 	int frmlen = skb->len + FCS_LEN;
 	int q;
 
+	txctl->an = (struct ath_node *)sta->drv_priv;
 	if (info->control.hw_key)
 		frmlen += info->control.hw_key->icv_len;
 
-	txctl->frmlen = frmlen;
-
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
 	 * to be cleaned up to work better with Beacon transmission and virtual
@@ -1761,7 +1751,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen);
+	setup_frame_info(hw, skb, frmlen);
+
+	/*
+	 * At this point, the vif, hw_key and sta pointers in the tx control
+	 * info are no longer valid (overwritten by the ath_frame_info data.
+	 */
+
+	bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
 	if (unlikely(!bf))
 		return -ENOMEM;
 
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set
  2010-11-14 14:20                   ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Felix Fietkau
  2010-11-14 14:20                     ` [PATCH 12/13] ath9k: more tx setup cleanups Felix Fietkau
@ 2010-11-15 11:27                     ` Vasanthakumar Thiagarajan
  2010-11-15 11:32                       ` Felix Fietkau
  1 sibling, 1 reply; 15+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-11-15 11:27 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville, Luis Rodriguez

On Sun, Nov 14, 2010 at 07:50:11PM +0530, Felix Fietkau wrote:
> This makes further tx path cleanups easier
> 
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> ---
>  drivers/net/wireless/ath/ath9k/main.c |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index 8464ca3..50bdb5d 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -1992,6 +1992,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
>  	case IEEE80211_AMPDU_RX_STOP:
>  		break;
>  	case IEEE80211_AMPDU_TX_START:
> +		if (!(sc->sc_flags & SC_OP_TXAGGR))
> +			return -EOPNOTSUPP;

SC_OP_TXAGGR is set when the hw supports tx AMPDU, I think
mac80211 does not call drv_ampdu_action() if hw does not
support AMPDU.

Vasanth

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set
  2010-11-15 11:27                     ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Vasanthakumar Thiagarajan
@ 2010-11-15 11:32                       ` Felix Fietkau
  0 siblings, 0 replies; 15+ messages in thread
From: Felix Fietkau @ 2010-11-15 11:32 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan; +Cc: linux-wireless, linville, Luis Rodriguez

On 2010-11-15 12:27 PM, Vasanthakumar Thiagarajan wrote:
> On Sun, Nov 14, 2010 at 07:50:11PM +0530, Felix Fietkau wrote:
>> This makes further tx path cleanups easier
>> 
>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>> ---
>>  drivers/net/wireless/ath/ath9k/main.c |    3 +++
>>  1 files changed, 3 insertions(+), 0 deletions(-)
>> 
>> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
>> index 8464ca3..50bdb5d 100644
>> --- a/drivers/net/wireless/ath/ath9k/main.c
>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>> @@ -1992,6 +1992,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
>>  	case IEEE80211_AMPDU_RX_STOP:
>>  		break;
>>  	case IEEE80211_AMPDU_TX_START:
>> +		if (!(sc->sc_flags & SC_OP_TXAGGR))
>> +			return -EOPNOTSUPP;
> 
> SC_OP_TXAGGR is set when the hw supports tx AMPDU, I think
> mac80211 does not call drv_ampdu_action() if hw does not
> support AMPDU.
You're right, I took another look at the code and while AMPDU is not
disabled based on SC_OP_TXAGGR, it is disabled based on the same
condition that gets checked before SC_OP_TXAGGR is even set.
Maybe I'll clean that up later...

- Felix

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2010-11-15 11:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-14 14:20 [PATCH 01/13] ath9k: remove bfs_seqno from struct ath_buf_state Felix Fietkau
2010-11-14 14:20 ` [PATCH 02/13] ath9k: remove bfs_tidno " Felix Fietkau
2010-11-14 14:20   ` [PATCH 03/13] ath9k: remove bfs_keytype " Felix Fietkau
2010-11-14 14:20     ` [PATCH 04/13] ath9k: remove bfs_paprd_timestamp " Felix Fietkau
2010-11-14 14:20       ` [PATCH 05/13] ath9k: remove bfs_keyix " Felix Fietkau
2010-11-14 14:20         ` [PATCH 06/13] ath9k: remove bfs_al " Felix Fietkau
2010-11-14 14:20           ` [PATCH 07/13] ath9k: remove bfs_nframes " Felix Fietkau
2010-11-14 14:20             ` [PATCH 08/13] ath9k: remove bfs_frmlen " Felix Fietkau
2010-11-14 14:20               ` [PATCH 09/13] ath9k: remove bf_tx_aborted from struct ath_buf Felix Fietkau
2010-11-14 14:20                 ` [PATCH 10/13] ath9k: clean up code duplication around ath_tx_start Felix Fietkau
2010-11-14 14:20                   ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Felix Fietkau
2010-11-14 14:20                     ` [PATCH 12/13] ath9k: more tx setup cleanups Felix Fietkau
2010-11-14 14:20                       ` [PATCH 13/13] ath9k: store frame information used by aggregation inside the skb tx info Felix Fietkau
2010-11-15 11:27                     ` [PATCH 11/13] ath9k: block new AMPDU sessions if SC_OP_TXAGGR is not set Vasanthakumar Thiagarajan
2010-11-15 11:32                       ` Felix Fietkau

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).