odhcpd: fix regression in dhcpv6 t1 and t2 calculation
[openwrt/staging/rmilecki.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index df492bb81277fd4a3a6e7b3fd8690a4b7fb2dc1b..63229520982831f801125f4877197c6ef7bc5618 100644 (file)
-commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798
-Author: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
-Date:   Tue May 27 16:58:02 2014 +0530
+commit 6fb7eefaa4d8377e6b124435059656dd6f643e91
+Author: Karl Beldan <karl.beldan@rivierawaves.com>
+Date:   Tue Oct 7 15:53:38 2014 +0200
 
-    ath9k: Fix deadlock while updating p2p beacon timer
+    mac80211/trivial: fix typo in starting baserate for rts_cts_rate_idx
     
-    pm_lock is taken twice while syncing HW TSF of p2p vif.
-    Fix this by taking the lock at caller side.
+    Fixes: 5253ffb8 ("mac80211: always pick a basic rate to tx RTS/CTS for pre-HT rates")
+    Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
+
+commit b18111d911980af52bead74ee45250cc96ad5108
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Tue Oct 7 10:14:37 2014 +0530
+
+    ath9k: Fix crash in MCC mode
+    
+    When a channel context is removed, the hw_queue_base
+    is set to -1, this will result in a panic because
+    ath9k_chanctx_stop_queues() can be called on an interface
+    that is not assigned to any context yet - for example,
+    when trying to scan.
     
-    Cc: Felix Fietkau <nbd@openwrt.org>
-    Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
+    Fix this issue by setting the hw_queue_base to zero
+    when a channel context is removed.
+    
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
     Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Thu Jun 5 13:52:27 2014 +0200
+commit e2cba8d7590e76661e86f1f0987ef9f8c13c9a6d
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:20 2014 +0530
 
-    rt2x00: do not initialize BCN_OFFSET registers
+    ath9k: Fix flushing in MCC mode
+    
+    When we are attempting to switch to a new
+    channel context, the TX queues are flushed, but
+    the mac80211 queues are not stopped and traffic
+    can still come down to the driver.
     
-    We setup BCN_OFFSET{0,1} registers dynamically, don't have to
-    initialize them.
+    This patch fixes it by stopping the queues
+    assigned to the current context/vif before
+    trying to flush.
     
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit e5c58ca7a48d4c82f282749a978052c47fd95998
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Thu Jun 5 13:52:26 2014 +0200
+commit 5ba8d9d2f018f2c4e23f9e68b90ca5b9d5470457
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:19 2014 +0530
 
-    rt2x00: change order when stop beaconing
+    ath9k: Fix queue handling for channel contexts
+    
+    When a full chip reset is done, all the queues
+    across all VIFs are stopped, but if MCC is enabled,
+    only the queues of the current context is awakened,
+    when we complete the reset.
+    
+    This results in unfairness for the inactive context.
+    Since frames are queued internally in the driver if
+    there is a context mismatch, we can awaken all the
+    queues when coming out of a reset.
     
-    When no beaconing is needed, first stop beacon queue (disable beaconing
-    globally) to avoid possible sending of not prepared beacon on short
-    period after clearing beacon and before stop of BCN queue.
+    The VIF-specific queues are still used in flow control,
+    to ensure fairness when traffic is high.
     
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Thu Jun 5 13:52:25 2014 +0200
+commit a064eaa10ca4ec58d5a405c9a7f87efc6d2fa423
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:18 2014 +0530
 
-    rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM
+    ath9k: Add ath9k_chanctx_stop_queues()
     
-    We setup MAC_BSSID_DW1_BSS_BCN_NUM dynamically when numbers of active
-    beacons increase. Change default to 0 to tell hardware that we want to
-    send only one beacon as default.
+    This can be used when the queues of a context
+    needs to be stopped.
     
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Thu Jun 5 13:52:24 2014 +0200
+commit b39031536aab9cb1324328cf46fa4ef940bd975f
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:17 2014 +0530
 
-    rt2x00: change beaconing setup on RT2800
+    ath9k: Pass context to ath9k_chanctx_wake_queues()
     
-    As reported by Matthias, on 5572 chip, even if we clear up TXWI
-    of corresponding beacon, hardware still try to send it or do other
-    action that increase power consumption peak up to 1A.
+    Change the ath9k_chanctx_wake_queues() API so
+    that we can pass the channel context that needs its
+    queues to be stopped.
     
-    To avoid the issue, setup beaconing dynamically by configuring offsets
-    of currently active beacons and MAC_BSSID_DW1_BSS_BCN_NUM variable,
-    which limit number of beacons that hardware will try to send.
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit 4f82eecf73019c27537f65c160e90385e159afd8
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:16 2014 +0530
+
+    ath9k: Fix queue handling in flush()
     
-    Reported-by: Matthias Fend <Matthias.Fend@wolfvision.net>
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    When draining of the TX queues fails, a
+    full HW reset is done. ath_reset() makes sure
+    that the queues in mac80211 are restarted,
+    so there is no need to wake them up again.
+    
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit 916e591b2cc41f7e572992175ca56d866d7bc958
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Thu Jun 5 13:52:23 2014 +0200
+commit 60913f4d2951f6410eed969aae4717c7ced37044
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:15 2014 +0530
 
-    rt2x00: change beaconing locking
+    ath9k: Remove duplicate code
     
-    This patch is needed for further changes to keep global variables
-    consistent when changing beaconing on diffrent vif's.
+    ath9k_has_tx_pending() can be used to
+    check if there are pending frames instead
+    of having duplicate code.
     
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit 930b0dffd1731f3f418f9132faea720a23b7af61
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Tue Jun 3 11:18:47 2014 +0200
+commit fc1314c75e0558c03cb434e2af2c257caa201e76
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:14 2014 +0530
 
-    mac80211: fix station/driver powersave race
+    ath9k: Fix pending frame check
     
-    It is currently possible to have a race due to the station PS
-    unblock work like this:
-     * station goes to sleep with frames buffered in the driver
-     * driver blocks wakeup
-     * station wakes up again
-     * driver flushes/returns frames, and unblocks, which schedules
-       the unblock work
-     * unblock work starts to run, and checks that the station is
-       awake (i.e. that the WLAN_STA_PS_STA flag isn't set)
-     * we process a received frame with PM=1, setting the flag again
-     * ieee80211_sta_ps_deliver_wakeup() runs, delivering all frames
-       to the driver, and then clearing the WLAN_STA_PS_DRIVER and
-       WLAN_STA_PS_STA flags
+    Checking for the queue depth outside of
+    the TX queue lock is incorrect and in this
+    case, is not required since it is done inside
+    ath9k_has_pending_frames().
     
-    In this scenario, mac80211 will think that the station is awake,
-    while it really is asleep, and any TX'ed frames should be filtered
-    by the device (it will know that the station is sleeping) but then
-    passed to mac80211 again, which will not buffer it either as it
-    thinks the station is awake, and eventually the packets will be
-    dropped.
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit b736728575af03488388e84fceac7bf0eac5dbb6
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:13 2014 +0530
+
+    ath9k: Check pending frames properly
     
-    Fix this by moving the clearing of the flags to exactly where we
-    learn about the situation. This creates a problem of reordering,
-    so introduce another flag indicating that delivery is being done,
-    this new flag also queues frames and is cleared only while the
-    spinlock is held (which the queuing code also holds) so that any
-    concurrent delivery/TX is handled correctly.
+    There is no need to check if the current
+    channel context has active ACs queued up
+    if the TX queue is not empty.
     
-    Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit 4b60af4ab4363bd79eeba94bb6bed396cf2aaf62
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Thu Oct 2 06:33:12 2014 +0530
+
+    ath9k: Print RoC expiration
+    
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit 4d9f634b02e4240f86719f30e4c9e62f6a4c4d36
+Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date:   Tue Sep 30 14:15:23 2014 +0530
+
+    ath9k: Check early for HW reset
+    
+    chan_lock is not required for checking if
+    we are in the middle of a HW reset, so do it
+    early. This also removes the small window
+    where the lock is dropped and reacquired.
+    
+    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit c393d179924685d5c8c72446c5b6401f25fdb2a0
+Author: Marek Puzyniak <marek.puzyniak@tieto.com>
+Date:   Tue Oct 7 17:04:30 2014 +0200
 
-commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
+    ath9k_htc: avoid kernel panic in ath9k_hw_reset
+    
+    hw pointer of ath_hw is not assigned to proper value
+    in function ath9k_hw_reset what finally causes kernel panic.
+    This can be solved by proper initialization of ath_hw in
+    ath9k_init_priv.
+    
+    Signed-off-by: Marek Puzyniak <marek.puzyniak@tieto.com>
+    Acked-by: Oleksij Rempel <linux@rempel-privat.de>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
+
+commit 065e0b64f71632f5ad7f00c102fde09c534cfbf0
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri May 23 19:58:14 2014 +0200
+Date:   Tue Sep 30 11:00:33 2014 +0200
 
-    mac80211: reduce packet loss notifications under load
+    ath9k: fix getting tx duration for dynack
     
-    During strong signal fluctuations under high throughput, few consecutive
-    failed A-MPDU transmissions can easily trigger packet loss notification,
-    and thus (in AP mode) client disconnection.
+    On AR9003, tx control and tx status are in separate descriptor rings.
+    Tx duration is extracted from the tx control descriptor data, which
+    ar9003_hw_proc_txdesc cannot access.
     
-    Reduce the number of false positives by checking the A-MPDU status flag
-    and treating a failed A-MPDU as a single packet.
+    Fix getting the duration by adding a separate callback for it.
     
+    Acked-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 7b7843a36fbcc568834404c7430ff895d8502131
+commit fdf9a4517b60d847b9bc0a30249efd96559fa450
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri May 23 19:26:32 2014 +0200
+Date:   Tue Sep 9 09:48:30 2014 +0200
 
-    mac80211: fix a memory leak on sta rate selection table
+    ath9k_hw: fix PLL clock initialization for newer SoC
+    
+    On AR934x and newer SoC devices, the layout of the AR_RTC_PLL_CONTROL
+    register changed. This currently breaks at least 5/10 MHz operation.
+    AR933x uses the old layout.
+    
+    It might also have been causing other stability issues because of the
+    different location of the PLL_BYPASS bit which needs to be set during
+    PLL clock initialization.
+    
+    This patch also removes more instances of hardcoded register values in
+    favor of properly computed ones with the PLL_BYPASS bit added.
+    
+    Reported-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit b6d1f51cd8bdc9d952147a960fbf1f261d8e4188
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon Sep 8 18:35:08 2014 +0200
+
+    ath9k_hw: reduce ANI spur immunity setting on HT40 extension channel
+    
+    The cycpwr_thr1 value needs to be lower on the extension channel than on
+    the control channel, similar to how the register settings are programmed
+    in the initvals.
+    
+    Also drop the unnecessary check for HT40 - this register can always be
+    written. This patch has been reported to improve HT40 stability and
+    throughput in some environments.
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 5ad2dfbaa19aa45d29184d30c8c5dae0e110074a
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon Sep 8 18:31:26 2014 +0200
+
+    Revert "ath9k_hw: reduce ANI firstep range for older chips"
+    
+    This reverts commit 09efc56345be4146ab9fc87a55c837ed5d6ea1ab
+    
+    I've received reports that this change is decreasing throughput in some
+    rare conditions on an AR9280 based device
     
     Cc: stable@vger.kernel.org
-    Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 96892d6aa0a153423070addf3070bc79578b3897
+commit 4c82fc569cf2f29e6c66d98ef4a1b0f3b6a98e9d
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon May 19 21:20:49 2014 +0200
+Date:   Sat Sep 27 22:39:27 2014 +0200
 
-    ath9k: avoid passing buffers to the hardware during flush
+    ath9k_hw: disable hardware ad-hoc flag on ar934x rev 3
     
-    The commit "ath9k: fix possible hang on flush" changed the receive code
-    to always link rx descriptors of processed frames, even when flushing.
-    In some cases, this leads to flushed rx buffers being passed to the
-    hardware while rx is already stopped.
+    On AR934x rev 3, settin the ad-hoc flag completely messes up hardware
+    state - beacons get stuck, almost no packets make it out, hardware is
+    constantly reset.
+    
+    When leaving out that flag and setting up the hw like in AP mode, TSF
+    timers won't be automatically synced, but at least the rest works.
+    
+    AR934x rev 2 and older are not affected by this bug
     
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
-  * buffer (or rx fifo). This can incorrectly acknowledge packets
-  * to a sender if last desc is self-linked.
-  */
--static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
-+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
-+                          bool flush)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
-                            common->rx_bufsize,
-                            0);
+commit ecfb4b3fff006372ac5c40871f9bb182fd00444f
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 22:15:43 2014 +0200
+
+    ath9k: use ah->get_mac_revision for all SoC devices if available
+    
+    It is needed for AR934x as well
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit c11113bc25df22898fb995d3205bdc4f27c98073
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 18:04:58 2014 +0200
+
+    ath5k: add missing include for debug code
+    
+    Needed for calling vmalloc()/vfree()
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 83f76a9f9a42773c7eef90bb86b4b2c16b0b3755
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 15:58:51 2014 +0200
+
+    ath5k: fix AHB kconfig dependency
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit ddd67f2a5cfd73fad4b78190025402d419b9f0a9
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 15:57:09 2014 +0200
+
+    Revert "ath5k: Remove AHB bus support"
+    
+    This reverts commit 093ec3c5337434f40d77c1af06c139da3e5ba6dc.
+
+--- a/drivers/net/wireless/ath/ath5k/Kconfig
++++ b/drivers/net/wireless/ath/ath5k/Kconfig
+@@ -2,12 +2,14 @@ config ATH5K
+       tristate "Atheros 5xxx wireless cards support"
+       depends on m
+       depends on PCI && MAC80211
++      depends on (PCI || ATHEROS_AR231X) && MAC80211
+       select ATH_COMMON
+       select MAC80211_LEDS
+       select BACKPORT_LEDS_CLASS
+       select BACKPORT_NEW_LEDS
+       select BACKPORT_AVERAGE
+-      select ATH5K_PCI
++      select ATH5K_AHB if ATHEROS_AR231X
++      select ATH5K_PCI if !ATHEROS_AR231X
+       ---help---
+         This module adds support for wireless adapters based on
+         Atheros 5xxx chipset.
+@@ -52,9 +54,16 @@ config ATH5K_TRACER
  
--      if (sc->rx.rxlink == NULL)
--              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
--      else
-+      if (sc->rx.rxlink)
-               *sc->rx.rxlink = bf->bf_daddr;
-+      else if (!flush)
-+              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+         If unsure, say N.
++config ATH5K_AHB
++      bool "Atheros 5xxx AHB bus support"
++      depends on ATHEROS_AR231X
++      ---help---
++        This adds support for WiSoC type chipsets of the 5xxx Atheros
++        family.
++
+ config ATH5K_PCI
+       bool "Atheros 5xxx PCI bus support"
+-      depends on PCI
++      depends on !ATHEROS_AR231X
+       ---help---
+         This adds support for PCI type chipsets of the 5xxx Atheros
+         family.
+--- /dev/null
++++ b/drivers/net/wireless/ath/ath5k/ahb.c
+@@ -0,0 +1,234 @@
++/*
++ * Copyright (c) 2008-2009 Atheros Communications Inc.
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/nl80211.h>
++#include <linux/platform_device.h>
++#include <linux/etherdevice.h>
++#include <linux/export.h>
++#include <ar231x_platform.h>
++#include "ath5k.h"
++#include "debug.h"
++#include "base.h"
++#include "reg.h"
++
++/* return bus cachesize in 4B word units */
++static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
++{
++      *csz = L1_CACHE_BYTES >> 2;
++}
++
++static bool
++ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
++{
++      struct ath5k_hw *ah = common->priv;
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      u16 *eeprom, *eeprom_end;
++
++      eeprom = (u16 *) bcfg->radio;
++      eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
++
++      eeprom += off;
++      if (eeprom > eeprom_end)
++              return false;
++
++      *data = *eeprom;
++      return true;
++}
++
++int ath5k_hw_read_srev(struct ath5k_hw *ah)
++{
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      ah->ah_mac_srev = bcfg->devid;
++      return 0;
++}
++
++static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
++{
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      u8 *cfg_mac;
++
++      if (to_platform_device(ah->dev)->id == 0)
++              cfg_mac = bcfg->config->wlan0_mac;
++      else
++              cfg_mac = bcfg->config->wlan1_mac;
++
++      memcpy(mac, cfg_mac, ETH_ALEN);
++      return 0;
++}
++
++static const struct ath_bus_ops ath_ahb_bus_ops = {
++      .ath_bus_type = ATH_AHB,
++      .read_cachesize = ath5k_ahb_read_cachesize,
++      .eeprom_read = ath5k_ahb_eeprom_read,
++      .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
++};
++
++/*Initialization*/
++static int ath_ahb_probe(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      struct ath5k_hw *ah;
++      struct ieee80211_hw *hw;
++      struct resource *res;
++      void __iomem *mem;
++      int irq;
++      int ret = 0;
++      u32 reg;
++
++      if (!dev_get_platdata(&pdev->dev)) {
++              dev_err(&pdev->dev, "no platform data specified\n");
++              ret = -EINVAL;
++              goto err_out;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "no memory resource found\n");
++              ret = -ENXIO;
++              goto err_out;
++      }
++
++      mem = ioremap_nocache(res->start, resource_size(res));
++      if (mem == NULL) {
++              dev_err(&pdev->dev, "ioremap failed\n");
++              ret = -ENOMEM;
++              goto err_out;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "no IRQ resource found\n");
++              ret = -ENXIO;
++              goto err_iounmap;
++      }
++
++      irq = res->start;
++
++      hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
++      if (hw == NULL) {
++              dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
++              ret = -ENOMEM;
++              goto err_iounmap;
++      }
++
++      ah = hw->priv;
++      ah->hw = hw;
++      ah->dev = &pdev->dev;
++      ah->iobase = mem;
++      ah->irq = irq;
++      ah->devid = bcfg->devid;
++
++      if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
++              /* Enable WMAC AHB arbitration */
++              reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++              reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++
++              /* Enable global WMAC swapping */
++              reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
++              reg |= AR5K_AR2315_BYTESWAP_WMAC;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
++      } else {
++              /* Enable WMAC DMA access (assuming 5312 or 231x*/
++              /* TODO: check other platforms */
++              reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
++              if (to_platform_device(ah->dev)->id == 0)
++                      reg |= AR5K_AR5312_ENABLE_WLAN0;
++              else
++                      reg |= AR5K_AR5312_ENABLE_WLAN1;
++              iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
++
++              /*
++               * On a dual-band AR5312, the multiband radio is only
++               * used as pass-through. Disable 2 GHz support in the
++               * driver for it
++               */
++              if (to_platform_device(ah->dev)->id == 0 &&
++                  (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
++                   (BD_WLAN1 | BD_WLAN0))
++                      ah->ah_capabilities.cap_needs_2GHz_ovr = true;
++              else
++                      ah->ah_capabilities.cap_needs_2GHz_ovr = false;
++      }
++
++      ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
++      if (ret != 0) {
++              dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
++              ret = -ENODEV;
++              goto err_free_hw;
++      }
++
++      platform_set_drvdata(pdev, hw);
++
++      return 0;
++
++ err_free_hw:
++      ieee80211_free_hw(hw);
++ err_iounmap:
++        iounmap(mem);
++ err_out:
++      return ret;
++}
++
++static int ath_ahb_remove(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      struct ieee80211_hw *hw = platform_get_drvdata(pdev);
++      struct ath5k_hw *ah;
++      u32 reg;
++
++      if (!hw)
++              return 0;
++
++      ah = hw->priv;
++
++      if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
++              /* Disable WMAC AHB arbitration */
++              reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++              reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++      } else {
++              /*Stop DMA access */
++              reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
++              if (to_platform_device(ah->dev)->id == 0)
++                      reg &= ~AR5K_AR5312_ENABLE_WLAN0;
++              else
++                      reg &= ~AR5K_AR5312_ENABLE_WLAN1;
++              iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
++      }
++
++      ath5k_deinit_ah(ah);
++      iounmap(ah->iobase);
++      ieee80211_free_hw(hw);
++
++      return 0;
++}
++
++static struct platform_driver ath_ahb_driver = {
++      .probe      = ath_ahb_probe,
++      .remove     = ath_ahb_remove,
++      .driver         = {
++              .name   = "ar231x-wmac",
++              .owner  = THIS_MODULE,
++      },
++};
++
++module_platform_driver(ath_ahb_driver);
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1647,6 +1647,32 @@ static inline struct ath_regulatory *ath
+       return &(ath5k_hw_common(ah)->regulatory);
+ }
  
-       sc->rx.rxlink = &ds->ds_link;
++#ifdef CONFIG_ATHEROS_AR231X
++#define AR5K_AR2315_PCI_BASE  ((void __iomem *)0xb0100000)
++
++static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
++{
++      /* On AR2315 and AR2317 the PCI clock domain registers
++       * are outside of the WMAC register space */
++      if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
++          (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
++              return AR5K_AR2315_PCI_BASE + reg;
++
++      return ah->iobase + reg;
++}
++
++static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
++{
++      return ioread32(ath5k_ahb_reg(ah, reg));
++}
++
++static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
++{
++      iowrite32(val, ath5k_ahb_reg(ah, reg));
++}
++
++#else
++
+ static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+ {
+       return ioread32(ah->iobase + reg);
+@@ -1657,6 +1683,8 @@ static inline void ath5k_hw_reg_write(st
+       iowrite32(val, ah->iobase + reg);
  }
  
--static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
-+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
-+                            bool flush)
++#endif
++
+ static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
  {
-       if (sc->rx.buf_hold)
--              ath_rx_buf_link(sc, sc->rx.buf_hold);
-+              ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
+       return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -99,6 +99,15 @@ static int ath5k_reset(struct ath5k_hw *
  
-       sc->rx.buf_hold = bf;
- }
-@@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
-       sc->rx.buf_hold = NULL;
-       sc->rx.rxlink = NULL;
-       list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
--              ath_rx_buf_link(sc, bf);
-+              ath_rx_buf_link(sc, bf, false);
-       }
+ /* Known SREVs */
+ static const struct ath5k_srev_name srev_names[] = {
++#ifdef CONFIG_ATHEROS_AR231X
++      { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R2 },
++      { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R7 },
++      { "2313",       AR5K_VERSION_MAC,       AR5K_SREV_AR2313_R8 },
++      { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R6 },
++      { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R7 },
++      { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R1 },
++      { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R2 },
++#else
+       { "5210",       AR5K_VERSION_MAC,       AR5K_SREV_AR5210 },
+       { "5311",       AR5K_VERSION_MAC,       AR5K_SREV_AR5311 },
+       { "5311A",      AR5K_VERSION_MAC,       AR5K_SREV_AR5311A },
+@@ -117,6 +126,7 @@ static const struct ath5k_srev_name srev
+       { "5418",       AR5K_VERSION_MAC,       AR5K_SREV_AR5418 },
+       { "2425",       AR5K_VERSION_MAC,       AR5K_SREV_AR2425 },
+       { "2417",       AR5K_VERSION_MAC,       AR5K_SREV_AR2417 },
++#endif
+       { "xxxxx",      AR5K_VERSION_MAC,       AR5K_SREV_UNKNOWN },
+       { "5110",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5110 },
+       { "5111",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5111 },
+@@ -132,6 +142,10 @@ static const struct ath5k_srev_name srev
+       { "5413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5413 },
+       { "5424",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5424 },
+       { "5133",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5133 },
++#ifdef CONFIG_ATHEROS_AR231X
++      { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
++      { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
++#endif
+       { "xxxxx",      AR5K_VERSION_RAD,       AR5K_SREV_UNKNOWN },
+ };
  
-       /* We could have deleted elements so the list may be empty now */
-@@ -1118,12 +1120,12 @@ requeue_drop_frag:
- requeue:
-               list_add_tail(&bf->list, &sc->rx.rxbuf);
+--- a/drivers/net/wireless/ath/ath5k/led.c
++++ b/drivers/net/wireless/ath/ath5k/led.c
+@@ -163,14 +163,20 @@ int ath5k_init_leds(struct ath5k_hw *ah)
+ {
+       int ret = 0;
+       struct ieee80211_hw *hw = ah->hw;
++#ifndef CONFIG_ATHEROS_AR231X
+       struct pci_dev *pdev = ah->pdev;
++#endif
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];
+       const struct pci_device_id *match;
  
--              if (edma) {
--                      ath_rx_edma_buf_link(sc, qtype);
--              } else {
--                      ath_rx_buf_relink(sc, bf);
-+              if (!edma) {
-+                      ath_rx_buf_relink(sc, bf, flush);
-                       if (!flush)
-                               ath9k_hw_rxena(ah);
-+              } else if (!flush) {
-+                      ath_rx_edma_buf_link(sc, qtype);
-               }
+       if (!ah->pdev)
+               return 0;
++#ifdef CONFIG_ATHEROS_AR231X
++      match = NULL;
++#else
+       match = pci_match_id(&ath5k_led_devices[0], pdev);
++#endif
+       if (match) {
+               __set_bit(ATH_STAT_LEDSOFT, ah->status);
+               ah->led_pin = ATH_PIN(match->driver_data);
+--- a/drivers/net/wireless/ath/ath5k/debug.c
++++ b/drivers/net/wireless/ath/ath5k/debug.c
+@@ -65,6 +65,7 @@
  
-               if (!budget--)
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct 
-       struct ps_data *ps;
-       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
--          test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-+          test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
-+          test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
-               if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       ps = &sdata->bss->ps;
-@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct 
-               clear_sta_flag(sta, WLAN_STA_PS_STA);
-               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+              clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
-               atomic_dec(&ps->num_sta_ps);
-               sta_info_recalc_tim(sta);
-@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct 
-       if (ieee80211_vif_is_mesh(&sdata->vif))
-               mesh_sta_cleanup(sta);
--      cancel_work_sync(&sta->drv_unblock_wk);
-+      cancel_work_sync(&sta->drv_deliver_wk);
-       /*
-        * Destroy aggregation state here. It would be nice to wait for the
-@@ -227,6 +229,7 @@ struct sta_info *sta_info_get_by_idx(str
-  */
- void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
+ #include <linux/seq_file.h>
+ #include <linux/list.h>
++#include <linux/vmalloc.h>
+ #include "debug.h"
+ #include "ath5k.h"
+ #include "reg.h"
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -222,31 +222,28 @@ static void ath9k_hw_read_revisions(stru
  {
-+      struct ieee80211_sta_rates *rates;
-       int i;
+       u32 val;
  
-       if (sta->rate_ctrl)
-@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca
-               kfree(sta->tx_lat);
++      if (ah->get_mac_revision)
++              ah->hw_version.macRev = ah->get_mac_revision();
++
+       switch (ah->hw_version.devid) {
+       case AR5416_AR9100_DEVID:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9100;
+               break;
+       case AR9300_DEVID_AR9330:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9330;
+-              if (ah->get_mac_revision) {
+-                      ah->hw_version.macRev = ah->get_mac_revision();
+-              } else {
++              if (!ah->get_mac_revision) {
+                       val = REG_READ(ah, AR_SREV);
+                       ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+               }
+               return;
+       case AR9300_DEVID_AR9340:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9340;
+-              val = REG_READ(ah, AR_SREV);
+-              ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+               return;
+       case AR9300_DEVID_QCA955X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9550;
+               return;
+       case AR9300_DEVID_AR953X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9531;
+-              if (ah->get_mac_revision)
+-                      ah->hw_version.macRev = ah->get_mac_revision();
+               return;
        }
  
-+      rates = rcu_dereference_protected(sta->sta.rates, true);
-+      if (rates)
-+              kfree(rates);
+@@ -704,6 +701,8 @@ static void ath9k_hw_init_pll(struct ath
+ {
+       u32 pll;
++      pll = ath9k_hw_compute_pll_control(ah, chan);
 +
-       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
+       if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
+               /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
+               REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+@@ -754,7 +753,8 @@ static void ath9k_hw_init_pll(struct ath
+               REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
+                             AR_CH0_DPLL3_PHASE_SHIFT, 0x1);
  
-       kfree(sta);
-@@ -252,33 +259,23 @@ static void sta_info_hash_add(struct iee
-       rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
- }
+-              REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
++              REG_WRITE(ah, AR_RTC_PLL_CONTROL,
++                        pll | AR_RTC_9300_PLL_BYPASS);
+               udelay(1000);
  
--static void sta_unblock(struct work_struct *wk)
-+static void sta_deliver_ps_frames(struct work_struct *wk)
- {
-       struct sta_info *sta;
+               /* program refdiv, nint, frac to RTC register */
+@@ -770,7 +770,8 @@ static void ath9k_hw_init_pll(struct ath
      } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+               u32 regval, pll2_divint, pll2_divfrac, refdiv;
  
--      sta = container_of(wk, struct sta_info, drv_unblock_wk);
-+      sta = container_of(wk, struct sta_info, drv_deliver_wk);
+-              REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
++              REG_WRITE(ah, AR_RTC_PLL_CONTROL,
++                        pll | AR_RTC_9300_SOC_PLL_BYPASS);
+               udelay(1000);
  
-       if (sta->dead)
-               return;
+               REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
+@@ -843,7 +844,6 @@ static void ath9k_hw_init_pll(struct ath
+               udelay(1000);
+       }
  
--      if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
--              local_bh_disable();
-+      local_bh_disable();
-+      if (!test_sta_flag(sta, WLAN_STA_PS_STA))
-               ieee80211_sta_ps_deliver_wakeup(sta);
--              local_bh_enable();
--      } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
--              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
--
--              local_bh_disable();
-+      else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL))
-               ieee80211_sta_ps_deliver_poll_response(sta);
--              local_bh_enable();
--      } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
--              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
--
--              local_bh_disable();
-+      else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD))
-               ieee80211_sta_ps_deliver_uapsd(sta);
--              local_bh_enable();
--      } else
--              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+      local_bh_enable();
- }
+-      pll = ath9k_hw_compute_pll_control(ah, chan);
+       if (AR_SREV_9565(ah))
+               pll |= 0x40000;
+       REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
+@@ -1192,9 +1192,12 @@ static void ath9k_hw_set_operating_mode(
  
- static int sta_prepare_rate_control(struct ieee80211_local *local,
-@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i
-       spin_lock_init(&sta->lock);
-       spin_lock_init(&sta->ps_lock);
--      INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
-+      INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
-       INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
-       mutex_init(&sta->ampdu_mlme.mtx);
- #ifdef CPTCFG_MAC80211_MESH
-@@ -1140,8 +1137,15 @@ void ieee80211_sta_ps_deliver_wakeup(str
-       }
+       switch (opmode) {
+       case NL80211_IFTYPE_ADHOC:
+-              set |= AR_STA_ID1_ADHOC;
+-              REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+-              break;
++              if (!AR_SREV_9340_13(ah)) {
++                      set |= AR_STA_ID1_ADHOC;
++                      REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
++                      break;
++              }
++              /* fall through */
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_AP:
+               set |= AR_STA_ID1_STA_AP;
+--- a/drivers/net/wireless/ath/ath9k/reg.h
++++ b/drivers/net/wireless/ath/ath9k/reg.h
+@@ -903,6 +903,10 @@
+ #define AR_SREV_9340(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
  
-       ieee80211_add_pending_skbs(local, &pending);
--      clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
--      clear_sta_flag(sta, WLAN_STA_PS_STA);
++#define AR_SREV_9340_13(_ah) \
++      (AR_SREV_9340((_ah)) && \
++       ((_ah)->hw_version.macRev == AR_SREV_REVISION_9340_13))
 +
-+      /* now we're no longer in the deliver code */
-+      clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
+ #define AR_SREV_9340_13_OR_LATER(_ah) \
+       (AR_SREV_9340((_ah)) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13))
+@@ -1240,12 +1244,23 @@ enum {
+ #define AR_CH0_DPLL3_PHASE_SHIFT_S   23
+ #define AR_PHY_CCA_NOM_VAL_2GHZ      -118
++#define AR_RTC_9300_SOC_PLL_DIV_INT          0x0000003f
++#define AR_RTC_9300_SOC_PLL_DIV_INT_S        0
++#define AR_RTC_9300_SOC_PLL_DIV_FRAC         0x000fffc0
++#define AR_RTC_9300_SOC_PLL_DIV_FRAC_S       6
++#define AR_RTC_9300_SOC_PLL_REFDIV           0x01f00000
++#define AR_RTC_9300_SOC_PLL_REFDIV_S         20
++#define AR_RTC_9300_SOC_PLL_CLKSEL           0x06000000
++#define AR_RTC_9300_SOC_PLL_CLKSEL_S         25
++#define AR_RTC_9300_SOC_PLL_BYPASS           0x08000000
 +
-+      /* The station might have polled and then woken up before we responded,
-+       * so clear these flags now to avoid them sticking around.
-+       */
-+      clear_sta_flag(sta, WLAN_STA_PSPOLL);
-+      clear_sta_flag(sta, WLAN_STA_UAPSD);
-       spin_unlock(&sta->ps_lock);
+ #define AR_RTC_9300_PLL_DIV          0x000003ff
+ #define AR_RTC_9300_PLL_DIV_S        0
+ #define AR_RTC_9300_PLL_REFDIV       0x00003C00
+ #define AR_RTC_9300_PLL_REFDIV_S     10
+ #define AR_RTC_9300_PLL_CLKSEL       0x0000C000
+ #define AR_RTC_9300_PLL_CLKSEL_S     14
++#define AR_RTC_9300_PLL_BYPASS       0x00010000
  
-       atomic_dec(&ps->num_sta_ps);
-@@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie
+ #define AR_RTC_9160_PLL_DIV   0x000003ff
+ #define AR_RTC_9160_PLL_DIV_S   0
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -1004,9 +1004,11 @@ static bool ar5008_hw_ani_control_new(st
+       case ATH9K_ANI_FIRSTEP_LEVEL:{
+               u32 level = param;
  
-       trace_api_sta_block_awake(sta->local, pubsta, block);
+-              value = level;
++              value = level * 2;
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRSTEP, value);
++              REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
++                            AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
  
--      if (block)
-+      if (block) {
-               set_sta_flag(sta, WLAN_STA_PS_DRIVER);
--      else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
--              ieee80211_queue_work(hw, &sta->drv_unblock_wk);
-+              return;
-+      }
-+
-+      if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
-+              return;
-+
-+      if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
-+              set_sta_flag(sta, WLAN_STA_PS_DELIVER);
-+              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+              ieee80211_queue_work(hw, &sta->drv_deliver_wk);
-+      } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) ||
-+                 test_sta_flag(sta, WLAN_STA_UAPSD)) {
-+              /* must be asleep in this case */
-+              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+              ieee80211_queue_work(hw, &sta->drv_deliver_wk);
-+      } else {
-+              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+      }
- }
- EXPORT_SYMBOL(ieee80211_sta_block_awake);
+               if (level != aniState->firstepLevel) {
+                       ath_dbg(common, ANI,
+@@ -1040,9 +1042,8 @@ static bool ar5008_hw_ani_control_new(st
+               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+                             AR_PHY_TIMING5_CYCPWR_THR1, value);
  
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
-  */
- #define STA_LOST_PKT_THRESHOLD        50
+-              if (IS_CHAN_HT40(ah->curchan))
+-                      REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+-                                    AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
++              REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
++                                AR_PHY_EXT_TIMING5_CYCPWR_THR1, value - 1);
  
-+static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
+               if (level != aniState->spurImmunityLevel) {
+                       ath_dbg(common, ANI,
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -517,6 +517,23 @@ static void ar9003_hw_spur_mitigate(stru
+       ar9003_hw_spur_mitigate_ofdm(ah, chan);
+ }
++static u32 ar9003_hw_compute_pll_control_soc(struct ath_hw *ah,
++                                           struct ath9k_channel *chan)
 +{
-+      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++      u32 pll;
++
++      pll = SM(0x5, AR_RTC_9300_SOC_PLL_REFDIV);
 +
-+      /* This packet was aggregated but doesn't carry status info */
-+      if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
-+          !(info->flags & IEEE80211_TX_STAT_AMPDU))
-+              return;
++      if (chan && IS_CHAN_HALF_RATE(chan))
++              pll |= SM(0x1, AR_RTC_9300_SOC_PLL_CLKSEL);
++      else if (chan && IS_CHAN_QUARTER_RATE(chan))
++              pll |= SM(0x2, AR_RTC_9300_SOC_PLL_CLKSEL);
 +
-+      if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
-+              return;
++      pll |= SM(0x2c, AR_RTC_9300_SOC_PLL_DIV_INT);
 +
-+      cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
-+                                  sta->lost_packets, GFP_ATOMIC);
-+      sta->lost_packets = 0;
++      return pll;
 +}
 +
- void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+ static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
  {
-       struct sk_buff *skb2;
-@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
-                       if (info->flags & IEEE80211_TX_STAT_ACK) {
-                               if (sta->lost_packets)
-                                       sta->lost_packets = 0;
--                      } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
--                              cfg80211_cqm_pktloss_notify(sta->sdata->dev,
--                                                          sta->sta.addr,
--                                                          sta->lost_packets,
--                                                          GFP_ATOMIC);
--                              sta->lost_packets = 0;
-+                      } else {
-+                              ieee80211_lost_packet(sta, skb);
-                       }
-               }
+@@ -1781,7 +1798,12 @@ void ar9003_hw_attach_phy_ops(struct ath
  
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *
-               return;
-       }
+       priv_ops->rf_set_freq = ar9003_hw_set_channel;
+       priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
+-      priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
++
++      if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
++              priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc;
++      else
++              priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
++
+       priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
+       priv_ops->init_bb = ar9003_hw_init_bb;
+       priv_ops->process_ini = ar9003_hw_process_ini;
+--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+@@ -381,16 +381,27 @@ static int ar9002_hw_proc_txdesc(struct 
+       ts->evm1 = ads->AR_TxEVM1;
+       ts->evm2 = ads->AR_TxEVM2;
  
-+      set_sta_flag(sta, WLAN_STA_PS_DELIVER);
-+      clear_sta_flag(sta, WLAN_STA_PS_STA);
-       ieee80211_sta_ps_deliver_wakeup(sta);
+-      status = ACCESS_ONCE(ads->ds_ctl4);
+-      ts->duration[0] = MS(status, AR_PacketDur0);
+-      ts->duration[1] = MS(status, AR_PacketDur1);
+-      status = ACCESS_ONCE(ads->ds_ctl5);
+-      ts->duration[2] = MS(status, AR_PacketDur2);
+-      ts->duration[3] = MS(status, AR_PacketDur3);
+-
+       return 0;
  }
  
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags {
-       WLAN_STA_TOFFSET_KNOWN,
-       WLAN_STA_MPSP_OWNER,
-       WLAN_STA_MPSP_RECIPIENT,
-+      WLAN_STA_PS_DELIVER,
- };
++static int ar9002_hw_get_duration(struct ath_hw *ah, const void *ds, int index)
++{
++      struct ar5416_desc *ads = AR5416DESC(ds);
++
++      switch (index) {
++      case 0:
++              return MS(ACCESS_ONCE(ads->ds_ctl4), AR_PacketDur0);
++      case 1:
++              return MS(ACCESS_ONCE(ads->ds_ctl4), AR_PacketDur1);
++      case 2:
++              return MS(ACCESS_ONCE(ads->ds_ctl5), AR_PacketDur2);
++      case 3:
++              return MS(ACCESS_ONCE(ads->ds_ctl5), AR_PacketDur3);
++      default:
++              return -1;
++      }
++}
++
+ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+                         u32 size, u32 flags)
+ {
+@@ -413,4 +424,5 @@ void ar9002_hw_attach_mac_ops(struct ath
+       ops->get_isr = ar9002_hw_get_isr;
+       ops->set_txdesc = ar9002_set_txdesc;
+       ops->proc_txdesc = ar9002_hw_proc_txdesc;
++      ops->get_duration = ar9002_hw_get_duration;
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -355,11 +355,9 @@ static int ar9003_hw_proc_txdesc(struct 
+                                struct ath_tx_status *ts)
+ {
+       struct ar9003_txs *ads;
+-      struct ar9003_txc *adc;
+       u32 status;
  
- #define ADDBA_RESP_INTERVAL HZ
-@@ -265,7 +266,7 @@ struct ieee80211_tx_latency_stat {
-  * @last_rx_rate_vht_nss: rx status nss of last data packet
-  * @lock: used for locking all fields that require locking, see comments
-  *    in the header file.
-- * @drv_unblock_wk: used for driver PS unblocking
-+ * @drv_deliver_wk: used for delivering frames after driver PS unblocking
-  * @listen_interval: listen interval of this station, when we're acting as AP
-  * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
-  * @ps_lock: used for powersave (when mac80211 is the AP) related locking
-@@ -345,7 +346,7 @@ struct sta_info {
-       void *rate_ctrl_priv;
-       spinlock_t lock;
--      struct work_struct drv_unblock_wk;
-+      struct work_struct drv_deliver_wk;
-       u16 listen_interval;
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
-               return TX_CONTINUE;
-       if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
--                    test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
-+                    test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
-+                    test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
-                    !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
-               int ac = skb_get_queue_mapping(tx->skb);
-@@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
-                * ahead and Tx the packet.
-                */
-               if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
--                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-+                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
-+                  !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
-                       spin_unlock(&sta->ps_lock);
-                       return TX_CONTINUE;
-               }
---- a/drivers/net/wireless/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
-@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offse
-       return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
+       ads = &ah->ts_ring[ah->ts_tail];
+-      adc = (struct ar9003_txc *)ads;
+       status = ACCESS_ONCE(ads->status8);
+       if ((status & AR_TxDone) == 0)
+@@ -428,18 +426,29 @@ static int ar9003_hw_proc_txdesc(struct 
+       ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
+       ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
+-      status = ACCESS_ONCE(adc->ctl15);
+-      ts->duration[0] = MS(status, AR_PacketDur0);
+-      ts->duration[1] = MS(status, AR_PacketDur1);
+-      status = ACCESS_ONCE(adc->ctl16);
+-      ts->duration[2] = MS(status, AR_PacketDur2);
+-      ts->duration[3] = MS(status, AR_PacketDur3);
+-
+       memset(ads, 0, sizeof(*ads));
+       return 0;
  }
  
-+static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
++static int ar9003_hw_get_duration(struct ath_hw *ah, const void *ds, int index)
 +{
-+      struct data_queue *queue = rt2x00dev->bcn;
-+      struct queue_entry *entry;
-+      int i, bcn_num = 0;
-+      u64 off, reg = 0;
-+      u32 bssid_dw1;
-+
-+      /*
-+       * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
-+       */
-+      for (i = 0; i < queue->limit; i++) {
-+              entry = &queue->entries[i];
-+              if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags))
-+                      continue;
-+              off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx);
-+              reg |= off << (8 * bcn_num);
-+              bcn_num++;
-+      }
-+
-+      WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing);
++      const struct ar9003_txc *adc = ds;
 +
-+      rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
-+      rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));
-+
-+      /*
-+       * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons.
-+       */
-+      rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1);
-+      rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM,
-+                         bcn_num > 0 ? bcn_num - 1 : 0);
-+      rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1);
++      switch (index) {
++      case 0:
++              return MS(ACCESS_ONCE(adc->ctl15), AR_PacketDur0);
++      case 1:
++              return MS(ACCESS_ONCE(adc->ctl15), AR_PacketDur1);
++      case 2:
++              return MS(ACCESS_ONCE(adc->ctl16), AR_PacketDur2);
++      case 3:
++              return MS(ACCESS_ONCE(adc->ctl16), AR_PacketDur3);
++      default:
++              return 0;
++      }
 +}
 +
- void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
  {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_en
-       rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
-                                  entry->skb->len + padding_len);
-+      __set_bit(ENTRY_BCN_ENABLED, &entry->flags);
-+
-+      /*
-+       * Change global beacons settings.
-+       */
-+      rt2800_update_beacons_setup(rt2x00dev);
-       /*
-        * Restore beaconing state.
-@@ -1053,8 +1093,13 @@ void rt2800_clear_beacon(struct queue_en
-        * Clear beacon.
-        */
-       rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
-+      __clear_bit(ENTRY_BCN_ENABLED, &entry->flags);
-       /*
-+       * Change global beacons settings.
-+       */
-+      rt2800_update_beacons_setup(rt2x00dev);
-+      /*
-        * Restore beaconing state.
-        */
-       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
-@@ -1556,7 +1601,7 @@ void rt2800_config_intf(struct rt2x00_de
-               if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
-                       reg = le32_to_cpu(conf->bssid[1]);
-                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
--                      rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
-+                      rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
-                       conf->bssid[1] = cpu_to_le32(reg);
-               }
+       struct ath_hw_ops *ops = ath9k_hw_ops(hw);
+@@ -449,6 +458,7 @@ void ar9003_hw_attach_mac_ops(struct ath
+       ops->get_isr = ar9003_hw_get_isr;
+       ops->set_txdesc = ar9003_set_txdesc;
+       ops->proc_txdesc = ar9003_hw_proc_txdesc;
++      ops->get_duration = ar9003_hw_get_duration;
+ }
  
-@@ -4517,28 +4562,6 @@ static int rt2800_init_registers(struct 
-       if (ret)
-               return ret;
--      rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
--      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0,
--                         rt2800_get_beacon_offset(rt2x00dev, 0));
--      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1,
--                         rt2800_get_beacon_offset(rt2x00dev, 1));
--      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2,
--                         rt2800_get_beacon_offset(rt2x00dev, 2));
--      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3,
--                         rt2800_get_beacon_offset(rt2x00dev, 3));
--      rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);
--
--      rt2800_register_read(rt2x00dev, BCN_OFFSET1, &reg);
--      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4,
--                         rt2800_get_beacon_offset(rt2x00dev, 4));
--      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5,
--                         rt2800_get_beacon_offset(rt2x00dev, 5));
--      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6,
--                         rt2800_get_beacon_offset(rt2x00dev, 6));
--      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7,
--                         rt2800_get_beacon_offset(rt2x00dev, 7));
--      rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);
--
-       rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
-       rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+ void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
+--- a/drivers/net/wireless/ath/ath9k/dynack.c
++++ b/drivers/net/wireless/ath/ath9k/dynack.c
+@@ -202,7 +202,7 @@ void ath_dynack_sample_tx_ts(struct ath_
+       ridx = ts->ts_rateindex;
  
---- a/drivers/net/wireless/rt2x00/rt2x00dev.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
-@@ -141,8 +141,11 @@ static void rt2x00lib_intf_scheduled_ite
-       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-               return;
+       da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
+-      da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration[ts->ts_rateindex];
++      da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration;
+       ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
+       ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
  
--      if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
-+      if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) {
-+              mutex_lock(&intf->beacon_skb_mutex);
-               rt2x00queue_update_beacon(rt2x00dev, vif);
-+              mutex_unlock(&intf->beacon_skb_mutex);
-+      }
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -67,6 +67,12 @@ static inline int ath9k_hw_txprocdesc(st
+       return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
  }
  
- static void rt2x00lib_intf_scheduled(struct work_struct *work)
-@@ -216,7 +219,7 @@ static void rt2x00lib_beaconupdate_iter(
-        * never be called for USB devices.
-        */
-       WARN_ON(rt2x00_is_usb(rt2x00dev));
--      rt2x00queue_update_beacon_locked(rt2x00dev, vif);
-+      rt2x00queue_update_beacon(rt2x00dev, vif);
++static inline int ath9k_hw_get_duration(struct ath_hw *ah, const void *ds,
++                                      int index)
++{
++      return ath9k_hw_ops(ah)->get_duration(ah, ds, index);
++}
++
+ static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+               struct ath_hw_antcomb_conf *antconf)
+ {
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -691,6 +691,7 @@ struct ath_hw_ops {
+                          struct ath_tx_info *i);
+       int (*proc_txdesc)(struct ath_hw *ah, void *ds,
+                          struct ath_tx_status *ts);
++      int (*get_duration)(struct ath_hw *ah, const void *ds, int index);
+       void (*antdiv_comb_conf_get)(struct ath_hw *ah,
+                       struct ath_hw_antcomb_conf *antconf);
+       void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -121,7 +121,7 @@ struct ath_tx_status {
+       u32 evm0;
+       u32 evm1;
+       u32 evm2;
+-      u32 duration[4];
++      u32 duration;
+ };
+ struct ath_rx_status {
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -683,6 +683,8 @@ static void ath_tx_process_buffer(struct
+       if (bf_is_ampdu_not_probing(bf))
+               txq->axq_ampdu_depth--;
++      ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc,
++                                           ts->ts_rateindex);
+       if (!bf_isampdu(bf)) {
+               if (!flush) {
+                       info = IEEE80211_SKB_CB(bf->bf_mpdu);
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -455,7 +455,8 @@ void ath9k_p2p_bss_info_changed(struct a
+ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+                         struct sk_buff *skb);
+ void ath9k_p2p_ps_timer(void *priv);
+-void ath9k_chanctx_wake_queues(struct ath_softc *sc);
++void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx);
++void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx);
+ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
+ void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+@@ -525,7 +526,12 @@ static inline void ath9k_beacon_add_noa(
+ static inline void ath9k_p2p_ps_timer(struct ath_softc *sc)
+ {
  }
+-static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc)
++static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc,
++                                           struct ath_chanctx *ctx)
++{
++}
++static inline void ath9k_chanctx_stop_queues(struct ath_softc *sc,
++                                           struct ath_chanctx *ctx)
+ {
+ }
+ static inline void ath_chanctx_check_active(struct ath_softc *sc,
+--- a/drivers/net/wireless/ath/ath9k/channel.c
++++ b/drivers/net/wireless/ath/ath9k/channel.c
+@@ -761,6 +761,13 @@ void ath_offchannel_next(struct ath_soft
  
- void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
---- a/drivers/net/wireless/rt2x00/rt2x00mac.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
-@@ -624,25 +624,24 @@ void rt2x00mac_bss_info_changed(struct i
-        * Start/stop beaconing.
-        */
-       if (changes & BSS_CHANGED_BEACON_ENABLED) {
-+              mutex_lock(&intf->beacon_skb_mutex);
-               if (!bss_conf->enable_beacon && intf->enable_beacon) {
-                       rt2x00dev->intf_beaconing--;
-                       intf->enable_beacon = false;
--                      /*
--                       * Clear beacon in the H/W for this vif. This is needed
--                       * to disable beaconing on this particular interface
--                       * and keep it running on other interfaces.
--                       */
--                      rt2x00queue_clear_beacon(rt2x00dev, vif);
-                       if (rt2x00dev->intf_beaconing == 0) {
-                               /*
-                                * Last beaconing interface disabled
-                                * -> stop beacon queue.
-                                */
--                              mutex_lock(&intf->beacon_skb_mutex);
-                               rt2x00queue_stop_queue(rt2x00dev->bcn);
--                              mutex_unlock(&intf->beacon_skb_mutex);
-                       }
-+                      /*
-+                       * Clear beacon in the H/W for this vif. This is needed
-+                       * to disable beaconing on this particular interface
-+                       * and keep it running on other interfaces.
-+                       */
-+                      rt2x00queue_clear_beacon(rt2x00dev, vif);
-               } else if (bss_conf->enable_beacon && !intf->enable_beacon) {
-                       rt2x00dev->intf_beaconing++;
-                       intf->enable_beacon = true;
-@@ -658,11 +657,10 @@ void rt2x00mac_bss_info_changed(struct i
-                                * First beaconing interface enabled
-                                * -> start beacon queue.
-                                */
--                              mutex_lock(&intf->beacon_skb_mutex);
-                               rt2x00queue_start_queue(rt2x00dev->bcn);
--                              mutex_unlock(&intf->beacon_skb_mutex);
-                       }
+ void ath_roc_complete(struct ath_softc *sc, bool abort)
+ {
++      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++
++      if (abort)
++              ath_dbg(common, CHAN_CTX, "RoC aborted\n");
++      else
++              ath_dbg(common, CHAN_CTX, "RoC expired\n");
++
+       sc->offchannel.roc_vif = NULL;
+       sc->offchannel.roc_chan = NULL;
+       if (!abort)
+@@ -1037,9 +1044,11 @@ static void ath_offchannel_channel_chang
+ void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+ {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++      struct ath_chanctx *old_ctx;
+       struct timespec ts;
+       bool measure_time = false;
+       bool send_ps = false;
++      bool queues_stopped = false;
+       spin_lock_bh(&sc->chan_lock);
+       if (!sc->next_chan) {
+@@ -1069,6 +1078,10 @@ void ath_chanctx_set_next(struct ath_sof
+                       getrawmonotonic(&ts);
+                       measure_time = true;
+               }
++
++              ath9k_chanctx_stop_queues(sc, sc->cur_chan);
++              queues_stopped = true;
++
+               __ath9k_flush(sc->hw, ~0, true);
+               if (ath_chanctx_send_ps_frame(sc, true))
+@@ -1082,6 +1095,7 @@ void ath_chanctx_set_next(struct ath_sof
+                       sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
                }
-+              mutex_unlock(&intf->beacon_skb_mutex);
        }
++      old_ctx = sc->cur_chan;
+       sc->cur_chan = sc->next_chan;
+       sc->cur_chan->stopped = false;
+       sc->next_chan = NULL;
+@@ -1104,7 +1118,16 @@ void ath_chanctx_set_next(struct ath_sof
+               if (measure_time)
+                       sc->sched.channel_switch_time =
+                               ath9k_hw_get_tsf_offset(&ts, NULL);
++              /*
++               * A reset will ensure that all queues are woken up,
++               * so there is no need to awaken them again.
++               */
++              goto out;
+       }
++
++      if (queues_stopped)
++              ath9k_chanctx_wake_queues(sc, old_ctx);
++out:
+       if (send_ps)
+               ath_chanctx_send_ps_frame(sc, false);
  
-       /*
---- a/drivers/net/wireless/rt2x00/rt2x00queue.c
-+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
-@@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x
-       if (unlikely(!intf->beacon))
-               return -ENOBUFS;
+@@ -1170,18 +1193,37 @@ bool ath9k_is_chanctx_enabled(void)
+ /* Queue management */
+ /********************/
  
--      mutex_lock(&intf->beacon_skb_mutex);
--
-       /*
-        * Clean up the beacon skb.
-        */
-@@ -768,13 +766,11 @@ int rt2x00queue_clear_beacon(struct rt2x
-       if (rt2x00dev->ops->lib->clear_beacon)
-               rt2x00dev->ops->lib->clear_beacon(intf->beacon);
+-void ath9k_chanctx_wake_queues(struct ath_softc *sc)
++void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
++{
++      struct ath_hw *ah = sc->sc_ah;
++      int i;
++
++      if (ctx == &sc->offchannel.chan) {
++              ieee80211_stop_queue(sc->hw,
++                                   sc->hw->offchannel_tx_hw_queue);
++      } else {
++              for (i = 0; i < IEEE80211_NUM_ACS; i++)
++                      ieee80211_stop_queue(sc->hw,
++                                           ctx->hw_queue_base + i);
++      }
++
++      if (ah->opmode == NL80211_IFTYPE_AP)
++              ieee80211_stop_queue(sc->hw, sc->hw->queues - 2);
++}
++
++
++void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
+ {
+       struct ath_hw *ah = sc->sc_ah;
+       int i;
  
--      mutex_unlock(&intf->beacon_skb_mutex);
--
-       return 0;
- }
+-      if (sc->cur_chan == &sc->offchannel.chan) {
++      if (ctx == &sc->offchannel.chan) {
+               ieee80211_wake_queue(sc->hw,
+                                    sc->hw->offchannel_tx_hw_queue);
+       } else {
+               for (i = 0; i < IEEE80211_NUM_ACS; i++)
+                       ieee80211_wake_queue(sc->hw,
+-                                           sc->cur_chan->hw_queue_base + i);
++                                           ctx->hw_queue_base + i);
+       }
  
--int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
--                                   struct ieee80211_vif *vif)
-+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
-+                            struct ieee80211_vif *vif)
- {
-       struct rt2x00_intf *intf = vif_to_intf(vif);
-       struct skb_frame_desc *skbdesc;
-@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str
+       if (ah->opmode == NL80211_IFTYPE_AP)
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+@@ -464,6 +464,7 @@ static int ath9k_init_priv(struct ath9k_
+               return -ENOMEM;
  
+       ah->dev = priv->dev;
++      ah->hw = priv->hw;
+       ah->hw_version.devid = devid;
+       ah->hw_version.usbdev = drv_info;
+       ah->ah_flags |= AH_USE_EEPROM;
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -60,8 +60,10 @@ static bool ath9k_has_pending_frames(str
+       spin_lock_bh(&txq->axq_lock);
+-      if (txq->axq_depth)
++      if (txq->axq_depth) {
+               pending = true;
++              goto out;
++      }
+       if (txq->mac80211_qnum >= 0) {
+               struct list_head *list;
+@@ -70,6 +72,7 @@ static bool ath9k_has_pending_frames(str
+               if (!list_empty(list))
+                       pending = true;
+       }
++out:
+       spin_unlock_bh(&txq->axq_lock);
+       return pending;
  }
+@@ -261,12 +264,7 @@ static bool ath_complete_reset(struct at
  
--int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
--                            struct ieee80211_vif *vif)
--{
--      struct rt2x00_intf *intf = vif_to_intf(vif);
--      int ret;
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
 -
--      mutex_lock(&intf->beacon_skb_mutex);
--      ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif);
--      mutex_unlock(&intf->beacon_skb_mutex);
+-      if (!ath9k_is_chanctx_enabled())
+-              ieee80211_wake_queues(sc->hw);
+-      else
+-              ath9k_chanctx_wake_queues(sc);
 -
--      return ret;
--}
++      ieee80211_wake_queues(sc->hw);
+       ath9k_p2p_ps_timer(sc);
+       return true;
+@@ -1971,9 +1969,6 @@ static bool ath9k_has_tx_pending(struct 
+               if (!ATH_TXQ_SETUP(sc, i))
+                       continue;
+-              if (!sc->tx.txq[i].axq_depth)
+-                      continue;
 -
- bool rt2x00queue_for_each_entry(struct data_queue *queue,
-                               enum queue_index start,
-                               enum queue_index end,
---- a/drivers/net/wireless/rt2x00/rt2x00queue.h
-+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
-@@ -353,6 +353,7 @@ struct txentry_desc {
-  */
- enum queue_entry_flags {
-       ENTRY_BCN_ASSIGNED,
-+      ENTRY_BCN_ENABLED,
-       ENTRY_OWNER_DEVICE_DATA,
-       ENTRY_DATA_PENDING,
-       ENTRY_DATA_IO_FAILED,
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1757,7 +1757,6 @@ out:
- void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
- {
-       struct ath_vif *avp = (void *)vif->drv_priv;
--      unsigned long flags;
-       u32 tsf;
+               npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+               if (npend)
+                       break;
+@@ -1999,7 +1994,6 @@ void __ath9k_flush(struct ieee80211_hw *
+       struct ath_common *common = ath9k_hw_common(ah);
+       int timeout = HZ / 5; /* 200 ms */
+       bool drain_txq;
+-      int i;
  
-       if (!sc->p2p_ps_timer)
-@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft
-               return;
+       cancel_delayed_work_sync(&sc->tx_complete_work);
+@@ -2027,10 +2021,6 @@ void __ath9k_flush(struct ieee80211_hw *
+                       ath_reset(sc);
+               ath9k_ps_restore(sc);
+-              for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+-                      ieee80211_wake_queue(sc->hw,
+-                                           sc->cur_chan->hw_queue_base + i);
+-              }
+       }
  
-       sc->p2p_ps_vif = avp;
+       ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
+@@ -2039,16 +2029,8 @@ void __ath9k_flush(struct ieee80211_hw *
+ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
+ {
+       struct ath_softc *sc = hw->priv;
+-      int i;
 -
--      spin_lock_irqsave(&sc->sc_pm_lock, flags);
--      if (!(sc->ps_flags & PS_BEACON_SYNC)) {
--              tsf = ath9k_hw_gettsf32(sc->sc_ah);
--              ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
--              ath9k_update_p2p_ps_timer(sc, avp);
+-      for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+-              if (!ATH_TXQ_SETUP(sc, i))
+-                      continue;
+-              if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
+-                      return true;
 -      }
--      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-+      tsf = ath9k_hw_gettsf32(sc->sc_ah);
-+      ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
-+      ath9k_update_p2p_ps_timer(sc, avp);
+-      return false;
++      return ath9k_has_tx_pending(sc);
  }
  
- static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
-@@ -1791,6 +1785,7 @@ static void ath9k_bss_info_changed(struc
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_vif *avp = (void *)vif->drv_priv;
-+      unsigned long flags;
-       int slottime;
-       ath9k_ps_wakeup(sc);
-@@ -1853,7 +1848,10 @@ static void ath9k_bss_info_changed(struc
-       if (changed & BSS_CHANGED_P2P_PS) {
-               spin_lock_bh(&sc->sc_pcu_lock);
--              ath9k_update_p2p_ps(sc, vif);
-+              spin_lock_irqsave(&sc->sc_pm_lock, flags);
-+              if (!(sc->ps_flags & PS_BEACON_SYNC))
-+                      ath9k_update_p2p_ps(sc, vif);
-+              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-               spin_unlock_bh(&sc->sc_pcu_lock);
-       }
+ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
+@@ -2350,7 +2332,7 @@ static void ath9k_remove_chanctx(struct 
+               conf->def.chan->center_freq);
+       ctx->assigned = false;
+-      ctx->hw_queue_base = -1;
++      ctx->hw_queue_base = 0;
+       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
+       mutex_unlock(&sc->mutex);
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -448,7 +448,7 @@ static void rate_fixup_ratelist(struct i
+        */
+       if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
+               u32 basic_rates = vif->bss_conf.basic_rates;
+-              s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0;
++              s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
+               rate = &sband->bitrates[rates[0].idx];