From: Greg Kroah-Hartman Date: Wed, 30 Jan 2013 10:25:13 +0000 (+0100) Subject: 3.7-stable patches X-Git-Tag: v3.0.62~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e48a5f8f0b5c921ede27ad03499ed2c9e3e9df75;p=thirdparty%2Fkernel%2Fstable-queue.git 3.7-stable patches added patches: ath9k-add-a-better-fix-for-the-rx-tasklet-vs-rx-flush-race.patch ath9k-disable-the-tasklet-before-taking-the-pcu-lock.patch ath9k-fix-rx-flush-handling.patch ath9k-remove-sc-rx.rxbuflock-to-fix-a-deadlock.patch ath9k-remove-the-warn_on-that-triggers-if-generating-a-beacon-fails.patch --- diff --git a/queue-3.7/ath9k-add-a-better-fix-for-the-rx-tasklet-vs-rx-flush-race.patch b/queue-3.7/ath9k-add-a-better-fix-for-the-rx-tasklet-vs-rx-flush-race.patch new file mode 100644 index 00000000000..0a2258b6ef8 --- /dev/null +++ b/queue-3.7/ath9k-add-a-better-fix-for-the-rx-tasklet-vs-rx-flush-race.patch @@ -0,0 +1,132 @@ +From 7fc00a3054b70b1794c2d64db703eb467ad0365c Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Wed, 9 Jan 2013 16:16:55 +0100 +Subject: ath9k: add a better fix for the rx tasklet vs rx flush race + +From: Felix Fietkau + +commit 7fc00a3054b70b1794c2d64db703eb467ad0365c upstream. + +Ensure that the rx tasklet is no longer running when entering the reset path. +Also remove the distinction between flush and no-flush frame processing. +If a frame has been received and ACKed by the hardware, the stack needs to see +it, so that the BA receive window does not go out of sync. + +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 1 - + drivers/net/wireless/ath/ath9k/debug.c | 1 - + drivers/net/wireless/ath/ath9k/debug.h | 2 -- + drivers/net/wireless/ath/ath9k/main.c | 4 ++++ + drivers/net/wireless/ath/ath9k/recv.c | 15 --------------- + 5 files changed, 4 insertions(+), 19 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -630,7 +630,6 @@ void ath_ant_comb_update(struct ath_soft + enum sc_op_flags { + SC_OP_INVALID, + SC_OP_BEACONS, +- SC_OP_RXFLUSH, + SC_OP_ANI_RUN, + SC_OP_PRIM_STA_VIF, + SC_OP_HW_RESET, +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -973,7 +973,6 @@ static ssize_t read_file_recv(struct fil + RXS_ERR("RX-LENGTH-ERR", rx_len_err); + RXS_ERR("RX-OOM-ERR", rx_oom_err); + RXS_ERR("RX-RATE-ERR", rx_rate_err); +- RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush); + RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); + + PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); +--- a/drivers/net/wireless/ath/ath9k/debug.h ++++ b/drivers/net/wireless/ath/ath9k/debug.h +@@ -200,7 +200,6 @@ struct ath_tx_stats { + * @rx_oom_err: No. of frames dropped due to OOM issues. + * @rx_rate_err: No. of frames dropped due to rate errors. + * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. +- * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH. + * @rx_beacons: No. of beacons received. + * @rx_frags: No. of rx-fragements received. + */ +@@ -219,7 +218,6 @@ struct ath_rx_stats { + u32 rx_oom_err; + u32 rx_rate_err; + u32 rx_too_many_frags_err; +- u32 rx_drop_rxflush; + u32 rx_beacons; + u32 rx_frags; + }; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -195,6 +195,8 @@ static bool ath_prepare_reset(struct ath + ath9k_debug_samp_bb_mac(sc); + ath9k_hw_disable_interrupts(ah); + ++ tasklet_disable(&sc->intr_tq); ++ + if (!ath_stoprecv(sc)) + ret = false; + +@@ -209,6 +211,8 @@ static bool ath_prepare_reset(struct ath + ath_flushrecv(sc); + } + ++ tasklet_enable(&sc->intr_tq); ++ + return ret; + } + +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -286,7 +286,6 @@ int ath_rx_init(struct ath_softc *sc, in + + spin_lock_init(&sc->sc_pcu_lock); + spin_lock_init(&sc->rx.rxbuflock); +- clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); + + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + + sc->sc_ah->caps.rx_status_len; +@@ -501,11 +500,9 @@ bool ath_stoprecv(struct ath_softc *sc) + + void ath_flushrecv(struct ath_softc *sc) + { +- set_bit(SC_OP_RXFLUSH, &sc->sc_flags); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_rx_tasklet(sc, 1, true); + ath_rx_tasklet(sc, 1, false); +- clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); + } + + static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) +@@ -1067,9 +1064,6 @@ int ath_rx_tasklet(struct ath_softc *sc, + + do { + bool decrypt_error = false; +- /* If handling rx interrupt and flush is in progress => exit */ +- if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0)) +- break; + + memset(&rs, 0, sizeof(rs)); + if (edma) +@@ -1109,15 +1103,6 @@ int ath_rx_tasklet(struct ath_softc *sc, + sc->rx.num_pkts++; + ath_debug_stat_rx(sc, &rs); + +- /* +- * If we're asked to flush receive queue, directly +- * chain it back at the queue without processing it. +- */ +- if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) { +- RX_STAT_INC(rx_drop_rxflush); +- goto requeue_drop_frag; +- } +- + memset(rxs, 0, sizeof(struct ieee80211_rx_status)); + + rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; diff --git a/queue-3.7/ath9k-disable-the-tasklet-before-taking-the-pcu-lock.patch b/queue-3.7/ath9k-disable-the-tasklet-before-taking-the-pcu-lock.patch new file mode 100644 index 00000000000..98daf988520 --- /dev/null +++ b/queue-3.7/ath9k-disable-the-tasklet-before-taking-the-pcu-lock.patch @@ -0,0 +1,58 @@ +From 4668cce527acb3bd048c5e6c99b157a14b214671 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Jan 2013 16:56:46 +0100 +Subject: ath9k: disable the tasklet before taking the PCU lock + +From: Felix Fietkau + +commit 4668cce527acb3bd048c5e6c99b157a14b214671 upstream. + +Fixes a reported CPU soft lockup where the tasklet tries to acquire the +lock and blocks while ath_prepare_reset (holding the lock) waits for it +to complete. + +Reported-by: Robert Shade +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/main.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -195,16 +195,12 @@ static bool ath_prepare_reset(struct ath + ath9k_debug_samp_bb_mac(sc); + ath9k_hw_disable_interrupts(ah); + +- tasklet_disable(&sc->intr_tq); +- + if (!ath_stoprecv(sc)) + ret = false; + + if (!ath_drain_all_txq(sc, retry_tx)) + ret = false; + +- tasklet_enable(&sc->intr_tq); +- + return ret; + } + +@@ -261,6 +257,7 @@ static int ath_reset_internal(struct ath + + __ath_cancel_work(sc); + ++ tasklet_disable(&sc->intr_tq); + spin_lock_bh(&sc->sc_pcu_lock); + + if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { +@@ -291,6 +288,8 @@ static int ath_reset_internal(struct ath + + out: + spin_unlock_bh(&sc->sc_pcu_lock); ++ tasklet_enable(&sc->intr_tq); ++ + return r; + } + diff --git a/queue-3.7/ath9k-fix-rx-flush-handling.patch b/queue-3.7/ath9k-fix-rx-flush-handling.patch new file mode 100644 index 00000000000..7d013033836 --- /dev/null +++ b/queue-3.7/ath9k-fix-rx-flush-handling.patch @@ -0,0 +1,135 @@ +From 4b883f021b9ccf2df3d14425e6e610281fb6a35e Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Wed, 9 Jan 2013 16:16:56 +0100 +Subject: ath9k: fix rx flush handling + +From: Felix Fietkau + +commit 4b883f021b9ccf2df3d14425e6e610281fb6a35e upstream. + +Right now the rx flush is not doing anything useful on AR9003+, as it only +works if the buffers in the rx FIFO have not been purged yet, as is done +by ath_stoprecv. + +To fix this, always call ath_flushrecv from within ath_stoprecv before +the FIFO is emptied, but still after the hw receive path has been stopped. + +This ensures that frames received (and ACKed by the hardware) shortly before +a reset will be seen by the software, which should improve A-MPDU session +stability. + +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 1 - + drivers/net/wireless/ath/ath9k/main.c | 16 +++------------- + drivers/net/wireless/ath/ath9k/recv.c | 16 +++++++++------- + 3 files changed, 12 insertions(+), 21 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -326,7 +326,6 @@ struct ath_rx { + + int ath_startrecv(struct ath_softc *sc); + bool ath_stoprecv(struct ath_softc *sc); +-void ath_flushrecv(struct ath_softc *sc); + u32 ath_calcrxfilter(struct ath_softc *sc); + int ath_rx_init(struct ath_softc *sc, int nbufs); + void ath_rx_cleanup(struct ath_softc *sc); +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -181,7 +181,7 @@ static void ath_restart_work(struct ath_ + ath_start_ani(sc); + } + +-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) ++static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx) + { + struct ath_hw *ah = sc->sc_ah; + bool ret = true; +@@ -203,14 +203,6 @@ static bool ath_prepare_reset(struct ath + if (!ath_drain_all_txq(sc, retry_tx)) + ret = false; + +- if (!flush) { +- if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) +- ath_rx_tasklet(sc, 1, true); +- ath_rx_tasklet(sc, 1, false); +- } else { +- ath_flushrecv(sc); +- } +- + tasklet_enable(&sc->intr_tq); + + return ret; +@@ -265,7 +257,6 @@ static int ath_reset_internal(struct ath + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_cal_data *caldata = NULL; + bool fastcc = true; +- bool flush = false; + int r; + + __ath_cancel_work(sc); +@@ -279,11 +270,10 @@ static int ath_reset_internal(struct ath + + if (!hchan) { + fastcc = false; +- flush = true; + hchan = ah->curchan; + } + +- if (!ath_prepare_reset(sc, retry_tx, flush)) ++ if (!ath_prepare_reset(sc, retry_tx)) + fastcc = false; + + ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", +@@ -820,7 +810,7 @@ static void ath9k_stop(struct ieee80211_ + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); + } + +- ath_prepare_reset(sc, false, true); ++ ath_prepare_reset(sc, false); + + if (sc->rx.frag) { + dev_kfree_skb_any(sc->rx.frag); +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -472,6 +472,13 @@ start_recv: + return 0; + } + ++static void ath_flushrecv(struct ath_softc *sc) ++{ ++ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ++ ath_rx_tasklet(sc, 1, true); ++ ath_rx_tasklet(sc, 1, false); ++} ++ + bool ath_stoprecv(struct ath_softc *sc) + { + struct ath_hw *ah = sc->sc_ah; +@@ -482,6 +489,8 @@ bool ath_stoprecv(struct ath_softc *sc) + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah, &reset); + ++ ath_flushrecv(sc); ++ + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_edma_stop_recv(sc); + else +@@ -498,13 +507,6 @@ bool ath_stoprecv(struct ath_softc *sc) + return stopped && !reset; + } + +-void ath_flushrecv(struct ath_softc *sc) +-{ +- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) +- ath_rx_tasklet(sc, 1, true); +- ath_rx_tasklet(sc, 1, false); +-} +- + static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) + { + /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ diff --git a/queue-3.7/ath9k-remove-sc-rx.rxbuflock-to-fix-a-deadlock.patch b/queue-3.7/ath9k-remove-sc-rx.rxbuflock-to-fix-a-deadlock.patch new file mode 100644 index 00000000000..76b76c7446c --- /dev/null +++ b/queue-3.7/ath9k-remove-sc-rx.rxbuflock-to-fix-a-deadlock.patch @@ -0,0 +1,117 @@ +From 463e3ed3eacc8f47866e5d612bd8ee0bcee5e2f0 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 14 Jan 2013 10:50:15 +0100 +Subject: ath9k: remove sc->rx.rxbuflock to fix a deadlock + +From: Felix Fietkau + +commit 463e3ed3eacc8f47866e5d612bd8ee0bcee5e2f0 upstream. + +The commit "ath9k: fix rx flush handling" added a deadlock that happens +because ath_rx_tasklet is called in a section that has already taken the +rx buffer lock. + +It seems that the only purpose of the rxbuflock was a band-aid fix to the +reset vs rx tasklet race, which has been properly fixed in the commit +"ath9k: add a better fix for the rx tasklet vs rx flush race". + +Now that the fix is in, we can safely remove the lock to avoid such issues. + +Reported-by: Sujith Manoharan +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 1 - + drivers/net/wireless/ath/ath9k/recv.c | 13 ------------- + 2 files changed, 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -315,7 +315,6 @@ struct ath_rx { + u32 *rxlink; + u32 num_pkts; + unsigned int rxfilter; +- spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; + struct ath_buf *rx_bufptr; +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -254,8 +254,6 @@ rx_init_fail: + + static void ath_edma_start_recv(struct ath_softc *sc) + { +- spin_lock_bh(&sc->rx.rxbuflock); +- + ath9k_hw_rxena(sc->sc_ah); + + ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, +@@ -267,8 +265,6 @@ static void ath_edma_start_recv(struct a + ath_opmode_init(sc); + + ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); +- +- spin_unlock_bh(&sc->rx.rxbuflock); + } + + static void ath_edma_stop_recv(struct ath_softc *sc) +@@ -285,7 +281,6 @@ int ath_rx_init(struct ath_softc *sc, in + int error = 0; + + spin_lock_init(&sc->sc_pcu_lock); +- spin_lock_init(&sc->rx.rxbuflock); + + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + + sc->sc_ah->caps.rx_status_len; +@@ -446,7 +441,6 @@ int ath_startrecv(struct ath_softc *sc) + return 0; + } + +- spin_lock_bh(&sc->rx.rxbuflock); + if (list_empty(&sc->rx.rxbuf)) + goto start_recv; + +@@ -467,8 +461,6 @@ start_recv: + ath_opmode_init(sc); + ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); + +- spin_unlock_bh(&sc->rx.rxbuflock); +- + return 0; + } + +@@ -484,7 +476,6 @@ bool ath_stoprecv(struct ath_softc *sc) + struct ath_hw *ah = sc->sc_ah; + bool stopped, reset = false; + +- spin_lock_bh(&sc->rx.rxbuflock); + ath9k_hw_abortpcurecv(ah); + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah, &reset); +@@ -495,7 +486,6 @@ bool ath_stoprecv(struct ath_softc *sc) + ath_edma_stop_recv(sc); + else + sc->rx.rxlink = NULL; +- spin_unlock_bh(&sc->rx.rxbuflock); + + if (!(ah->ah_flags & AH_UNPLUGGED) && + unlikely(!stopped)) { +@@ -1059,7 +1049,6 @@ int ath_rx_tasklet(struct ath_softc *sc, + dma_type = DMA_FROM_DEVICE; + + qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; +- spin_lock_bh(&sc->rx.rxbuflock); + + tsf = ath9k_hw_gettsf64(ah); + tsf_lower = tsf & 0xffffffff; +@@ -1251,8 +1240,6 @@ requeue: + } + } while (1); + +- spin_unlock_bh(&sc->rx.rxbuflock); +- + if (!(ah->imask & ATH9K_INT_RXEOL)) { + ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + ath9k_hw_set_interrupts(ah); diff --git a/queue-3.7/ath9k-remove-the-warn_on-that-triggers-if-generating-a-beacon-fails.patch b/queue-3.7/ath9k-remove-the-warn_on-that-triggers-if-generating-a-beacon-fails.patch new file mode 100644 index 00000000000..8de7c5b089f --- /dev/null +++ b/queue-3.7/ath9k-remove-the-warn_on-that-triggers-if-generating-a-beacon-fails.patch @@ -0,0 +1,31 @@ +From 3adcf20afb585993ffee24de36d1975f6b26b120 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Wed, 9 Jan 2013 16:16:54 +0100 +Subject: ath9k: remove the WARN_ON that triggers if generating a beacon fails + +From: Felix Fietkau + +commit 3adcf20afb585993ffee24de36d1975f6b26b120 upstream. + +During teardown, mac80211 will not return a new beacon. This is normal and +handled properly in the driver, so there's no need to spam the user with a kernel +warning here. + +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/beacon.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath9k/beacon.c ++++ b/drivers/net/wireless/ath/ath9k/beacon.c +@@ -360,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long + return; + + bf = ath9k_beacon_generate(sc->hw, vif); +- WARN_ON(!bf); + + if (sc->beacon.bmisscnt != 0) { + ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", diff --git a/queue-3.7/series b/queue-3.7/series index 35815d142d5..df127c88b6b 100644 --- a/queue-3.7/series +++ b/queue-3.7/series @@ -34,3 +34,8 @@ mac80211-fix-ft-roaming.patch ath9k_htc-fix-memory-leak.patch ath9k-do-not-link-receive-buffers-during-flush.patch ath9k-fix-double-free-bug-on-beacon-generate-failure.patch +ath9k-remove-the-warn_on-that-triggers-if-generating-a-beacon-fails.patch +ath9k-add-a-better-fix-for-the-rx-tasklet-vs-rx-flush-race.patch +ath9k-fix-rx-flush-handling.patch +ath9k-remove-sc-rx.rxbuflock-to-fix-a-deadlock.patch +ath9k-disable-the-tasklet-before-taking-the-pcu-lock.patch