--- /dev/null
+From afe68d0a8f5961652e26cea39d74e2cc820de841 Mon Sep 17 00:00:00 2001
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+Date: Mon, 20 Dec 2010 11:29:59 -0500
+Subject: ath9k: fix aphy / wiphy idle mismatch
+
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+
+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 <pstew@google.com>
+Cc: Amod Bodas <amod.bodas@atheros.com>
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From a08e7ade9ddf4fe79576f953cc5c1725e944d26c Mon Sep 17 00:00:00 2001
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+Date: Tue, 7 Dec 2010 15:13:20 -0800
+Subject: ath9k: fix assumptions for idle calls on suspend/resume
+
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+
+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 <pstew@google.com>
+Cc: Amod Bodas <amod.bodas@atheros.com>
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
+ }
+
--- /dev/null
+From 1186488b4a4d4871e40cb1604ba3ede3d4b7cc90 Mon Sep 17 00:00:00 2001
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+Date: Thu, 30 Dec 2010 19:07:44 +0530
+Subject: ath9k: fix beacon restart on channel change
+
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+
+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 <rmanoharan@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
+ }
--- /dev/null
+From 39ec2997c374b528cdbf65099b6d6b8593a67f7f Mon Sep 17 00:00:00 2001
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Date: Wed, 10 Nov 2010 05:03:15 -0800
+Subject: ath9k: Fix bug in delimiter padding computation
+
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+
+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 <nbd@openwrt.org>
+Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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))
--- /dev/null
+From 203043f579ece44bb30291442cd56332651dd37d Mon Sep 17 00:00:00 2001
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+Date: Tue, 25 Jan 2011 14:08:40 +0100
+Subject: ath9k: fix race conditions when stop device
+
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+
+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 <sgruszka@redhat.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
+
--- /dev/null
+From 4bdd1e978ede034c1211957eb17eaf50de00d234 Mon Sep 17 00:00:00 2001
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+Date: Tue, 26 Oct 2010 15:27:24 -0700
+Subject: ath9k: move the PCU lock to the sc structure
+
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+
+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 <greearb@candelatech.com>
+Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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++) {
--- /dev/null
+From 9d94674ab754be0e275120a183670ead435f9c0d Mon Sep 17 00:00:00 2001
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+Date: Tue, 26 Oct 2010 15:27:23 -0700
+Subject: ath9k: simplify hw reset locking
+
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+
+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 <greearb@candelatech.com>
+Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+---
+ 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++) {
--- /dev/null
+From ff8f59b5bbdf1527235b8c88d859c7d23691324f Mon Sep 17 00:00:00 2001
+From: Sujith Manoharan <Sujith.Manoharan@atheros.com>
+Date: Tue, 28 Dec 2010 14:28:05 +0530
+Subject: ath9k_htc: Handle pending URBs properly
+
+From: Sujith Manoharan <Sujith.Manoharan@atheros.com>
+
+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 <Sujith.Manoharan@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 6f4810101a629b31b5427872a09ea092cfc5c4bd Mon Sep 17 00:00:00 2001
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+Date: Thu, 20 Jan 2011 17:47:39 -0800
+Subject: ath9k_hw: disabled PAPRD for AR9003
+
+From: Luis R. Rodriguez <lrodriguez@atheros.com>
+
+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 <paul.shaw@atheros.com>
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 811ea256b30b37091b5bbf41517404cf98ab56c1 Mon Sep 17 00:00:00 2001
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+Date: Mon, 17 Jan 2011 15:21:40 +0530
+Subject: ath9k_hw: do PA offset calibration only on longcal interval
+
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+
+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 <vasanth@atheros.com>
+Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 5b64aa72ead6f8be488d2be7af579f0d69fb7a6e Mon Sep 17 00:00:00 2001
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+Date: Thu, 27 Jan 2011 18:39:37 +0530
+Subject: ath9k_hw: Fix system hang when resuming from S3/S4
+
+From: Rajkumar Manoharan <rmanoharan@atheros.com>
+
+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 <jlee@atheros.com>
+Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 52a0e2477dac2106bc1688cbe9615cdafc9deb7d Mon Sep 17 00:00:00 2001
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Date: Wed, 10 Nov 2010 05:03:11 -0800
+Subject: ath9k_hw: Fix XPABIAS level configuration for AR9003
+
+From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+
+commit 52a0e2477dac2106bc1688cbe9615cdafc9deb7d upstream.
+
+Improper configuration of 0x16288 and 0x16290 would affect transmission.
+
+Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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)
--- /dev/null
+From 554d1d027b19265c4aa3f718b3126d2b86e09a08 Mon Sep 17 00:00:00 2001
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+Date: Thu, 23 Dec 2010 12:38:21 +0100
+Subject: iwlagn: enable only rfkill interrupt when device is down
+
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+
+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 <sgruszka@redhat.com>
+Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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");
--- /dev/null
+From 3dd823e6b86407aed1a025041d8f1df77e43a9c8 Mon Sep 17 00:00:00 2001
+From: Don Fry <donald.h.fry@intel.com>
+Date: Sun, 6 Feb 2011 09:29:45 -0800
+Subject: iwlagn: Re-enable RF_KILL interrupt when down
+
+From: Don Fry <donald.h.fry@intel.com>
+
+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 <donald.h.fry@intel.com>
+Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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 */
--- /dev/null
+From d2460f4b2fa6dbdeec800414f9cf5b1fc8b71197 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 3 Jan 2011 19:42:24 +0100
+Subject: mac80211: add missing synchronize_rcu
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit d2460f4b2fa6dbdeec800414f9cf5b1fc8b71197 upstream.
+
+commit ad0e2b5a00dbec303e4682b403bb6703d11dcdb2
+Author: Johannes Berg <johannes.berg@intel.com>
+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 <jussi.kivilinna@mbnet.fi>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+---
+ 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);
+
--- /dev/null
+From eb3e554b4b3a56386ef5214dbe0e3935a350178b Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+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 <nbd@openwrt.org>
+
+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 <nbd@openwrt.org>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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)
--- /dev/null
+From 489ee9195a7de9e6bc833d639ff6b553ffdad90e Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 18 Dec 2010 19:30:48 +0100
+Subject: mac80211: fix initialization of skb->cb in ieee80211_subif_start_xmit
+
+From: Felix Fietkau <nbd@openwrt.org>
+
+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 <nbd@openwrt.org>
+Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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;
--- /dev/null
+From 919bbad580445801c22ef6ccbe624551fee652bd Mon Sep 17 00:00:00 2001
+From: Milton Miller <miltonm@bga.com>
+Date: Thu, 30 Dec 2010 02:01:03 -0600
+Subject: mac80211: fix mesh forwarding when ratelimited too
+
+From: Milton Miller <miltonm@bga.com>
+
+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 <miltonm@bga.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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);
--- /dev/null
+From 82694f764dad783a123394e2220b92b9be721b43 Mon Sep 17 00:00:00 2001
+From: Luciano Coelho <coelho@ti.com>
+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 <coelho@ti.com>
+
+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 <johannes@sipsolutions.net>
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+---
+ 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 */
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