+commit c0ee7fa4c0da824ccccc172bf175fb1f86540921
+Author: Felix Fietkau <nbd@openwrt.org>
+Date: Wed Jul 16 18:00:31 2014 +0200
+
+ ath9k: fix pending tx frames accounting
+
+ Packets originally buffered for the regular hardware tx queues can end
+ up being transmitted through the U-APSD queue (via PS-Poll or U-APSD).
+ When packets are dropped due to retransmit failures, the pending frames
+ counter is not always updated properly.
+ Fix this by keeping track of the queue that a frame was accounted for in
+ the ath_frame_info struct, and using that on completion to decide
+ whether the counter should be updated.
+ This fixes some spurious transmit queue hangs.
+
+ Cc: stable@vger.kernel.org
+ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
commit edcdf0989410a05a6a4b8438df4010447eaa7d9a
Author: Felix Fietkau <nbd@openwrt.org>
Date: Sun Jun 22 13:36:20 2014 +0200
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -185,7 +185,8 @@ struct ath_atx_ac {
+
+ struct ath_frame_info {
+ struct ath_buf *bf;
+- int framelen;
++ u16 framelen;
++ s8 txq;
+ enum ath9k_key_type keytype;
+ u8 keyix;
+ u8 rtscts_rate;
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -147,15 +147,13 @@ static void ath_set_rates(struct ieee802
+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+ struct sk_buff *skb)
+ {
+- int q;
+-
+- q = skb_get_queue_mapping(skb);
+- if (txq == sc->tx.uapsdq)
+- txq = sc->tx.txq_map[q];
++ struct ath_frame_info *fi = get_frame_info(skb);
++ int q = fi->txq;
+
+- if (txq != sc->tx.txq_map[q])
++ if (q < 0)
+ return;
+
++ txq = sc->tx.txq_map[q];
+ if (WARN_ON(--txq->pending_frames < 0))
+ txq->pending_frames = 0;
+
+@@ -1999,6 +1997,7 @@ static void setup_frame_info(struct ieee
+ an = (struct ath_node *) sta->drv_priv;
+
+ memset(fi, 0, sizeof(*fi));
++ fi->txq = -1;
+ if (hw_key)
+ fi->keyix = hw_key->hw_key_idx;
+ else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+@@ -2150,6 +2149,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = txctl->sta;
+ struct ieee80211_vif *vif = info->control.vif;
++ struct ath_frame_info *fi = get_frame_info(skb);
+ struct ath_softc *sc = hw->priv;
+ struct ath_txq *txq = txctl->txq;
+ struct ath_atx_tid *tid = NULL;
+@@ -2170,11 +2170,13 @@ int ath_tx_start(struct ieee80211_hw *hw
+ q = skb_get_queue_mapping(skb);
+
+ ath_txq_lock(sc, txq);
+- if (txq == sc->tx.txq_map[q] &&
+- ++txq->pending_frames > sc->tx.txq_max_pending[q] &&
+- !txq->stopped) {
+- ieee80211_stop_queue(sc->hw, q);
+- txq->stopped = true;
++ if (txq == sc->tx.txq_map[q]) {
++ fi->txq = q;
++ if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
++ !txq->stopped) {
++ ieee80211_stop_queue(sc->hw, q);
++ txq->stopped = true;
++ }
+ }
+
+ if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -564,6 +564,9 @@ static inline int ath9k_dump_btcoex(stru
+@@ -565,6 +565,9 @@ static inline int ath9k_dump_btcoex(stru
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
void ath_fill_led_pin(struct ath_softc *sc);
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
-@@ -702,6 +705,13 @@ void ath_ant_comb_scan(struct ath_softc
+@@ -703,6 +706,13 @@ void ath_ant_comb_scan(struct ath_softc
#define PS_BEACON_SYNC BIT(4)
#define PS_WAIT_FOR_ANI BIT(5)
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
-@@ -744,9 +754,8 @@ struct ath_softc {
+@@ -745,9 +755,8 @@ struct ath_softc {
struct ath_beacon beacon;
#ifdef CPTCFG_MAC80211_LEDS