From fa8bcf84e01953ca716f1f80984292c7eb6d8981 Mon Sep 17 00:00:00 2001 From: nbd Date: Sat, 18 May 2013 19:36:22 +0000 Subject: ath9k: fix some more aggregation related issues Signed-off-by: Felix Fietkau git-svn-id: svn://svn.openwrt.org/openwrt/trunk@36656 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/mac80211/patches/300-pending_work.patch | 337 +++++++++++++-------- .../patches/512-ath9k_channelbw_debugfs.patch | 4 +- .../mac80211/patches/530-ath9k_extra_leds.patch | 6 +- 3 files changed, 217 insertions(+), 130 deletions(-) diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index e1f6af536..af9270d0f 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/package/mac80211/patches/300-pending_work.patch @@ -8,25 +8,31 @@ struct ath_buf_state bf_state; }; -@@ -253,6 +254,7 @@ struct ath_atx_tid { - int sched; - int paused; - u8 state; -+ bool stop_cb; +@@ -250,9 +251,9 @@ struct ath_atx_tid { + int tidno; + int baw_head; /* first un-acked tx buffer */ + int baw_tail; /* next unused tx buffer slot */ +- int sched; +- int paused; +- u8 state; ++ bool sched; ++ bool paused; ++ bool active; }; struct ath_node { -@@ -350,7 +352,8 @@ void ath_tx_tasklet(struct ath_softc *sc - void ath_tx_edma_tasklet(struct ath_softc *sc); - 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); -+bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, -+ bool flush); - void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); - - void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); -@@ -658,11 +661,10 @@ enum sc_op_flags { +@@ -273,10 +274,6 @@ struct ath_node { + #endif + }; + +-#define AGGR_CLEANUP BIT(1) +-#define AGGR_ADDBA_COMPLETE BIT(2) +-#define AGGR_ADDBA_PROGRESS BIT(3) +- + struct ath_tx_control { + struct ath_txq *txq; + struct ath_node *an; +@@ -658,11 +655,10 @@ enum sc_op_flags { struct ath_rate_table; struct ath9k_vif_iter_data { @@ -161,7 +167,7 @@ u16 tid, u16 *ssn, u8 buf_size) { struct ath_softc *sc = hw->priv; -+ bool flush = false, cb; ++ bool flush = false; int ret = 0; local_bh_disable(); @@ -175,10 +181,9 @@ + flush = true; + case IEEE80211_AMPDU_TX_STOP_CONT: ath9k_ps_wakeup(sc); -- ath_tx_aggr_stop(sc, sta, tid); + ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); -+ cb = ath_tx_aggr_stop(sc, sta, tid, flush); -+ if (cb) ++ if (!flush) + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ath9k_ps_restore(sc); break; @@ -3697,11 +3702,35 @@ hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -157,7 +157,27 @@ static void ath_send_bar(struct ath_atx_ +@@ -125,24 +125,6 @@ static void ath_tx_queue_tid(struct ath_ + list_add_tail(&ac->list, &txq->axq_acq); + } + +-static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +-{ +- struct ath_txq *txq = tid->ac->txq; +- +- WARN_ON(!tid->paused); +- +- ath_txq_lock(sc, txq); +- tid->paused = false; +- +- if (skb_queue_empty(&tid->buf_q)) +- goto unlock; +- +- ath_tx_queue_tid(txq, tid); +- ath_txq_schedule(sc, txq); +-unlock: +- ath_txq_unlock_complete(sc, txq); +-} +- + static struct ath_frame_info *get_frame_info(struct sk_buff *skb) + { + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); +@@ -157,6 +139,13 @@ static void ath_send_bar(struct ath_atx_ seqno << IEEE80211_SEQ_SEQ_SHIFT); } --static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ath_buf *bf) +{ @@ -3709,44 +3738,10 @@ + ARRAY_SIZE(bf->rates)); +} + -+static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -+{ -+ tid->state &= ~AGGR_ADDBA_COMPLETE; -+ tid->state &= ~AGGR_CLEANUP; -+ if (!tid->stop_cb) -+ return; -+ -+ ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr, -+ tid->tidno); -+ tid->stop_cb = false; -+} -+ -+static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid, -+ bool flush_packets) + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; - struct sk_buff *skb; -@@ -174,31 +194,29 @@ static void ath_tx_flush_tid(struct ath_ - while ((skb = __skb_dequeue(&tid->buf_q))) { - fi = get_frame_info(skb); - bf = fi->bf; -+ if (!bf && !flush_packets) -+ bf = ath_tx_setup_buffer(sc, txq, tid, skb); - - if (!bf) { -- bf = ath_tx_setup_buffer(sc, txq, tid, skb); -- if (!bf) { -- ieee80211_free_txskb(sc->hw, skb); -- continue; -- } -+ ieee80211_free_txskb(sc->hw, skb); -+ continue; - } - -- if (fi->retries) { -+ if (fi->retries || flush_packets) { - list_add_tail(&bf->list, &bf_head); - ath_tx_update_baw(sc, tid, bf->bf_state.seqno); +@@ -189,15 +178,11 @@ static void ath_tx_flush_tid(struct ath_ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); sendbar = true; } else { @@ -3759,15 +3754,11 @@ - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; - } -+ if (tid->baw_head == tid->baw_tail) -+ ath_tx_clear_tid(sc, tid); - -- if (sendbar) { -+ if (sendbar && !flush_packets) { +- + if (sendbar) { ath_txq_unlock(sc, txq); ath_send_bar(tid, tid->seq_start); - ath_txq_lock(sc, txq); -@@ -269,9 +287,7 @@ static void ath_tid_drain(struct ath_sof +@@ -269,9 +254,7 @@ static void ath_tid_drain(struct ath_sof list_add_tail(&bf->list, &bf_head); @@ -3778,7 +3769,7 @@ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); } -@@ -407,7 +423,7 @@ static void ath_tx_complete_aggr(struct +@@ -407,7 +390,7 @@ static void ath_tx_complete_aggr(struct tx_info = IEEE80211_SKB_CB(skb); @@ -3787,16 +3778,53 @@ retries = ts->ts_longretry + 1; for (i = 0; i < ts->ts_rateindex; i++) -@@ -594,7 +610,7 @@ static void ath_tx_complete_aggr(struct +@@ -483,19 +466,19 @@ static void ath_tx_complete_aggr(struct + tx_info = IEEE80211_SKB_CB(skb); + fi = get_frame_info(skb); + +- if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { ++ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { ++ /* ++ * Outside of the current BlockAck window, ++ * maybe part of a previous session ++ */ ++ txfail = 1; ++ } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { + /* transmit completion, subframe is + * acked by block ack */ + acked_cnt++; + } else if (!isaggr && txok) { + /* transmit completion */ + acked_cnt++; +- } else if (tid->state & AGGR_CLEANUP) { +- /* +- * cleanup in progress, just fail +- * the un-acked sub-frames +- */ +- txfail = 1; + } else if (flush) { + txpending = 1; + } else if (fi->retries < ATH_MAX_SW_RETRIES) { +@@ -519,7 +502,7 @@ static void ath_tx_complete_aggr(struct + if (bf_next != NULL || !bf_last->bf_stale) + list_move_tail(&bf->list, &bf_head); + +- if (!txpending || (tid->state & AGGR_CLEANUP)) { ++ if (!txpending) { + /* + * complete the acked-ones/xretried ones; update + * block-ack window +@@ -593,9 +576,6 @@ static void ath_tx_complete_aggr(struct + ath_txq_lock(sc, txq); } - if (tid->state & AGGR_CLEANUP) +- if (tid->state & AGGR_CLEANUP) - ath_tx_flush_tid(sc, tid); -+ ath_tx_flush_tid(sc, tid, false); - +- rcu_read_unlock(); -@@ -612,6 +628,7 @@ static void ath_tx_process_buffer(struct + if (needreset) +@@ -612,6 +592,7 @@ static void ath_tx_process_buffer(struct struct ath_tx_status *ts, struct ath_buf *bf, struct list_head *bf_head) { @@ -3804,7 +3832,7 @@ bool txok, flush; txok = !(ts->ts_status & ATH9K_TXERR_MASK); -@@ -623,8 +640,12 @@ static void ath_tx_process_buffer(struct +@@ -623,8 +604,12 @@ static void ath_tx_process_buffer(struct txq->axq_ampdu_depth--; if (!bf_isampdu(bf)) { @@ -3818,7 +3846,7 @@ ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); -@@ -668,7 +689,7 @@ static u32 ath_lookup_rate(struct ath_so +@@ -668,7 +653,7 @@ static u32 ath_lookup_rate(struct ath_so skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); @@ -3827,7 +3855,7 @@ /* * Find the lowest frame length among the rate series that will have a -@@ -736,8 +757,6 @@ static int ath_compute_num_delims(struct +@@ -736,8 +721,6 @@ static int ath_compute_num_delims(struct bool first_subfrm) { #define FIRST_DESC_NDELIMS 60 @@ -3836,7 +3864,7 @@ u32 nsymbits, nsymbols; u16 minlen; u8 flags, rix; -@@ -778,8 +797,8 @@ static int ath_compute_num_delims(struct +@@ -778,8 +761,8 @@ static int ath_compute_num_delims(struct if (tid->an->mpdudensity == 0) return ndelim; @@ -3847,7 +3875,7 @@ width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; -@@ -858,6 +877,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_ +@@ -858,6 +841,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_ bf_first = bf; if (!rl) { @@ -3855,7 +3883,7 @@ aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; } -@@ -998,14 +1018,14 @@ static void ath_buf_set_rate(struct ath_ +@@ -998,14 +982,14 @@ static void ath_buf_set_rate(struct ath_ skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); @@ -3872,55 +3900,92 @@ bool is_40, is_sgi, is_sp; int phy; -@@ -1249,18 +1269,23 @@ int ath_tx_aggr_start(struct ath_softc * - return 0; - } +@@ -1224,9 +1208,6 @@ int ath_tx_aggr_start(struct ath_softc * + an = (struct ath_node *)sta->drv_priv; + txtid = ATH_AN_2_TID(an, tid); --void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -+bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, -+ bool flush) - { - struct ath_node *an = (struct ath_node *)sta->drv_priv; +- if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE)) +- return -EAGAIN; +- + /* update ampdu factor/density, they may have changed. This may happen + * in HT IBSS when a beacon with HT-info is received after the station + * has already been added. +@@ -1238,7 +1219,7 @@ int ath_tx_aggr_start(struct ath_softc * + an->mpdudensity = density; + } + +- txtid->state |= AGGR_ADDBA_PROGRESS; ++ txtid->active = true; + txtid->paused = true; + *ssn = txtid->seq_start = txtid->seq_next; + txtid->bar_index = -1; +@@ -1255,28 +1236,9 @@ void ath_tx_aggr_stop(struct ath_softc * struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = txtid->ac->txq; -+ bool ret = !flush; -+ -+ if (flush) -+ txtid->stop_cb = false; - if (txtid->state & AGGR_CLEANUP) +- if (txtid->state & AGGR_CLEANUP) - return; -+ return false; - - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - txtid->state &= ~AGGR_ADDBA_PROGRESS; +- +- if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { +- txtid->state &= ~AGGR_ADDBA_PROGRESS; - return; -+ return ret; - } - +- } +- ath_txq_lock(sc, txq); -@@ -1272,13 +1297,17 @@ void ath_tx_aggr_stop(struct ath_softc * - * TID can only be reused after all in-progress subframes have been - * completed. - */ ++ txtid->active = false; + txtid->paused = true; +- +- /* +- * If frames are still being transmitted for this TID, they will be +- * cleaned up during tx completion. To prevent race conditions, this +- * TID can only be reused after all in-progress subframes have been +- * completed. +- */ - if (txtid->baw_head != txtid->baw_tail) -+ if (txtid->baw_head != txtid->baw_tail) { - txtid->state |= AGGR_CLEANUP; +- txtid->state |= AGGR_CLEANUP; - else -+ ret = false; -+ txtid->stop_cb = !flush; -+ } else { - txtid->state &= ~AGGR_ADDBA_COMPLETE; -+ } - -- ath_tx_flush_tid(sc, txtid); -+ ath_tx_flush_tid(sc, txtid, flush); +- txtid->state &= ~AGGR_ADDBA_COMPLETE; +- + ath_tx_flush_tid(sc, txtid); ath_txq_unlock_complete(sc, txq); -+ return ret; + } +@@ -1342,18 +1304,28 @@ void ath_tx_aggr_wakeup(struct ath_softc + } + } + +-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ++void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, ++ u16 tidno) + { +- struct ath_atx_tid *txtid; ++ struct ath_atx_tid *tid; + struct ath_node *an; ++ struct ath_txq *txq; + + an = (struct ath_node *)sta->drv_priv; ++ tid = ATH_AN_2_TID(an, tidno); ++ txq = tid->ac->txq; + +- txtid = ATH_AN_2_TID(an, tid); +- txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; +- txtid->state |= AGGR_ADDBA_COMPLETE; +- txtid->state &= ~AGGR_ADDBA_PROGRESS; +- ath_tx_resume_tid(sc, txtid); ++ ath_txq_lock(sc, txq); ++ ++ tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; ++ tid->paused = false; ++ ++ if (!skb_queue_empty(&tid->buf_q)) { ++ ath_tx_queue_tid(txq, tid); ++ ath_txq_schedule(sc, txq); ++ } ++ ++ ath_txq_unlock_complete(sc, txq); } - void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, -@@ -1743,6 +1772,7 @@ static void ath_tx_send_ampdu(struct ath + /********************/ +@@ -1743,6 +1715,7 @@ static void ath_tx_send_ampdu(struct ath return; } @@ -3928,7 +3993,7 @@ bf->bf_state.bf_type = BUF_AMPDU; INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); -@@ -1892,49 +1922,6 @@ static struct ath_buf *ath_tx_setup_buff +@@ -1892,49 +1865,6 @@ static struct ath_buf *ath_tx_setup_buff return bf; } @@ -3978,7 +4043,7 @@ /* Upon failure caller should free skb */ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) -@@ -1945,8 +1932,11 @@ int ath_tx_start(struct ieee80211_hw *hw +@@ -1945,8 +1875,11 @@ int ath_tx_start(struct ieee80211_hw *hw struct ieee80211_vif *vif = info->control.vif; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; @@ -3990,7 +4055,7 @@ int q; /* NOTE: sta can be NULL according to net/mac80211.h */ -@@ -2002,8 +1992,41 @@ int ath_tx_start(struct ieee80211_hw *hw +@@ -2002,8 +1935,41 @@ int ath_tx_start(struct ieee80211_hw *hw txq->stopped = true; } @@ -3999,7 +4064,7 @@ + tidno = ieee80211_get_qos_ctl(hdr)[0] & + IEEE80211_QOS_CTL_TID_MASK; + tid = ATH_AN_2_TID(txctl->an, tidno); -+ + + WARN_ON(tid->ac->txq != txctl->txq); + } + @@ -4011,7 +4076,7 @@ + ath_tx_send_ampdu(sc, tid, skb, txctl); + goto out; + } - ++ + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + if (txctl->paprd) @@ -4033,24 +4098,32 @@ ath_txq_unlock(sc, txq); return 0; -@@ -2414,6 +2437,7 @@ void ath_tx_node_init(struct ath_softc * +@@ -2408,12 +2374,10 @@ void ath_tx_node_init(struct ath_softc * + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->paused = false; +- tid->state &= ~AGGR_CLEANUP; ++ tid->active = false; + __skb_queue_head_init(&tid->buf_q); + acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_ADDBA_PROGRESS; -+ tid->stop_cb = false; +- tid->state &= ~AGGR_ADDBA_COMPLETE; +- tid->state &= ~AGGR_ADDBA_PROGRESS; } for (acno = 0, ac = &an->ac[acno]; -@@ -2450,8 +2474,7 @@ void ath_tx_node_cleanup(struct ath_soft +@@ -2450,9 +2414,9 @@ void ath_tx_node_cleanup(struct ath_soft } ath_tid_drain(sc, txq, tid); - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; -+ ath_tx_clear_tid(sc, tid); ++ tid->active = false; ath_txq_unlock(sc, txq); } + } ++ --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -124,7 +124,7 @@ static bool ath_rx_edma_buf_link(struct @@ -4117,3 +4190,17 @@ if (wdev->sme_state == CFG80211_SME_CONNECTED) __cfg80211_disconnected(dev, NULL, 0, 0, false); else if (wdev->sme_state == CFG80211_SME_CONNECTING) +--- a/drivers/net/wireless/ath/ath9k/rc.c ++++ b/drivers/net/wireless/ath/ath9k/rc.c +@@ -1227,10 +1227,7 @@ static bool ath_tx_aggr_check(struct ath + return false; + + txtid = ATH_AN_2_TID(an, tidno); +- +- if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS))) +- return true; +- return false; ++ return !txtid->active; + } + + diff --git a/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch index 9edc4074f..f5bc24e9c 100644 --- a/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch +++ b/package/mac80211/patches/512-ath9k_channelbw_debugfs.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h -@@ -693,6 +693,7 @@ struct ath_softc { +@@ -687,6 +687,7 @@ struct ath_softc { struct ieee80211_hw *hw; struct device *dev; @@ -8,7 +8,7 @@ struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; -@@ -897,6 +898,7 @@ struct fft_sample_ht20 { +@@ -891,6 +892,7 @@ struct fft_sample_ht20 { u8 data[SPECTRAL_HT20_NUM_BINS]; } __packed; diff --git a/package/mac80211/patches/530-ath9k_extra_leds.patch b/package/mac80211/patches/530-ath9k_extra_leds.patch index 9ea1ff29f..f82cdf592 100644 --- a/package/mac80211/patches/530-ath9k_extra_leds.patch +++ b/package/mac80211/patches/530-ath9k_extra_leds.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h -@@ -555,6 +555,9 @@ struct ath9k_wow_pattern { +@@ -549,6 +549,9 @@ struct ath9k_wow_pattern { 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); @@ -10,7 +10,7 @@ #else static inline void ath_init_leds(struct ath_softc *sc) { -@@ -689,6 +692,13 @@ enum spectral_mode { +@@ -683,6 +686,13 @@ enum spectral_mode { SPECTRAL_CHANSCAN, }; @@ -24,7 +24,7 @@ struct ath_softc { struct ieee80211_hw *hw; struct device *dev; -@@ -730,9 +740,8 @@ struct ath_softc { +@@ -724,9 +734,8 @@ struct ath_softc { struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_MAC80211_LEDS -- cgit v1.2.3