-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(®, MAC_BSSID_DW1_BSS_ID_MASK, 3);
-- rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
-+ rt2x00_set_field32(®, 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, ®);
-- rt2x00_set_field32(®, BCN_OFFSET0_BCN0,
-- rt2800_get_beacon_offset(rt2x00dev, 0));
-- rt2x00_set_field32(®, BCN_OFFSET0_BCN1,
-- rt2800_get_beacon_offset(rt2x00dev, 1));
-- rt2x00_set_field32(®, BCN_OFFSET0_BCN2,
-- rt2800_get_beacon_offset(rt2x00dev, 2));
-- rt2x00_set_field32(®, BCN_OFFSET0_BCN3,
-- rt2800_get_beacon_offset(rt2x00dev, 3));
-- rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);
--
-- rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®);
-- rt2x00_set_field32(®, BCN_OFFSET1_BCN4,
-- rt2800_get_beacon_offset(rt2x00dev, 4));
-- rt2x00_set_field32(®, BCN_OFFSET1_BCN5,
-- rt2800_get_beacon_offset(rt2x00dev, 5));
-- rt2x00_set_field32(®, BCN_OFFSET1_BCN6,
-- rt2800_get_beacon_offset(rt2x00dev, 6));
-- rt2x00_set_field32(®, 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];