From: Greg Kroah-Hartman Date: Fri, 11 Feb 2011 22:01:12 +0000 (-0800) Subject: .36 patches X-Git-Tag: v2.6.36.4~47 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cc0deeb18b94edb4824155606029a01a40dfe395;p=thirdparty%2Fkernel%2Fstable-queue.git .36 patches --- diff --git a/queue-2.6.36/ath9k-fix-aphy-wiphy-idle-mismatch.patch b/queue-2.6.36/ath9k-fix-aphy-wiphy-idle-mismatch.patch new file mode 100644 index 00000000000..b42b9ef3d62 --- /dev/null +++ b/queue-2.6.36/ath9k-fix-aphy-wiphy-idle-mismatch.patch @@ -0,0 +1,50 @@ +From afe68d0a8f5961652e26cea39d74e2cc820de841 Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Mon, 20 Dec 2010 11:29:59 -0500 +Subject: ath9k: fix aphy / wiphy idle mismatch + +From: Luis R. Rodriguez + +commit afe68d0a8f5961652e26cea39d74e2cc820de841 upstream. + +ath9k supports its own set of virtual wiphys, and it uses +the mac80211 idle notifications to know when a device needs +to be idle or not. We recently changed ath9k to force idle +on driver stop() and on resume but forgot to take into account +ath9k's own virtual wiphy idle states. These are used internally +by ath9k to check if the device's radio should be powered down +on each idle call. Without this change its possible that the +device could have been forced off but the virtual wiphy idle +was left on. + +Cc: Paul Stewart +Cc: Amod Bodas +Signed-off-by: Luis R. Rodriguez +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/main.c | 1 + + drivers/net/wireless/ath/ath9k/pci.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1370,6 +1370,7 @@ static void ath9k_stop(struct ieee80211_ + ath9k_ps_restore(sc); + + sc->ps_idle = true; ++ ath9k_set_wiphy_idle(aphy, true); + ath_radio_disable(sc, hw); + + sc->sc_flags |= SC_OP_INVALID; +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -291,6 +291,7 @@ static int ath_pci_resume(struct pci_dev + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + + sc->ps_idle = true; ++ ath9k_set_wiphy_idle(aphy, true); + ath_radio_disable(sc, hw); + + return 0; diff --git a/queue-2.6.36/ath9k-fix-assumptions-for-idle-calls-on-suspend-resume.patch b/queue-2.6.36/ath9k-fix-assumptions-for-idle-calls-on-suspend-resume.patch new file mode 100644 index 00000000000..82cf06be522 --- /dev/null +++ b/queue-2.6.36/ath9k-fix-assumptions-for-idle-calls-on-suspend-resume.patch @@ -0,0 +1,67 @@ +From a08e7ade9ddf4fe79576f953cc5c1725e944d26c Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Tue, 7 Dec 2010 15:13:20 -0800 +Subject: ath9k: fix assumptions for idle calls on suspend/resume + +From: Luis R. Rodriguez + +commit a08e7ade9ddf4fe79576f953cc5c1725e944d26c upstream. + +mac80211 will notify drivers when to go idle and ath9k +assumed that it would get further notifications for idle +states after a device stop() config call but as per agreed +semantics the idle state of the radio is left up to driver +after mac80211 issues the stop() callback. The driver is +resposnbile for ensuring the device remains idle after +that even between suspend / resume calls. + +This fixes suspend/resume when you issue suspend and resume +twice on ath9k when ath9k_stop() was already called. We need +to put the radio to full sleep in order for resume to work +correctly. + +What might seem fishy is we are turning the radio off +after resume. The reason why we do this is because we know +we should not have anything enabled after a mac80211 tells +us to stop(), if we resume and never get a start() we won't +get another stop() by mac80211 so to be safe always bring +the 802.11 device with the radio disabled after resume, +this ensures that if we suspend we already have the radio +disabled and only a start() will ever trigger it on. + +Cc: Paul Stewart +Cc: Amod Bodas +Signed-off-by: Luis R. Rodriguez +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/main.c | 4 ++-- + drivers/net/wireless/ath/ath9k/pci.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1369,8 +1369,8 @@ static void ath9k_stop(struct ieee80211_ + ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_ps_restore(sc); + +- /* Finally, put the chip in FULL SLEEP mode */ +- ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); ++ sc->ps_idle = true; ++ ath_radio_disable(sc, hw); + + sc->sc_flags |= SC_OP_INVALID; + +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -290,6 +290,9 @@ static int ath_pci_resume(struct pci_dev + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + ++ sc->ps_idle = true; ++ ath_radio_disable(sc, hw); ++ + return 0; + } + diff --git a/queue-2.6.36/ath9k-fix-beacon-restart-on-channel-change.patch b/queue-2.6.36/ath9k-fix-beacon-restart-on-channel-change.patch new file mode 100644 index 00000000000..507298741e3 --- /dev/null +++ b/queue-2.6.36/ath9k-fix-beacon-restart-on-channel-change.patch @@ -0,0 +1,33 @@ +From 1186488b4a4d4871e40cb1604ba3ede3d4b7cc90 Mon Sep 17 00:00:00 2001 +From: Rajkumar Manoharan +Date: Thu, 30 Dec 2010 19:07:44 +0530 +Subject: ath9k: fix beacon restart on channel change + +From: Rajkumar Manoharan + +commit 1186488b4a4d4871e40cb1604ba3ede3d4b7cc90 upstream. + +Restart the beacon timers only if the beacon +was already configured. Otherwise beacons timers +are restarted unnecessarily in unassociated state too. + +Signed-off-by: Rajkumar Manoharan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -258,7 +258,8 @@ int ath_set_channel(struct ath_softc *sc + ath9k_hw_set_interrupts(ah, ah->imask); + + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { +- ath_beacon_config(sc, NULL); ++ if (sc->sc_flags & SC_OP_BEACONS) ++ ath_beacon_config(sc, NULL); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ath_start_ani(common); + } diff --git a/queue-2.6.36/ath9k-fix-bug-in-delimiter-padding-computation.patch b/queue-2.6.36/ath9k-fix-bug-in-delimiter-padding-computation.patch new file mode 100644 index 00000000000..be4068910f7 --- /dev/null +++ b/queue-2.6.36/ath9k-fix-bug-in-delimiter-padding-computation.patch @@ -0,0 +1,34 @@ +From 39ec2997c374b528cdbf65099b6d6b8593a67f7f Mon Sep 17 00:00:00 2001 +From: Vasanthakumar Thiagarajan +Date: Wed, 10 Nov 2010 05:03:15 -0800 +Subject: ath9k: Fix bug in delimiter padding computation + +From: Vasanthakumar Thiagarajan + +commit 39ec2997c374b528cdbf65099b6d6b8593a67f7f upstream. + +There is a roundng error in delimiter padding computation +which causes severe throughput drop with some of AR9003. + +signed-off-by: Felix Fietkau +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -177,8 +177,8 @@ void ath_descdma_cleanup(struct ath_soft + + /* returns delimiter padding required given the packet length */ + #define ATH_AGGR_GET_NDELIM(_len) \ +- (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ +- (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) ++ (((_len) >= ATH_AGGR_MINPLEN) ? 0 : \ ++ DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ)) + + #define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) diff --git a/queue-2.6.36/ath9k-fix-race-conditions-when-stop-device.patch b/queue-2.6.36/ath9k-fix-race-conditions-when-stop-device.patch new file mode 100644 index 00000000000..75f47fdf930 --- /dev/null +++ b/queue-2.6.36/ath9k-fix-race-conditions-when-stop-device.patch @@ -0,0 +1,72 @@ +From 203043f579ece44bb30291442cd56332651dd37d Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Tue, 25 Jan 2011 14:08:40 +0100 +Subject: ath9k: fix race conditions when stop device + +From: Stanislaw Gruszka + +commit 203043f579ece44bb30291442cd56332651dd37d upstream. + +We do not kill any scheduled tasklets when stopping device, that may +cause usage of resources after free. Moreover we enable interrupts +in tasklet function, so we could potentially end with interrupts +enabled when driver is not ready to receive them. + +I think patch should fix Ben's kernel crash from: +http://marc.info/?l=linux-wireless&m=129438358921501&w=2 + +Signed-off-by: Stanislaw Gruszka +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/init.c | 5 ----- + drivers/net/wireless/ath/ath9k/main.c | 9 +++++++++ + 2 files changed, 9 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -626,8 +626,6 @@ err_queues: + err_debug: + ath9k_hw_deinit(ah); + err_hw: +- tasklet_kill(&sc->intr_tq); +- tasklet_kill(&sc->bcon_tasklet); + + kfree(ah); + sc->sc_ah = NULL; +@@ -787,9 +785,6 @@ static void ath9k_deinit_softc(struct at + ath9k_exit_debug(sc->sc_ah); + ath9k_hw_deinit(sc->sc_ah); + +- tasklet_kill(&sc->intr_tq); +- tasklet_kill(&sc->bcon_tasklet); +- + kfree(sc->sc_ah); + sc->sc_ah = NULL; + } +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1349,6 +1349,9 @@ static void ath9k_stop(struct ieee80211_ + ath9k_btcoex_timer_pause(sc); + } + ++ /* prevent tasklets to enable interrupts once we disable them */ ++ ah->imask &= ~ATH9K_INT_GLOBAL; ++ + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(ah, 0); +@@ -1823,6 +1826,12 @@ static int ath9k_set_key(struct ieee8021 + ret = -EINVAL; + } + ++ /* we can now sync irq and kill any running tasklets, since we already ++ * disabled interrupts and not holding a spin lock */ ++ synchronize_irq(sc->irq); ++ tasklet_kill(&sc->intr_tq); ++ tasklet_kill(&sc->bcon_tasklet); ++ + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + diff --git a/queue-2.6.36/ath9k-move-the-pcu-lock-to-the-sc-structure.patch b/queue-2.6.36/ath9k-move-the-pcu-lock-to-the-sc-structure.patch new file mode 100644 index 00000000000..f3bd9c85914 --- /dev/null +++ b/queue-2.6.36/ath9k-move-the-pcu-lock-to-the-sc-structure.patch @@ -0,0 +1,237 @@ +From 4bdd1e978ede034c1211957eb17eaf50de00d234 Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Tue, 26 Oct 2010 15:27:24 -0700 +Subject: ath9k: move the PCU lock to the sc structure + +From: Luis R. Rodriguez + +commit 4bdd1e978ede034c1211957eb17eaf50de00d234 upstream. + +The PCU lock should be used to contend TX DMA as well, +this will be done next. + +This is part of a series of patches which fix stopping +TX DMA completley when requested on the driver. +For more details about this issue refer to this thread: + +http://marc.info/?l=linux-wireless&m=128629803703756&w=2 + +Tested-by: Ben Greear +Cc: Kyungwan Nam +Signed-off-by: Luis R. Rodriguez +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 2 - + drivers/net/wireless/ath/ath9k/main.c | 42 ++++++++++++++++----------------- + drivers/net/wireless/ath/ath9k/recv.c | 2 - + drivers/net/wireless/ath/ath9k/xmit.c | 4 +-- + 4 files changed, 25 insertions(+), 25 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -312,7 +312,6 @@ struct ath_rx { + u8 rxotherant; + u32 *rxlink; + unsigned int rxfilter; +- spinlock_t pcu_lock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +@@ -559,6 +558,7 @@ struct ath_softc { + int irq; + spinlock_t sc_serial_rw; + spinlock_t sc_pm_lock; ++ spinlock_t sc_pcu_lock; + struct mutex mutex; + struct work_struct paprd_work; + struct work_struct hw_check_work; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -214,7 +214,7 @@ int ath_set_channel(struct ath_softc *sc + ath9k_hw_set_interrupts(ah, 0); + ath_drain_all_txq(sc, false); + +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + + stopped = ath_stoprecv(sc); + +@@ -239,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc + "Unable to reset channel (%u MHz), " + "reset status %d\n", + channel->center_freq, r); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + goto ps_restore; + } + +@@ -247,11 +247,11 @@ int ath_set_channel(struct ath_softc *sc + ath_print(common, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); + r = -EIO; +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + goto ps_restore; + } + +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + + ath_cache_conf_rate(sc, &hw->conf); + ath_update_txpow(sc); +@@ -588,7 +588,7 @@ void ath9k_tasklet(unsigned long data) + rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + + if (status & rxmask) { +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + + /* Check for high priority Rx first */ + if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && +@@ -596,7 +596,7 @@ void ath9k_tasklet(unsigned long data) + ath_rx_tasklet(sc, 0, true); + + ath_rx_tasklet(sc, 0, false); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + } + + if (status & ATH9K_INT_TX) { +@@ -843,7 +843,7 @@ void ath_radio_enable(struct ath_softc * + if (!ah->curchan) + ah->curchan = ath_get_curchannel(sc, sc->hw); + +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + if (r) { + ath_print(common, ATH_DBG_FATAL, +@@ -856,10 +856,10 @@ void ath_radio_enable(struct ath_softc * + if (ath_startrecv(sc) != 0) { + ath_print(common, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + return; + } +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, NULL); /* restart beacons */ +@@ -899,7 +899,7 @@ void ath_radio_disable(struct ath_softc + + ath_drain_all_txq(sc, false); /* clear pending tx frames */ + +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + + ath_stoprecv(sc); /* turn off frame recv */ + ath_flushrecv(sc); /* flush recv queue */ +@@ -917,7 +917,7 @@ void ath_radio_disable(struct ath_softc + + ath9k_hw_phy_disable(ah); + +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + + ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_ps_restore(sc); +@@ -939,7 +939,7 @@ int ath_reset(struct ath_softc *sc, bool + ath9k_hw_set_interrupts(ah, 0); + ath_drain_all_txq(sc, retry_tx); + +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + + ath_stoprecv(sc); + ath_flushrecv(sc); +@@ -953,7 +953,7 @@ int ath_reset(struct ath_softc *sc, bool + ath_print(common, ATH_DBG_FATAL, + "Unable to start recv logic\n"); + +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + + /* + * We may be doing a reset in response to a request +@@ -1119,14 +1119,14 @@ static int ath9k_start(struct ieee80211_ + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d " + "(freq %u MHz)\n", r, + curchan->center_freq); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + goto mutex_unlock; + } + +@@ -1147,10 +1147,10 @@ static int ath9k_start(struct ieee80211_ + ath_print(common, ATH_DBG_FATAL, + "Unable to start recv logic\n"); + r = -EIO; +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + goto mutex_unlock; + } +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + + /* Setup our intr mask. */ + ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | +@@ -1354,14 +1354,14 @@ static void ath9k_stop(struct ieee80211_ + + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_drain_all_txq(sc, false); +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + ath_stoprecv(sc); + ath9k_hw_phy_disable(ah); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + } else { +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + sc->rx.rxlink = NULL; +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + } + + /* disable HAL and put h/w to sleep */ +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -308,7 +308,7 @@ int ath_rx_init(struct ath_softc *sc, in + struct ath_buf *bf; + int error = 0; + +- spin_lock_init(&sc->rx.pcu_lock); ++ spin_lock_init(&sc->sc_pcu_lock); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_lock_init(&sc->rx.rxbuflock); + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1160,13 +1160,13 @@ void ath_drain_all_txq(struct ath_softc + ath_print(common, ATH_DBG_FATAL, + "Failed to stop TX DMA. Resetting hardware!\n"); + +- spin_lock_bh(&sc->rx.pcu_lock); ++ spin_lock_bh(&sc->sc_pcu_lock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); + if (r) + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d\n", + r); +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->sc_pcu_lock); + } + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { diff --git a/queue-2.6.36/ath9k-simplify-hw-reset-locking.patch b/queue-2.6.36/ath9k-simplify-hw-reset-locking.patch new file mode 100644 index 00000000000..9a0c81e6816 --- /dev/null +++ b/queue-2.6.36/ath9k-simplify-hw-reset-locking.patch @@ -0,0 +1,175 @@ +From 9d94674ab754be0e275120a183670ead435f9c0d Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Tue, 26 Oct 2010 15:27:23 -0700 +Subject: ath9k: simplify hw reset locking + +From: Luis R. Rodriguez + +commit 9d94674ab754be0e275120a183670ead435f9c0d upstream. + +The new PCU lock is better placed so we can just contend +against that when trying to reset hardware. + +This is part of a series of patches which fix stopping +TX DMA completley when requested on the driver. +For more details about this issue refer to this thread: + +http://marc.info/?l=linux-wireless&m=128629803703756&w=2 + +Tested-by: Ben Greear +Cc: Kyungwan Nam +Signed-off-by: Luis R. Rodriguez +Signed-off-by: John W. Linville + +--- + drivers/net/wireless/ath/ath9k/ath9k.h | 1 - + drivers/net/wireless/ath/ath9k/init.c | 1 - + drivers/net/wireless/ath/ath9k/main.c | 22 ++++++---------------- + drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- + 4 files changed, 8 insertions(+), 20 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -557,7 +557,6 @@ struct ath_softc { + struct ath_hw *sc_ah; + void __iomem *mem; + int irq; +- spinlock_t sc_resetlock; + spinlock_t sc_serial_rw; + spinlock_t sc_pm_lock; + struct mutex mutex; +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -574,7 +574,6 @@ static int ath9k_init_softc(u16 devid, s + common->debug_mask = ath9k_debug; + + spin_lock_init(&sc->wiphy_lock); +- spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->sc_pm_lock); + mutex_init(&sc->mutex); +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -233,19 +233,15 @@ int ath_set_channel(struct ath_softc *sc + sc->sc_ah->curchan->channel, + channel->center_freq, conf_is_ht40(conf)); + +- spin_lock_bh(&sc->sc_resetlock); +- + r = ath9k_hw_reset(ah, hchan, caldata, fastcc); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Unable to reset channel (%u MHz), " + "reset status %d\n", + channel->center_freq, r); +- spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); + goto ps_restore; + } +- spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) { + ath_print(common, ATH_DBG_FATAL, +@@ -848,7 +844,6 @@ void ath_radio_enable(struct ath_softc * + ah->curchan = ath_get_curchannel(sc, sc->hw); + + spin_lock_bh(&sc->rx.pcu_lock); +- spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + if (r) { + ath_print(common, ATH_DBG_FATAL, +@@ -856,7 +851,6 @@ void ath_radio_enable(struct ath_softc * + "reset status %d\n", + channel->center_freq, r); + } +- spin_unlock_bh(&sc->sc_resetlock); + + ath_update_txpow(sc); + if (ath_startrecv(sc) != 0) { +@@ -913,7 +907,6 @@ void ath_radio_disable(struct ath_softc + if (!ah->curchan) + ah->curchan = ath_get_curchannel(sc, hw); + +- spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + if (r) { + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, +@@ -921,7 +914,6 @@ void ath_radio_disable(struct ath_softc + "reset status %d\n", + channel->center_freq, r); + } +- spin_unlock_bh(&sc->sc_resetlock); + + ath9k_hw_phy_disable(ah); + +@@ -952,12 +944,10 @@ int ath_reset(struct ath_softc *sc, bool + ath_stoprecv(sc); + ath_flushrecv(sc); + +- spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); + if (r) + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d\n", r); +- spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) + ath_print(common, ATH_DBG_FATAL, +@@ -1130,18 +1120,15 @@ static int ath9k_start(struct ieee80211_ + * and then setup of the interrupt mask. + */ + spin_lock_bh(&sc->rx.pcu_lock); +- spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d " + "(freq %u MHz)\n", r, + curchan->center_freq); +- spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); + goto mutex_unlock; + } +- spin_unlock_bh(&sc->sc_resetlock); + + /* + * This is needed only to setup initial state +@@ -1365,14 +1352,17 @@ static void ath9k_stop(struct ieee80211_ + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(ah, 0); + +- spin_lock_bh(&sc->rx.pcu_lock); + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_drain_all_txq(sc, false); ++ spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); + ath9k_hw_phy_disable(ah); +- } else ++ spin_unlock_bh(&sc->rx.pcu_lock); ++ } else { ++ spin_lock_bh(&sc->rx.pcu_lock); + sc->rx.rxlink = NULL; +- spin_unlock_bh(&sc->rx.pcu_lock); ++ spin_unlock_bh(&sc->rx.pcu_lock); ++ } + + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(ah); +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1160,13 +1160,13 @@ void ath_drain_all_txq(struct ath_softc + ath_print(common, ATH_DBG_FATAL, + "Failed to stop TX DMA. Resetting hardware!\n"); + +- spin_lock_bh(&sc->sc_resetlock); ++ spin_lock_bh(&sc->rx.pcu_lock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); + if (r) + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d\n", + r); +- spin_unlock_bh(&sc->sc_resetlock); ++ spin_unlock_bh(&sc->rx.pcu_lock); + } + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { diff --git a/queue-2.6.36/ath9k_htc-handle-pending-urbs-properly.patch b/queue-2.6.36/ath9k_htc-handle-pending-urbs-properly.patch new file mode 100644 index 00000000000..6080ece6c80 --- /dev/null +++ b/queue-2.6.36/ath9k_htc-handle-pending-urbs-properly.patch @@ -0,0 +1,117 @@ +From ff8f59b5bbdf1527235b8c88d859c7d23691324f Mon Sep 17 00:00:00 2001 +From: Sujith Manoharan +Date: Tue, 28 Dec 2010 14:28:05 +0530 +Subject: ath9k_htc: Handle pending URBs properly + +From: Sujith Manoharan + +commit ff8f59b5bbdf1527235b8c88d859c7d23691324f upstream. + +When doing a channel change, the pending URBs have to be killed +properly on calling htc_stop(). + +This fixes the probe response timeout seen when sending UDP traffic at +a high rate and running background scan at the same time. + +Signed-off-by: Sujith Manoharan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/hif_usb.c | 40 +++++++++++++++++++++++++++---- + drivers/net/wireless/ath/ath9k/hif_usb.h | 1 + 2 files changed, 37 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/hif_usb.c ++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c +@@ -144,16 +144,36 @@ static void hif_usb_tx_cb(struct urb *ur + case -ENODEV: + case -ESHUTDOWN: + /* +- * The URB has been killed, free the SKBs +- * and return. ++ * The URB has been killed, free the SKBs. + */ + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); +- return; ++ ++ /* ++ * If the URBs are being flushed, no need to add this ++ * URB to the free list. ++ */ ++ spin_lock(&hif_dev->tx.tx_lock); ++ if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { ++ spin_unlock(&hif_dev->tx.tx_lock); ++ return; ++ } ++ spin_unlock(&hif_dev->tx.tx_lock); ++ ++ /* ++ * In the stop() case, this URB has to be added to ++ * the free list. ++ */ ++ goto add_free; + default: + break; + } + +- /* Check if TX has been stopped */ ++ /* ++ * Check if TX has been stopped, this is needed because ++ * this CB could have been invoked just after the TX lock ++ * was released in hif_stop() and kill_urb() hasn't been ++ * called yet. ++ */ + spin_lock(&hif_dev->tx.tx_lock); + if (hif_dev->tx.flags & HIF_USB_TX_STOP) { + spin_unlock(&hif_dev->tx.tx_lock); +@@ -305,6 +325,7 @@ static void hif_usb_start(void *hif_hand + static void hif_usb_stop(void *hif_handle, u8 pipe_id) + { + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; ++ struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); +@@ -312,6 +333,12 @@ static void hif_usb_stop(void *hif_handl + hif_dev->tx.tx_skb_cnt = 0; + hif_dev->tx.flags |= HIF_USB_TX_STOP; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); ++ ++ /* The pending URBs have to be canceled. */ ++ list_for_each_entry_safe(tx_buf, tx_buf_tmp, ++ &hif_dev->tx.tx_pending, list) { ++ usb_kill_urb(tx_buf->urb); ++ } + } + + static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, +@@ -577,6 +604,7 @@ free: + static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) + { + struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; ++ unsigned long flags; + + list_for_each_entry_safe(tx_buf, tx_buf_tmp, + &hif_dev->tx.tx_buf, list) { +@@ -587,6 +615,10 @@ static void ath9k_hif_usb_dealloc_tx_urb + kfree(tx_buf); + } + ++ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); ++ hif_dev->tx.flags |= HIF_USB_TX_FLUSH; ++ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); ++ + list_for_each_entry_safe(tx_buf, tx_buf_tmp, + &hif_dev->tx.tx_pending, list) { + usb_kill_urb(tx_buf->urb); +--- a/drivers/net/wireless/ath/ath9k/hif_usb.h ++++ b/drivers/net/wireless/ath/ath9k/hif_usb.h +@@ -62,6 +62,7 @@ struct tx_buf { + }; + + #define HIF_USB_TX_STOP BIT(0) ++#define HIF_USB_TX_FLUSH BIT(1) + + struct hif_usb_tx { + u8 flags; diff --git a/queue-2.6.36/ath9k_hw-disabled-paprd-for-ar9003.patch b/queue-2.6.36/ath9k_hw-disabled-paprd-for-ar9003.patch new file mode 100644 index 00000000000..afe618b47ab --- /dev/null +++ b/queue-2.6.36/ath9k_hw-disabled-paprd-for-ar9003.patch @@ -0,0 +1,57 @@ +From 6f4810101a629b31b5427872a09ea092cfc5c4bd Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Thu, 20 Jan 2011 17:47:39 -0800 +Subject: ath9k_hw: disabled PAPRD for AR9003 + +From: Luis R. Rodriguez + +commit 6f4810101a629b31b5427872a09ea092cfc5c4bd upstream. + +AR9003's PAPRD was enabled prematurely, and is causing some +large discrepancies on throughput and network connectivity. +For example downlink (RX) throughput against an AR9280 AP +can vary widlely from 43-73 Mbit/s while disabling this +gets AR9382 (2x2) up to around 93 Mbit/s in a 2.4 GHz HT20 setup. + +Cc: Paul Shaw +Signed-off-by: Luis R. Rodriguez +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/hw.c | 6 +++++- + drivers/net/wireless/ath/ath9k/hw.h | 1 + + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -387,6 +387,9 @@ static void ath9k_hw_init_config(struct + else + ah->config.ht_enable = 0; + ++ /* PAPRD needs some more work to be enabled */ ++ ah->config.paprd_disable = 1; ++ + ah->config.rx_intr_mitigation = true; + ah->config.pcieSerDesWrite = true; + +@@ -2264,7 +2267,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw + pCap->rx_status_len = sizeof(struct ar9003_rxs); + pCap->tx_desc_len = sizeof(struct ar9003_txc); + pCap->txs_len = sizeof(struct ar9003_txs); +- if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) ++ if (!ah->config.paprd_disable && ++ ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) + pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; + } else { + pCap->tx_desc_len = sizeof(struct ath_desc); +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -240,6 +240,7 @@ struct ath9k_ops_config { + u32 pcie_waen; + u8 analog_shiftreg; + u8 ht_enable; ++ u8 paprd_disable; + u32 ofdm_trig_low; + u32 ofdm_trig_high; + u32 cck_trig_high; diff --git a/queue-2.6.36/ath9k_hw-do-pa-offset-calibration-only-on-longcal-interval.patch b/queue-2.6.36/ath9k_hw-do-pa-offset-calibration-only-on-longcal-interval.patch new file mode 100644 index 00000000000..33873a06c50 --- /dev/null +++ b/queue-2.6.36/ath9k_hw-do-pa-offset-calibration-only-on-longcal-interval.patch @@ -0,0 +1,61 @@ +From 811ea256b30b37091b5bbf41517404cf98ab56c1 Mon Sep 17 00:00:00 2001 +From: Rajkumar Manoharan +Date: Mon, 17 Jan 2011 15:21:40 +0530 +Subject: ath9k_hw: do PA offset calibration only on longcal interval + +From: Rajkumar Manoharan + +commit 811ea256b30b37091b5bbf41517404cf98ab56c1 upstream. + +The power detector adc offset calibration has to be done +on 4 minutes interval (longcal * pa_skip_count). But the commit +"ath9k_hw: fix a noise floor calibration related race condition" +makes the PA calibration executed more frequently beased on +nfcal_pending value. Running PAOffset calibration lesser than +longcal interval doesn't help anything and the worse part is that +it causes NF load timeouts and RX deaf conditions. + +In a very noisy environment, where the distance b/w AP & station +is ~10 meter and running a downlink udp traffic with frequent +background scan causes "Timeout while waiting for nf to load: +AR_PHY_AGC_CONTROL=0x40d1a" and moves the chip into deaf state. +This issue was originaly reported in Android platform where +the network-manager application does bgscan more frequently +on AR9271 chips. (AR9285 family usb device). + +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Rajkumar Manoharan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ar9002_calib.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c +@@ -710,10 +710,6 @@ static bool ar9002_hw_calibrate(struct a + + /* Do NF cal only at longer intervals */ + if (longcal || nfcal_pending) { +- /* Do periodic PAOffset Cal */ +- ar9002_hw_pa_cal(ah, false); +- ar9002_hw_olc_temp_compensation(ah); +- + /* + * Get the value from the previous NF cal and update + * history buffer. +@@ -728,8 +724,12 @@ static bool ar9002_hw_calibrate(struct a + ath9k_hw_loadnf(ah, ah->curchan); + } + +- if (longcal) ++ if (longcal) { + ath9k_hw_start_nfcal(ah, false); ++ /* Do periodic PAOffset Cal */ ++ ar9002_hw_pa_cal(ah, false); ++ ar9002_hw_olc_temp_compensation(ah); ++ } + } + + return iscaldone; diff --git a/queue-2.6.36/ath9k_hw-fix-system-hang-when-resuming-from-s3-s4.patch b/queue-2.6.36/ath9k_hw-fix-system-hang-when-resuming-from-s3-s4.patch new file mode 100644 index 00000000000..17e46f090cb --- /dev/null +++ b/queue-2.6.36/ath9k_hw-fix-system-hang-when-resuming-from-s3-s4.patch @@ -0,0 +1,38 @@ +From 5b64aa72ead6f8be488d2be7af579f0d69fb7a6e Mon Sep 17 00:00:00 2001 +From: Rajkumar Manoharan +Date: Thu, 27 Jan 2011 18:39:37 +0530 +Subject: ath9k_hw: Fix system hang when resuming from S3/S4 + +From: Rajkumar Manoharan + +commit 5b64aa72ead6f8be488d2be7af579f0d69fb7a6e upstream. + +The bit 6 & 7 of AR_WA (0x4004) should be enabled only +for the chips that are supporting L0s functionality +while resuming back from S3/S4. + +Enabling these bits for AR9280 is causing system hang +within a few S3/S4-resume cycles. + +Cc: Jack Lee +Signed-off-by: Rajkumar Manoharan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ar9002_hw.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c +@@ -445,9 +445,8 @@ static void ar9002_hw_configpcipowersave + } + + /* WAR for ASPM system hang */ +- if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) { ++ if (AR_SREV_9285(ah) || AR_SREV_9287(ah)) + val |= (AR_WA_BIT6 | AR_WA_BIT7); +- } + + if (AR_SREV_9285E_20(ah)) + val |= AR_WA_BIT23; diff --git a/queue-2.6.36/ath9k_hw-fix-xpabias-level-configuration-for-ar9003.patch b/queue-2.6.36/ath9k_hw-fix-xpabias-level-configuration-for-ar9003.patch new file mode 100644 index 00000000000..54a7dc5c87a --- /dev/null +++ b/queue-2.6.36/ath9k_hw-fix-xpabias-level-configuration-for-ar9003.patch @@ -0,0 +1,52 @@ +From 52a0e2477dac2106bc1688cbe9615cdafc9deb7d Mon Sep 17 00:00:00 2001 +From: Vasanthakumar Thiagarajan +Date: Wed, 10 Nov 2010 05:03:11 -0800 +Subject: ath9k_hw: Fix XPABIAS level configuration for AR9003 + +From: Vasanthakumar Thiagarajan + +commit 52a0e2477dac2106bc1688cbe9615cdafc9deb7d upstream. + +Improper configuration of 0x16288 and 0x16290 would affect transmission. + +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +@@ -22,12 +22,14 @@ + #define COMP_CKSUM_LEN 2 + + #define AR_CH0_TOP (0x00016288) +-#define AR_CH0_TOP_XPABIASLVL (0x3) ++#define AR_CH0_TOP_XPABIASLVL (0x300) + #define AR_CH0_TOP_XPABIASLVL_S (8) + + #define AR_CH0_THERM (0x00016290) +-#define AR_CH0_THERM_SPARE (0x3f) +-#define AR_CH0_THERM_SPARE_S (0) ++#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 ++#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 ++#define AR_CH0_THERM_XPASHORT2GND 0x4 ++#define AR_CH0_THERM_XPASHORT2GND_S 2 + + #define AR_SWITCH_TABLE_COM_ALL (0xffff) + #define AR_SWITCH_TABLE_COM_ALL_S (0) +@@ -995,9 +997,9 @@ static s32 ar9003_hw_xpa_bias_level_get( + static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) + { + int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); +- REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, (bias & 0x3)); +- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_SPARE, +- ((bias >> 2) & 0x3)); ++ REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); ++ REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, bias >> 2); ++ REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); + } + + static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) diff --git a/queue-2.6.36/iwlagn-enable-only-rfkill-interrupt-when-device-is-down.patch b/queue-2.6.36/iwlagn-enable-only-rfkill-interrupt-when-device-is-down.patch new file mode 100644 index 00000000000..2cae375fc0a --- /dev/null +++ b/queue-2.6.36/iwlagn-enable-only-rfkill-interrupt-when-device-is-down.patch @@ -0,0 +1,78 @@ +From 554d1d027b19265c4aa3f718b3126d2b86e09a08 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Thu, 23 Dec 2010 12:38:21 +0100 +Subject: iwlagn: enable only rfkill interrupt when device is down + +From: Stanislaw Gruszka + +commit 554d1d027b19265c4aa3f718b3126d2b86e09a08 upstream. + +Since commit 6cd0b1cb872b3bf9fc5de4536404206ab74bafdd "iwlagn: fix +hw-rfkill while the interface is down", we enable interrupts when +device is not ready to receive them. However hardware, when it is in +some inconsistent state, can generate other than rfkill interrupts +and crash the system. I can reproduce crash with "kernel BUG at +drivers/net/wireless/iwlwifi/iwl-agn.c:1010!" message, when forcing +firmware restarts. + +To fix only enable rfkill interrupt when down device and after probe. +I checked patch on laptop with 5100 device, rfkill change is still +passed to user space when device is down. + +Signed-off-by: Stanislaw Gruszka +Acked-by: Wey-Yi Guy +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++++---- + drivers/net/wireless/iwlwifi/iwl-helpers.h | 6 ++++++ + 2 files changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -3260,9 +3260,10 @@ static void iwl_mac_stop(struct ieee8021 + + flush_workqueue(priv->workqueue); + +- /* enable interrupts again in order to receive rfkill changes */ ++ /* User space software may expect getting rfkill changes ++ * even if interface is down */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); +- iwl_enable_interrupts(priv); ++ iwl_enable_rfkill_int(priv); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + } +@@ -4103,14 +4104,14 @@ static int iwl_pci_probe(struct pci_dev + * 8. Enable interrupts and read RFKILL state + *********************************************/ + +- /* enable interrupts if needed: hw bug w/a */ ++ /* enable rfkill interrupt: hw bug w/a */ + pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); + } + +- iwl_enable_interrupts(priv); ++ iwl_enable_rfkill_int(priv); + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) +--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h ++++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h +@@ -168,6 +168,12 @@ static inline void iwl_disable_interrupt + IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); + } + ++static inline void iwl_enable_rfkill_int(struct iwl_priv *priv) ++{ ++ IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); ++ iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); ++} ++ + static inline void iwl_enable_interrupts(struct iwl_priv *priv) + { + IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); diff --git a/queue-2.6.36/iwlagn-re-enable-rf_kill-interrupt-when-down.patch b/queue-2.6.36/iwlagn-re-enable-rf_kill-interrupt-when-down.patch new file mode 100644 index 00000000000..98b66862af5 --- /dev/null +++ b/queue-2.6.36/iwlagn-re-enable-rf_kill-interrupt-when-down.patch @@ -0,0 +1,45 @@ +From 3dd823e6b86407aed1a025041d8f1df77e43a9c8 Mon Sep 17 00:00:00 2001 +From: Don Fry +Date: Sun, 6 Feb 2011 09:29:45 -0800 +Subject: iwlagn: Re-enable RF_KILL interrupt when down + +From: Don Fry + +commit 3dd823e6b86407aed1a025041d8f1df77e43a9c8 upstream. + +With commit 554d1d027b19265c4aa3f718b3126d2b86e09a08 only one RF_KILL +interrupt will be seen by the driver when the interface is down. + +Re-enable the interrupt when it occurs to see all transitions. + +Signed-off-by: Don Fry +Signed-off-by: Wey-Yi Guy +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -1234,6 +1234,9 @@ static void iwl_irq_tasklet_legacy(struc + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_enable_interrupts(priv); ++ /* Re-enable RF_KILL if it occurred */ ++ else if (handled & CSR_INT_BIT_RF_KILL) ++ iwl_enable_rfkill_int(priv); + + #ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { +@@ -1449,6 +1452,9 @@ static void iwl_irq_tasklet(struct iwl_p + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_enable_interrupts(priv); ++ /* Re-enable RF_KILL if it occurred */ ++ else if (handled & CSR_INT_BIT_RF_KILL) ++ iwl_enable_rfkill_int(priv); + } + + /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ diff --git a/queue-2.6.36/mac80211-add-missing-synchronize_rcu.patch b/queue-2.6.36/mac80211-add-missing-synchronize_rcu.patch new file mode 100644 index 00000000000..340a2c3ccb6 --- /dev/null +++ b/queue-2.6.36/mac80211-add-missing-synchronize_rcu.patch @@ -0,0 +1,43 @@ +From d2460f4b2fa6dbdeec800414f9cf5b1fc8b71197 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Mon, 3 Jan 2011 19:42:24 +0100 +Subject: mac80211: add missing synchronize_rcu + +From: Johannes Berg + +commit d2460f4b2fa6dbdeec800414f9cf5b1fc8b71197 upstream. + +commit ad0e2b5a00dbec303e4682b403bb6703d11dcdb2 +Author: Johannes Berg +Date: Tue Jun 1 10:19:19 2010 +0200 + + mac80211: simplify key locking + +removed the synchronization against RCU and thus +opened a race window where we can use a key for +TX while it is already freed. Put a synchronisation +into the right place to close that window. + +Reported-by: Jussi Kivilinna +Signed-off-by: Johannes Berg +Signed-off-by: John W. Linville + +--- + net/mac80211/key.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/mac80211/key.c ++++ b/net/mac80211/key.c +@@ -323,6 +323,12 @@ static void __ieee80211_key_destroy(stru + if (!key) + return; + ++ /* ++ * Synchronize so the TX path can no longer be using ++ * this key before we free/remove it. ++ */ ++ synchronize_rcu(); ++ + if (key->local) + ieee80211_key_disable_hw_accel(key); + diff --git a/queue-2.6.36/mac80211-fix-a-crash-in-ieee80211_beacon_get_tim-on-change_interface.patch b/queue-2.6.36/mac80211-fix-a-crash-in-ieee80211_beacon_get_tim-on-change_interface.patch new file mode 100644 index 00000000000..a2338360007 --- /dev/null +++ b/queue-2.6.36/mac80211-fix-a-crash-in-ieee80211_beacon_get_tim-on-change_interface.patch @@ -0,0 +1,37 @@ +From eb3e554b4b3a56386ef5214dbe0e3935a350178b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 24 Jan 2011 19:28:49 +0100 +Subject: mac80211: fix a crash in ieee80211_beacon_get_tim on change_interface + +From: Felix Fietkau + +commit eb3e554b4b3a56386ef5214dbe0e3935a350178b upstream. + +Some drivers (e.g. ath9k) do not always disable beacons when they're +supposed to. When an interface is changed using the change_interface op, +the mode specific sdata part is in an undefined state and trying to +get a beacon at this point can produce weird crashes. + +To fix this, add a check for ieee80211_sdata_running before using +anything from the sdata. + +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/tx.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2175,6 +2175,9 @@ struct sk_buff *ieee80211_beacon_get_tim + + sdata = vif_to_sdata(vif); + ++ if (!ieee80211_sdata_running(sdata)) ++ goto out; ++ + if (tim_offset) + *tim_offset = 0; + if (tim_length) diff --git a/queue-2.6.36/mac80211-fix-initialization-of-skb-cb-in-ieee80211_subif_start_xmit.patch b/queue-2.6.36/mac80211-fix-initialization-of-skb-cb-in-ieee80211_subif_start_xmit.patch new file mode 100644 index 00000000000..f0e181c6404 --- /dev/null +++ b/queue-2.6.36/mac80211-fix-initialization-of-skb-cb-in-ieee80211_subif_start_xmit.patch @@ -0,0 +1,41 @@ +From 489ee9195a7de9e6bc833d639ff6b553ffdad90e Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 18 Dec 2010 19:30:48 +0100 +Subject: mac80211: fix initialization of skb->cb in ieee80211_subif_start_xmit + +From: Felix Fietkau + +commit 489ee9195a7de9e6bc833d639ff6b553ffdad90e upstream. + +The change 'mac80211: Fix BUG in pskb_expand_head when transmitting shared skbs' +added a check for copying the skb if it's shared, however the tx info variable +still points at the cb of the old skb + +Signed-off-by: Felix Fietkau +Acked-by: Helmut Schaa +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/tx.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1694,7 +1694,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_tx_info *info; + int ret = NETDEV_TX_BUSY, head_need; + u16 ethertype, hdrlen, meshhdrlen = 0; + __le16 fc; +@@ -1984,6 +1984,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + ++ info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + + dev->trans_start = jiffies; diff --git a/queue-2.6.36/mac80211-fix-mesh-forwarding-when-ratelimited-too.patch b/queue-2.6.36/mac80211-fix-mesh-forwarding-when-ratelimited-too.patch new file mode 100644 index 00000000000..f1e13eed74a --- /dev/null +++ b/queue-2.6.36/mac80211-fix-mesh-forwarding-when-ratelimited-too.patch @@ -0,0 +1,43 @@ +From 919bbad580445801c22ef6ccbe624551fee652bd Mon Sep 17 00:00:00 2001 +From: Milton Miller +Date: Thu, 30 Dec 2010 02:01:03 -0600 +Subject: mac80211: fix mesh forwarding when ratelimited too + +From: Milton Miller + +commit 919bbad580445801c22ef6ccbe624551fee652bd upstream. + +Commit b51aff057c9d0ef6c529dc25fd9f775faf7b6c63 said: + + Under memory pressure, the mac80211 mesh code + may helpfully print a message that it failed + to clone a mesh frame and then will proceed + to crash trying to use it anyway. Fix that. + +Avoid the reference whenever the frame copy is unsuccessful +regardless of the debug message being suppressed or printed. + +Signed-off-by: Milton Miller +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + net/mac80211/rx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1712,11 +1712,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 + + fwd_skb = skb_copy(skb, GFP_ATOMIC); + +- if (!fwd_skb && net_ratelimit()) { ++ if (!fwd_skb && net_ratelimit()) + printk(KERN_DEBUG "%s: failed to clone mesh frame\n", + sdata->name); ++ if (!fwd_skb) + goto out; +- } + + fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; + memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); diff --git a/queue-2.6.36/mac80211-use-maximum-number-of-ampdu-frames-as-default-in-ba-rx.patch b/queue-2.6.36/mac80211-use-maximum-number-of-ampdu-frames-as-default-in-ba-rx.patch new file mode 100644 index 00000000000..b04f64e807a --- /dev/null +++ b/queue-2.6.36/mac80211-use-maximum-number-of-ampdu-frames-as-default-in-ba-rx.patch @@ -0,0 +1,52 @@ +From 82694f764dad783a123394e2220b92b9be721b43 Mon Sep 17 00:00:00 2001 +From: Luciano Coelho +Date: Wed, 12 Jan 2011 15:18:11 +0200 +Subject: mac80211: use maximum number of AMPDU frames as default in BA RX + +From: Luciano Coelho + +commit 82694f764dad783a123394e2220b92b9be721b43 upstream. + +When the buffer size is set to zero in the block ack parameter set +field, we should use the maximum supported number of subframes. The +existing code was bogus and was doing some unnecessary calculations +that lead to wrong values. + +Thanks Johannes for helping me figure this one out. + +Cc: Johannes Berg +Signed-off-by: Luciano Coelho +Reviewed-by: Johannes Berg +Signed-off-by: John W. Linville + +--- + net/mac80211/agg-rx.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -172,8 +172,6 @@ void ieee80211_process_addba_request(str + struct ieee80211_mgmt *mgmt, + size_t len) + { +- struct ieee80211_hw *hw = &local->hw; +- struct ieee80211_conf *conf = &hw->conf; + struct tid_ampdu_rx *tid_agg_rx; + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; + u8 dialog_token; +@@ -218,13 +216,8 @@ void ieee80211_process_addba_request(str + goto end_no_lock; + } + /* determine default buffer size */ +- if (buf_size == 0) { +- struct ieee80211_supported_band *sband; +- +- sband = local->hw.wiphy->bands[conf->channel->band]; +- buf_size = IEEE80211_MIN_AMPDU_BUF; +- buf_size = buf_size << sband->ht_cap.ampdu_factor; +- } ++ if (buf_size == 0) ++ buf_size = IEEE80211_MAX_AMPDU_BUF; + + + /* examine state machine */ diff --git a/queue-2.6.36/series b/queue-2.6.36/series index 837e47689ef..d897263bd80 100644 --- a/queue-2.6.36/series +++ b/queue-2.6.36/series @@ -41,3 +41,22 @@ staging-hv-enable-sending-garp-packet-after-live-migration.patch staging-rt3090-fix-rt3090-scan-ap-function.patch staging-rt2860-fix-previous-patch-error.patch staging-rt2860-fix-incorrect-netif_stop_queue-usage-warning.patch +mac80211-fix-mesh-forwarding-when-ratelimited-too.patch +mac80211-add-missing-synchronize_rcu.patch +mac80211-use-maximum-number-of-ampdu-frames-as-default-in-ba-rx.patch +mac80211-fix-a-crash-in-ieee80211_beacon_get_tim-on-change_interface.patch +mac80211-fix-initialization-of-skb-cb-in-ieee80211_subif_start_xmit.patch +iwlagn-enable-only-rfkill-interrupt-when-device-is-down.patch +iwlagn-re-enable-rf_kill-interrupt-when-down.patch +ath9k_htc-handle-pending-urbs-properly.patch +ath9k_hw-fix-xpabias-level-configuration-for-ar9003.patch +ath9k-simplify-hw-reset-locking.patch +ath9k-move-the-pcu-lock-to-the-sc-structure.patch +ath9k-fix-bug-in-delimiter-padding-computation.patch +ath9k-fix-assumptions-for-idle-calls-on-suspend-resume.patch +ath9k-fix-aphy-wiphy-idle-mismatch.patch +ath9k-fix-beacon-restart-on-channel-change.patch +ath9k_hw-do-pa-offset-calibration-only-on-longcal-interval.patch +ath9k_hw-disabled-paprd-for-ar9003.patch +ath9k_hw-fix-system-hang-when-resuming-from-s3-s4.patch +ath9k-fix-race-conditions-when-stop-device.patch