From: Felix Fietkau <nbd@openwrt.org>
Date: Wed, 3 Oct 2012 18:57:31 +0000 (+0000)
Subject: ath9k: use ieee80211_free_txskb, might fix hostapd stability issues
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=15c884fdb2b8c604d816e22a4f983653aee7c6df;p=lede.git

ath9k: use ieee80211_free_txskb, might fix hostapd stability issues

SVN-Revision: 33611
---

diff --git a/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch b/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch
new file mode 100644
index 0000000000..dd484662b4
--- /dev/null
+++ b/package/mac80211/patches/566-ath9k_use_ieee80211_free_txskb.patch
@@ -0,0 +1,149 @@
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -66,8 +66,7 @@ static void ath_tx_update_baw(struct ath
+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ 					   struct ath_txq *txq,
+ 					   struct ath_atx_tid *tid,
+-					   struct sk_buff *skb,
+-					   bool dequeue);
++					   struct sk_buff *skb);
+ 
+ enum {
+ 	MCS_HT20,
+@@ -176,7 +175,15 @@ static void ath_tx_flush_tid(struct ath_
+ 		fi = get_frame_info(skb);
+ 		bf = fi->bf;
+ 
+-		if (bf && fi->retries) {
++		if (!bf) {
++			bf = ath_tx_setup_buffer(sc, txq, tid, skb);
++			if (!bf) {
++				ieee80211_free_txskb(sc->hw, skb);
++				continue;
++			}
++		}
++
++		if (fi->retries) {
+ 			list_add_tail(&bf->list, &bf_head);
+ 			ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
+ 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
+@@ -785,10 +792,13 @@ static enum ATH_AGGR_STATUS ath_tx_form_
+ 		fi = get_frame_info(skb);
+ 		bf = fi->bf;
+ 		if (!fi->bf)
+-			bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
++			bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+ 
+-		if (!bf)
++		if (!bf) {
++			__skb_unlink(skb, &tid->buf_q);
++			ieee80211_free_txskb(sc->hw, skb);
+ 			continue;
++		}
+ 
+ 		bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
+ 		seqno = bf->bf_state.seqno;
+@@ -1731,9 +1741,11 @@ static void ath_tx_send_ampdu(struct ath
+ 		return;
+ 	}
+ 
+-	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
+-	if (!bf)
++	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
++	if (!bf) {
++		ieee80211_free_txskb(sc->hw, skb);
+ 		return;
++	}
+ 
+ 	bf->bf_state.bf_type = BUF_AMPDU;
+ 	INIT_LIST_HEAD(&bf_head);
+@@ -1757,11 +1769,6 @@ static void ath_tx_send_normal(struct at
+ 	struct ath_buf *bf;
+ 
+ 	bf = fi->bf;
+-	if (!bf)
+-		bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
+-
+-	if (!bf)
+-		return;
+ 
+ 	INIT_LIST_HEAD(&bf_head);
+ 	list_add_tail(&bf->list, &bf_head);
+@@ -1835,8 +1842,7 @@ u8 ath_txchainmask_reduction(struct ath_
+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ 					   struct ath_txq *txq,
+ 					   struct ath_atx_tid *tid,
+-					   struct sk_buff *skb,
+-					   bool dequeue)
++					   struct sk_buff *skb)
+ {
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 	struct ath_frame_info *fi = get_frame_info(skb);
+@@ -1848,7 +1854,7 @@ static struct ath_buf *ath_tx_setup_buff
+ 	bf = ath_tx_get_buffer(sc);
+ 	if (!bf) {
+ 		ath_dbg(common, XMIT, "TX buffers are full\n");
+-		goto error;
++		return NULL;
+ 	}
+ 
+ 	ATH_TXBUF_RESET(bf);
+@@ -1877,18 +1883,12 @@ static struct ath_buf *ath_tx_setup_buff
+ 		ath_err(ath9k_hw_common(sc->sc_ah),
+ 			"dma_mapping_error() on TX\n");
+ 		ath_tx_return_buffer(sc, bf);
+-		goto error;
++		return NULL;
+ 	}
+ 
+ 	fi->bf = bf;
+ 
+ 	return bf;
+-
+-error:
+-	if (dequeue)
+-		__skb_unlink(skb, &tid->buf_q);
+-	dev_kfree_skb_any(skb);
+-	return NULL;
+ }
+ 
+ /* FIXME: tx power */
+@@ -1917,9 +1917,14 @@ static void ath_tx_start_dma(struct ath_
+ 		 */
+ 		ath_tx_send_ampdu(sc, tid, skb, txctl);
+ 	} else {
+-		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
+-		if (!bf)
++		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
++		if (!bf) {
++			if (txctl->paprd)
++				dev_kfree_skb_any(skb);
++			else
++				ieee80211_free_txskb(sc->hw, skb);
+ 			return;
++		}
+ 
+ 		bf->bf_state.bfs_paprd = txctl->paprd;
+ 
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -775,7 +775,7 @@ static void ath9k_tx(struct ieee80211_hw
+ 
+ 	return;
+ exit:
+-	dev_kfree_skb_any(skb);
++	ieee80211_free_txskb(hw, skb);
+ }
+ 
+ static void ath9k_stop(struct ieee80211_hw *hw)
+--- a/drivers/net/wireless/ath/ath9k/beacon.c
++++ b/drivers/net/wireless/ath/ath9k/beacon.c
+@@ -120,7 +120,7 @@ static void ath9k_tx_cabq(struct ieee802
+ 
+ 	if (ath_tx_start(hw, skb, &txctl) != 0) {
+ 		ath_dbg(common, XMIT, "CABQ TX failed\n");
+-		dev_kfree_skb_any(skb);
++		ieee80211_free_txskb(hw, skb);
+ 	}
+ }
+