PKG_NAME:=mac80211
-PKG_VERSION:=2011-02-25
+PKG_VERSION:=2011-03-11
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
-PKG_MD5SUM:=c0242cc152a157902ff60fe05d1773b2
+PKG_MD5SUM:=123b9220fa2b016979b7b3874f349643
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
--- a/include/linux/compat-2.6.36.h
+++ b/include/linux/compat-2.6.36.h
-@@ -102,6 +102,8 @@ int no_printk(const char *s, ...) { retu
- #define alloc_workqueue(name, flags, max_active) __create_workqueue(name, flags, max_active, 0)
- #endif
+@@ -104,6 +104,8 @@ int no_printk(const char *s, ...) { retu
+
+ #define PCI_EEPROM_WIDTH_93C86 8
+#define PCI_EEPROM_WIDTH_93C86 8
+
+++ /dev/null
---- a/compat/compat-2.6.39.c
-+++ b/compat/compat-2.6.39.c
-@@ -10,6 +10,7 @@
-
- #include <linux/compat.h>
- #include <linux/tty.h>
-+#include <linux/sched.h>
-
- /*
- * Termios Helper Methods
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1091,6 +1091,12 @@ int ath9k_init_debug(struct ath_hw *ah)
- sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
+@@ -1145,6 +1145,12 @@ int ath9k_init_debug(struct ath_hw *ah)
+ sc, &fops_regdump))
goto err;
+ debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -189,7 +189,6 @@ struct ath_txq {
+ u32 axq_ampdu_depth;
+ bool stopped;
+ bool axq_tx_inprogress;
+- bool txq_flush_inprogress;
+ struct list_head axq_acq;
+ struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+ struct list_head txq_fifo_pending;
+--- a/drivers/net/wireless/ath/ath9k/beacon.c
++++ b/drivers/net/wireless/ath/ath9k/beacon.c
+@@ -373,6 +373,7 @@ void ath_beacon_tasklet(unsigned long da
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
++ ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
+ ath9k_hw_bstuck_nfcal(ah);
+ } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+@@ -450,16 +451,6 @@ void ath_beacon_tasklet(unsigned long da
+ sc->beacon.updateslot = OK;
+ }
+ if (bfaddr != 0) {
+- /*
+- * Stop any current dma and put the new frame(s) on the queue.
+- * This should never fail since we check above that no frames
+- * are still pending on the queue.
+- */
+- if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
+- ath_err(common, "beacon queue %u did not stop?\n",
+- sc->beacon.beaconq);
+- }
+-
+ /* NB: cabq traffic should already be queued and primed */
+ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
+ ath9k_hw_txstart(ah, sc->beacon.beaconq);
+@@ -780,7 +771,7 @@ void ath9k_set_beaconing_status(struct a
+ ah->imask &= ~ATH9K_INT_SWBA;
+ ath9k_hw_set_interrupts(ah, ah->imask);
+ tasklet_kill(&sc->bcon_tasklet);
+- ath9k_hw_stoptxdma(ah, sc->beacon.beaconq);
++ ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
+ }
+ ath9k_ps_restore(sc);
+ }
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -95,9 +95,9 @@
+ #define REG_READ_FIELD(_a, _r, _f) \
+ (((REG_READ(_a, _r) & _f) >> _f##_S))
+ #define REG_SET_BIT(_a, _r, _f) \
+- REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
++ REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f))
+ #define REG_CLR_BIT(_a, _r, _f) \
+- REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
++ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f))
+
+ #define DO_DELAY(x) do { \
+ if ((++(x) % 64) == 0) \
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -143,84 +143,59 @@ bool ath9k_hw_updatetxtriglevel(struct a
+ }
+ EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
+
+-bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
++void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
+ {
+-#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
+-#define ATH9K_TIME_QUANTUM 100 /* usec */
+- struct ath_common *common = ath9k_hw_common(ah);
+- struct ath9k_hw_capabilities *pCap = &ah->caps;
+- struct ath9k_tx_queue_info *qi;
+- u32 tsfLow, j, wait;
+- u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
++ int i, q;
+
+- if (q >= pCap->total_queues) {
+- ath_dbg(common, ATH_DBG_QUEUE,
+- "Stopping TX DMA, invalid queue: %u\n", q);
+- return false;
+- }
++ REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
+
+- qi = &ah->txq[q];
+- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+- ath_dbg(common, ATH_DBG_QUEUE,
+- "Stopping TX DMA, inactive queue: %u\n", q);
+- return false;
+- }
++ REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
++ REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+- REG_WRITE(ah, AR_Q_TXD, 1 << q);
++ for (q = 0; q < AR_NUM_QCU; q++) {
++ for (i = 0; i < 1000; i++) {
++ if (i)
++ udelay(5);
+
+- for (wait = wait_time; wait != 0; wait--) {
+- if (ath9k_hw_numtxpending(ah, q) == 0)
+- break;
+- udelay(ATH9K_TIME_QUANTUM);
++ if (!ath9k_hw_numtxpending(ah, q))
++ break;
++ }
+ }
+
+- if (ath9k_hw_numtxpending(ah, q)) {
+- ath_dbg(common, ATH_DBG_QUEUE,
+- "%s: Num of pending TX Frames %d on Q %d\n",
+- __func__, ath9k_hw_numtxpending(ah, q), q);
+-
+- for (j = 0; j < 2; j++) {
+- tsfLow = REG_READ(ah, AR_TSF_L32);
+- REG_WRITE(ah, AR_QUIET2,
+- SM(10, AR_QUIET2_QUIET_DUR));
+- REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+- REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+- REG_SET_BIT(ah, AR_TIMER_MODE,
+- AR_QUIET_TIMER_EN);
+-
+- if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+- break;
++ REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
++ REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+- ath_dbg(common, ATH_DBG_QUEUE,
+- "TSF has moved while trying to set quiet time TSF: 0x%08x\n",
+- tsfLow);
+- }
++ REG_WRITE(ah, AR_Q_TXD, 0);
++}
++EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
+
+- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
++bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
++{
++#define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */
++#define ATH9K_TIME_QUANTUM 100 /* usec */
++ int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
++ int wait;
+
+- udelay(200);
+- REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
++ REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+- wait = wait_time;
+- while (ath9k_hw_numtxpending(ah, q)) {
+- if ((--wait) == 0) {
+- ath_err(common,
+- "Failed to stop TX DMA in 100 msec after killing last frame\n");
+- break;
+- }
++ for (wait = wait_time; wait != 0; wait--) {
++ if (wait != wait_time)
+ udelay(ATH9K_TIME_QUANTUM);
+- }
+
+- REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
++ if (ath9k_hw_numtxpending(ah, q) == 0)
++ break;
+ }
+
+ REG_WRITE(ah, AR_Q_TXD, 0);
++
+ return wait != 0;
+
+ #undef ATH9K_TX_STOP_DMA_TIMEOUT
+ #undef ATH9K_TIME_QUANTUM
+ }
+-EXPORT_SYMBOL(ath9k_hw_stoptxdma);
++EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
+
+ void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
+ {
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -676,7 +676,8 @@ void ath9k_hw_txstart(struct ath_hw *ah,
+ void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
+ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
+ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
+-bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
++bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
++void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
+ void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
+ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
+ const struct ath9k_tx_queue_info *qinfo);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -2128,56 +2128,42 @@ static void ath9k_set_coverage_class(str
+
+ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
+ {
+-#define ATH_FLUSH_TIMEOUT 60 /* ms */
+ struct ath_softc *sc = hw->priv;
+- struct ath_txq *txq = NULL;
+- struct ath_hw *ah = sc->sc_ah;
+- struct ath_common *common = ath9k_hw_common(ah);
+- int i, j, npend = 0;
++ int timeout = 200; /* ms */
++ int i, j;
+
++ ath9k_ps_wakeup(sc);
+ mutex_lock(&sc->mutex);
+
+ cancel_delayed_work_sync(&sc->tx_complete_work);
+
+- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+- if (!ATH_TXQ_SETUP(sc, i))
+- continue;
+- txq = &sc->tx.txq[i];
+-
+- if (!drop) {
+- for (j = 0; j < ATH_FLUSH_TIMEOUT; j++) {
+- if (!ath9k_has_pending_frames(sc, txq))
+- break;
+- usleep_range(1000, 2000);
+- }
+- }
++ if (drop)
++ timeout = 1;
++
++ for (j = 0; j < timeout; j++) {
++ int npend = 0;
++
++ if (j)
++ usleep_range(1000, 2000);
+
+- if (drop || ath9k_has_pending_frames(sc, txq)) {
+- ath_dbg(common, ATH_DBG_QUEUE, "Drop frames from hw queue:%d\n",
+- txq->axq_qnum);
+- spin_lock_bh(&txq->axq_lock);
+- txq->txq_flush_inprogress = true;
+- spin_unlock_bh(&txq->axq_lock);
+-
+- ath9k_ps_wakeup(sc);
+- ath9k_hw_stoptxdma(ah, txq->axq_qnum);
+- npend = ath9k_hw_numtxpending(ah, txq->axq_qnum);
+- ath9k_ps_restore(sc);
+- if (npend)
+- break;
++ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
++ if (!ATH_TXQ_SETUP(sc, i))
++ continue;
+
+- ath_draintxq(sc, txq, false);
+- txq->txq_flush_inprogress = false;
++ npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+ }
++
++ if (!npend)
++ goto out;
+ }
+
+- if (npend) {
++ if (!ath_drain_all_txq(sc, false))
+ ath_reset(sc, false);
+- txq->txq_flush_inprogress = false;
+- }
+
++out:
+ ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
+ mutex_unlock(&sc->mutex);
++ ath9k_ps_restore(sc);
+ }
+
+ struct ieee80211_ops ath9k_ops = {
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -166,7 +166,7 @@ static void ath_tx_flush_tid(struct ath_
+ fi = get_frame_info(bf->bf_mpdu);
+ if (fi->retries) {
+ ath_tx_update_baw(sc, tid, fi->seqno);
+- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
++ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
+ } else {
+ ath_tx_send_normal(sc, txq, NULL, &bf_head);
+ }
+@@ -1194,16 +1194,14 @@ bool ath_drain_all_txq(struct ath_softc
+ if (sc->sc_flags & SC_OP_INVALID)
+ return true;
+
+- /* Stop beacon queue */
+- ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
++ ath9k_hw_abort_tx_dma(ah);
+
+- /* Stop data queues */
++ /* Check if any queue remains active */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+- if (ATH_TXQ_SETUP(sc, i)) {
+- txq = &sc->tx.txq[i];
+- ath9k_hw_stoptxdma(ah, txq->axq_qnum);
+- npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
+- }
++ if (!ATH_TXQ_SETUP(sc, i))
++ continue;
++
++ npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
+ }
+
+ if (npend)
+@@ -2014,8 +2012,7 @@ static void ath_tx_processq(struct ath_s
+ spin_lock_bh(&txq->axq_lock);
+ if (list_empty(&txq->axq_q)) {
+ txq->axq_link = NULL;
+- if (sc->sc_flags & SC_OP_TXAGGR &&
+- !txq->txq_flush_inprogress)
++ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_txq_schedule(sc, txq);
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+@@ -2096,7 +2093,7 @@ static void ath_tx_processq(struct ath_s
+
+ spin_lock_bh(&txq->axq_lock);
+
+- if (sc->sc_flags & SC_OP_TXAGGR && !txq->txq_flush_inprogress)
++ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_txq_schedule(sc, txq);
+ spin_unlock_bh(&txq->axq_lock);
+ }
+@@ -2267,18 +2264,17 @@ void ath_tx_edma_tasklet(struct ath_soft
+
+ spin_lock_bh(&txq->axq_lock);
+
+- if (!txq->txq_flush_inprogress) {
+- if (!list_empty(&txq->txq_fifo_pending)) {
+- INIT_LIST_HEAD(&bf_head);
+- bf = list_first_entry(&txq->txq_fifo_pending,
+- struct ath_buf, list);
+- list_cut_position(&bf_head,
+- &txq->txq_fifo_pending,
+- &bf->bf_lastbf->list);
+- ath_tx_txqaddbuf(sc, txq, &bf_head);
+- } else if (sc->sc_flags & SC_OP_TXAGGR)
+- ath_txq_schedule(sc, txq);
+- }
++ if (!list_empty(&txq->txq_fifo_pending)) {
++ INIT_LIST_HEAD(&bf_head);
++ bf = list_first_entry(&txq->txq_fifo_pending,
++ struct ath_buf, list);
++ list_cut_position(&bf_head,
++ &txq->txq_fifo_pending,
++ &bf->bf_lastbf->list);
++ ath_tx_txqaddbuf(sc, txq, &bf_head);
++ } else if (sc->sc_flags & SC_OP_TXAGGR)
++ ath_txq_schedule(sc, txq);
++
+ spin_unlock_bh(&txq->axq_lock);
+ }
+ }
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -77,6 +77,9 @@ bool ieee80211_set_channel_type(struct i
+ switch (tmp->vif.bss_conf.channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
++ if (superchan > tmp->vif.bss_conf.channel_type)
++ break;
++
+ superchan = tmp->vif.bss_conf.channel_type;
+ break;
+ case NL80211_CHAN_HT40PLUS:
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -120,6 +120,9 @@ static void ath_unregister_led(struct at
-
- void ath_deinit_leds(struct ath_softc *sc)
+@@ -41,6 +41,9 @@ void ath_init_leds(struct ath_softc *sc)
{
-+ if (AR_SREV_9100(sc->sc_ah))
-+ return;
-+
- ath_unregister_led(&sc->assoc_led);
- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
- ath_unregister_led(&sc->tx_led);
-@@ -133,6 +136,9 @@ void ath_init_leds(struct ath_softc *sc)
- char *trigger;
int ret;
+ if (AR_SREV_9100(sc->sc_ah))
+
if (AR_SREV_9287(sc->sc_ah))
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
- else
+ else if (AR_SREV_9485(sc->sc_ah))
#include "ath9k.h"
-@@ -522,6 +523,7 @@ static void ath9k_init_misc(struct ath_s
+@@ -537,6 +538,7 @@ static void ath9k_init_misc(struct ath_s
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops)
{
struct ath_hw *ah = NULL;
struct ath_common *common;
int ret = 0, i;
-@@ -536,7 +538,7 @@ static int ath9k_init_softc(u16 devid, s
+@@ -551,7 +553,7 @@ static int ath9k_init_softc(u16 devid, s
ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
ah->ah_flags |= AH_USE_EEPROM;
common = ath9k_hw_common(ah);
-@@ -572,6 +574,9 @@ static int ath9k_init_softc(u16 devid, s
+@@ -587,6 +589,9 @@ static int ath9k_init_softc(u16 devid, s
if (ret)
goto err_hw;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -538,8 +538,14 @@ static int ath9k_init_softc(u16 devid, s
+@@ -553,8 +553,14 @@ static int ath9k_init_softc(u16 devid, s
ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -139,10 +139,12 @@ void ath_init_leds(struct ath_softc *sc)
+@@ -44,12 +44,14 @@ void ath_init_leds(struct ath_softc *sc)
if (AR_SREV_9100(sc->sc_ah))
return;
- if (AR_SREV_9287(sc->sc_ah))
- sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+- else if (AR_SREV_9485(sc->sc_ah))
+- sc->sc_ah->led_pin = ATH_LED_PIN_9485;
- else
- sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+ if (sc->sc_ah->led_pin < 0) {
+ if (AR_SREV_9287(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9287;
++ else if (AR_SREV_9485(sc->sc_ah))
++ sc->sc_ah->led_pin = ATH_LED_PIN_9485;
+ else
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+ }
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1027,6 +1027,53 @@ static const struct file_operations fops
- .llseek = default_llseek,
+@@ -1077,6 +1077,53 @@ static const struct file_operations fops
+ .llseek = default_llseek,/* read accesses f_pos */
};
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
-@@ -1097,6 +1144,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1151,6 +1198,10 @@ int ath9k_init_debug(struct ath_hw *ah)
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1466,8 +1466,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ REG_WRITE(ah, AR_OBS, 8);
+
+ if (ah->config.rx_intr_mitigation) {
+- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
+- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
++ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);
++ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 500);
+ }
+
+ if (ah->config.tx_intr_mitigation) {
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -449,26 +449,20 @@ void ath9k_btcoex_timer_pause(struct ath
-
- #define ATH_LED_PIN_DEF 1
- #define ATH_LED_PIN_9287 8
--#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
--#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
--
--enum ath_led_type {
-- ATH_LED_RADIO,
-- ATH_LED_ASSOC,
-- ATH_LED_TX,
-- ATH_LED_RX
--};
--
--struct ath_led {
-- struct ath_softc *sc;
-- struct led_classdev led_cdev;
-- enum ath_led_type led_type;
-- char name[32];
-- bool registered;
--};
-
-+#ifdef CONFIG_MAC80211_LEDS
- void ath_init_leds(struct ath_softc *sc);
- void ath_deinit_leds(struct ath_softc *sc);
-+#else
-+static inline void ath_init_leds(struct ath_softc *sc)
-+{
-+}
-+
-+static inline void ath_deinit_leds(struct ath_softc *sc)
-+{
-+}
-+#endif
-+
-
- /* Antenna diversity/combining */
- #define ATH_ANT_RX_CURRENT_SHIFT 4
-@@ -620,15 +614,11 @@ struct ath_softc {
- struct ath_beacon beacon;
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-
-- struct ath_led radio_led;
-- struct ath_led assoc_led;
-- struct ath_led tx_led;
-- struct ath_led rx_led;
-- struct delayed_work ath_led_blink_work;
-- int led_on_duration;
-- int led_off_duration;
-- int led_on_cnt;
-- int led_off_cnt;
-+#ifdef CONFIG_MAC80211_LEDS
-+ bool led_registered;
-+ char led_name[32];
-+ struct led_classdev led_cdev;
-+#endif
-
- struct ath9k_hw_cal_data caldata;
- int last_rssi;
---- a/drivers/net/wireless/ath/ath9k/gpio.c
-+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -20,120 +20,25 @@
- /* LED functions */
- /********************************/
-
--static void ath_led_blink_work(struct work_struct *work)
--{
-- struct ath_softc *sc = container_of(work, struct ath_softc,
-- ath_led_blink_work.work);
--
-- if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
-- return;
--
-- if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
-- (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
-- else
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
-- (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
--
-- ieee80211_queue_delayed_work(sc->hw,
-- &sc->ath_led_blink_work,
-- (sc->sc_flags & SC_OP_LED_ON) ?
-- msecs_to_jiffies(sc->led_off_duration) :
-- msecs_to_jiffies(sc->led_on_duration));
--
-- sc->led_on_duration = sc->led_on_cnt ?
-- max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
-- ATH_LED_ON_DURATION_IDLE;
-- sc->led_off_duration = sc->led_off_cnt ?
-- max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
-- ATH_LED_OFF_DURATION_IDLE;
-- sc->led_on_cnt = sc->led_off_cnt = 0;
-- if (sc->sc_flags & SC_OP_LED_ON)
-- sc->sc_flags &= ~SC_OP_LED_ON;
-- else
-- sc->sc_flags |= SC_OP_LED_ON;
--}
--
-+#ifdef CONFIG_MAC80211_LEDS
- static void ath_led_brightness(struct led_classdev *led_cdev,
- enum led_brightness brightness)
- {
-- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
-- struct ath_softc *sc = led->sc;
--
-- switch (brightness) {
-- case LED_OFF:
-- if (led->led_type == ATH_LED_ASSOC ||
-- led->led_type == ATH_LED_RADIO) {
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
-- (led->led_type == ATH_LED_RADIO));
-- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-- if (led->led_type == ATH_LED_RADIO)
-- sc->sc_flags &= ~SC_OP_LED_ON;
-- } else {
-- sc->led_off_cnt++;
-- }
-- break;
-- case LED_FULL:
-- if (led->led_type == ATH_LED_ASSOC) {
-- sc->sc_flags |= SC_OP_LED_ASSOCIATED;
-- if (led_blink)
-- ieee80211_queue_delayed_work(sc->hw,
-- &sc->ath_led_blink_work, 0);
-- } else if (led->led_type == ATH_LED_RADIO) {
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
-- sc->sc_flags |= SC_OP_LED_ON;
-- } else {
-- sc->led_on_cnt++;
-- }
-- break;
-- default:
-- break;
-- }
--}
--
--static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
-- char *trigger)
--{
-- int ret;
--
-- led->sc = sc;
-- led->led_cdev.name = led->name;
-- led->led_cdev.default_trigger = trigger;
-- led->led_cdev.brightness_set = ath_led_brightness;
--
-- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
-- if (ret)
-- ath_err(ath9k_hw_common(sc->sc_ah),
-- "Failed to register led:%s", led->name);
-- else
-- led->registered = 1;
-- return ret;
--}
--
--static void ath_unregister_led(struct ath_led *led)
--{
-- if (led->registered) {
-- led_classdev_unregister(&led->led_cdev);
-- led->registered = 0;
-- }
-+ struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
-+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
- }
-
- void ath_deinit_leds(struct ath_softc *sc)
- {
-- if (AR_SREV_9100(sc->sc_ah))
-+ if (!sc->led_registered)
- return;
-
-- ath_unregister_led(&sc->assoc_led);
-- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-- ath_unregister_led(&sc->tx_led);
-- ath_unregister_led(&sc->rx_led);
-- ath_unregister_led(&sc->radio_led);
-- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-+ ath_led_brightness(&sc->led_cdev, LED_OFF);
-+ led_classdev_unregister(&sc->led_cdev);
- }
-
- void ath_init_leds(struct ath_softc *sc)
- {
-- char *trigger;
- int ret;
-
- if (AR_SREV_9100(sc->sc_ah))
-@@ -152,48 +57,22 @@ void ath_init_leds(struct ath_softc *sc)
- /* LED off, active low */
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-
-- if (led_blink)
-- INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
-+ if (!led_blink)
-+ sc->led_cdev.default_trigger =
-+ ieee80211_get_radio_led_name(sc->hw);
-+
-+ snprintf(sc->led_name, sizeof(sc->led_name),
-+ "ath9k-%s", wiphy_name(sc->hw->wiphy));
-+ sc->led_cdev.name = sc->led_name;
-+ sc->led_cdev.brightness_set = ath_led_brightness;
-+
-+ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
-+ if (ret < 0)
-+ return;
-
-- trigger = ieee80211_get_radio_led_name(sc->hw);
-- snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
-- "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
-- ret = ath_register_led(sc, &sc->radio_led, trigger);
-- sc->radio_led.led_type = ATH_LED_RADIO;
-- if (ret)
-- goto fail;
--
-- trigger = ieee80211_get_assoc_led_name(sc->hw);
-- snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
-- "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
-- ret = ath_register_led(sc, &sc->assoc_led, trigger);
-- sc->assoc_led.led_type = ATH_LED_ASSOC;
-- if (ret)
-- goto fail;
--
-- trigger = ieee80211_get_tx_led_name(sc->hw);
-- snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
-- "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
-- ret = ath_register_led(sc, &sc->tx_led, trigger);
-- sc->tx_led.led_type = ATH_LED_TX;
-- if (ret)
-- goto fail;
--
-- trigger = ieee80211_get_rx_led_name(sc->hw);
-- snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
-- "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
-- ret = ath_register_led(sc, &sc->rx_led, trigger);
-- sc->rx_led.led_type = ATH_LED_RX;
-- if (ret)
-- goto fail;
--
-- return;
--
--fail:
-- if (led_blink)
-- cancel_delayed_work_sync(&sc->ath_led_blink_work);
-- ath_deinit_leds(sc);
-+ sc->led_registered = true;
- }
-+#endif
-
- /*******************/
- /* Rfkill */
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1216,9 +1216,6 @@ static void ath9k_stop(struct ieee80211_
-
- mutex_lock(&sc->mutex);
-
-- if (led_blink)
-- cancel_delayed_work_sync(&sc->ath_led_blink_work);
--
- cancel_delayed_work_sync(&sc->tx_complete_work);
- cancel_delayed_work_sync(&sc->hw_pll_work);
- cancel_work_sync(&sc->paprd_work);
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -141,6 +141,21 @@ static struct ieee80211_rate ath9k_legac
- RATE(540, 0x0c, 0),
- };
-
-+#ifdef CONFIG_MAC80211_LEDS
-+static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
-+ { .throughput = 0 * 1024, .blink_time = 334 },
-+ { .throughput = 1 * 1024, .blink_time = 260 },
-+ { .throughput = 5 * 1024, .blink_time = 220 },
-+ { .throughput = 10 * 1024, .blink_time = 190 },
-+ { .throughput = 20 * 1024, .blink_time = 170 },
-+ { .throughput = 50 * 1024, .blink_time = 150 },
-+ { .throughput = 70 * 1024, .blink_time = 130 },
-+ { .throughput = 100 * 1024, .blink_time = 110 },
-+ { .throughput = 200 * 1024, .blink_time = 80 },
-+ { .throughput = 300 * 1024, .blink_time = 50 },
-+};
-+#endif
-+
- static void ath9k_deinit_softc(struct ath_softc *sc);
-
- /*
-@@ -742,6 +757,13 @@ int ath9k_init_device(u16 devid, struct
-
- ath9k_init_txpower_limits(sc);
-
-+#ifdef CONFIG_MAC80211_LEDS
-+ /* must be initialized before ieee80211_register_hw */
-+ sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
-+ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
-+ ARRAY_SIZE(ath9k_tpt_blink));
-+#endif
-+
- /* Register with mac80211 */
- error = ieee80211_register_hw(hw);
- if (error)
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1466,8 +1466,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- REG_WRITE(ah, AR_OBS, 8);
-
- if (ah->config.rx_intr_mitigation) {
-- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
-- REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
-+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);
-+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 500);
- }
-
- if (ah->config.tx_intr_mitigation) {
--- /dev/null
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -2216,6 +2216,18 @@ static inline int ieee80211_sta_ps_trans
+ #define IEEE80211_TX_STATUS_HEADROOM 13
+
+ /**
++ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
++ *
++ * If a driver buffers frames for a powersave station instead of passing
++ * them back to mac80211 for retransmission, the station needs to be told
++ * to wake up using the TIM bitmap in the beacon.
++ *
++ * This function sets the station's TIM bit - it will be cleared when the
++ * station wakes up.
++ */
++void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
++
++/**
+ * ieee80211_tx_status - transmit status callback
+ *
+ * Call this function for all transmitted frames after they have been
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -608,7 +608,8 @@ static bool sta_info_cleanup_expire_buff
+ #endif
+ dev_kfree_skb(skb);
+
+- if (skb_queue_empty(&sta->ps_tx_buf))
++ if (skb_queue_empty(&sta->ps_tx_buf) &&
++ !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
+ sta_info_clear_tim_bit(sta);
+ }
+
+@@ -899,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
+ struct ieee80211_local *local = sdata->local;
+ int sent, buffered;
+
++ clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+ if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
+ drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
+
+@@ -991,3 +993,12 @@ void ieee80211_sta_block_awake(struct ie
+ ieee80211_queue_work(hw, &sta->drv_unblock_wk);
+ }
+ EXPORT_SYMBOL(ieee80211_sta_block_awake);
++
++void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
++{
++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
++
++ set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
++ sta_info_set_tim_bit(sta);
++}
++EXPORT_SYMBOL(ieee80211_sta_set_tim);
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -43,6 +43,8 @@
+ * be in the queues
+ * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
+ * station in power-save mode, reply when the driver unblocks.
++ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
++ * buffers. Automatically cleared on station wake-up.
+ */
+ enum ieee80211_sta_info_flags {
+ WLAN_STA_AUTH = 1<<0,
+@@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags {
+ WLAN_STA_BLOCK_BA = 1<<11,
+ WLAN_STA_PS_DRIVER = 1<<12,
+ WLAN_STA_PSPOLL = 1<<13,
++ WLAN_STA_PS_DRIVER_BUF = 1<<14,
+ };
+
+ #define STA_TID_NUM 16
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -202,6 +202,7 @@ struct ath_atx_ac {
+ int sched;
+ struct list_head list;
+ struct list_head tid_q;
++ bool clear_ps_filter;
+ };
+
+ struct ath_frame_info {
+@@ -259,6 +260,8 @@ struct ath_node {
+ struct ath_atx_ac ac[WME_NUM_AC];
+ u16 maxampdu;
+ u8 mpdudensity;
++
++ bool sleeping;
+ };
+
+ #define AGGR_CLEANUP BIT(1)
+@@ -340,6 +343,9 @@ int ath_tx_aggr_start(struct ath_softc *
+ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+
++void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
++bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
++
+ /********/
+ /* VIFs */
+ /********/
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1791,6 +1791,27 @@ static int ath9k_sta_remove(struct ieee8
+ return 0;
+ }
+
++static void ath9k_sta_notify(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ enum sta_notify_cmd cmd,
++ struct ieee80211_sta *sta)
++{
++ struct ath_softc *sc = hw->priv;
++ struct ath_node *an = (struct ath_node *) sta->drv_priv;
++
++ switch (cmd) {
++ case STA_NOTIFY_SLEEP:
++ an->sleeping = true;
++ if (ath_tx_aggr_sleep(sc, an))
++ ieee80211_sta_set_tim(sta);
++ break;
++ case STA_NOTIFY_AWAKE:
++ an->sleeping = false;
++ ath_tx_aggr_wakeup(sc, an);
++ break;
++ }
++}
++
+ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+ {
+@@ -2177,6 +2198,7 @@ struct ieee80211_ops ath9k_ops = {
+ .configure_filter = ath9k_configure_filter,
+ .sta_add = ath9k_sta_add,
+ .sta_remove = ath9k_sta_remove,
++ .sta_notify = ath9k_sta_notify,
+ .conf_tx = ath9k_conf_tx,
+ .bss_info_changed = ath9k_bss_info_changed,
+ .set_key = ath9k_set_key,
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct
+ struct ath_frame_info *fi;
+ int nframes;
+ u8 tidno;
++ bool clear_filter;
+
+ skb = bf->bf_mpdu;
+ hdr = (struct ieee80211_hdr *)skb->data;
+@@ -442,7 +443,11 @@ static void ath_tx_complete_aggr(struct
+ acked_cnt++;
+ } else {
+ if (!(tid->state & AGGR_CLEANUP) && retry) {
+- if (fi->retries < ATH_MAX_SW_RETRIES) {
++ if (ts->ts_status & ATH9K_TXERR_FILT) {
++ if (!an->sleeping)
++ clear_filter = true;
++ txpending = 1;
++ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
+ ath_tx_set_retry(sc, txq, bf->bf_mpdu);
+ txpending = 1;
+ } else {
+@@ -496,6 +501,7 @@ static void ath_tx_complete_aggr(struct
+ !txfail, sendbar);
+ } else {
+ /* retry the un-acked ones */
++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
+ if (bf->bf_next == NULL && bf_last->bf_stale) {
+ struct ath_buf *tbf;
+@@ -546,7 +552,12 @@ static void ath_tx_complete_aggr(struct
+
+ /* prepend un-acked frames to the beginning of the pending frame queue */
+ if (!list_empty(&bf_pending)) {
++ if (an->sleeping)
++ ieee80211_sta_set_tim(sta);
++
+ spin_lock_bh(&txq->axq_lock);
++ if (clear_filter)
++ tid->ac->clear_ps_filter = true;
+ list_splice(&bf_pending, &tid->buf_q);
+ ath_tx_queue_tid(txq, tid);
+ spin_unlock_bh(&txq->axq_lock);
+@@ -816,6 +827,11 @@ static void ath_tx_sched_aggr(struct ath
+ bf = list_first_entry(&bf_q, struct ath_buf, list);
+ bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
+
++ if (tid->ac->clear_ps_filter) {
++ tid->ac->clear_ps_filter = false;
++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
++ }
++
+ /* if only one frame, send as non-aggregate */
+ if (bf == bf->bf_lastbf) {
+ fi = get_frame_info(bf->bf_mpdu);
+@@ -896,6 +912,67 @@ void ath_tx_aggr_stop(struct ath_softc *
+ ath_tx_flush_tid(sc, txtid);
+ }
+
++bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
++{
++ struct ath_atx_tid *tid;
++ struct ath_atx_ac *ac;
++ struct ath_txq *txq;
++ bool buffered = false;
++ int tidno;
++
++ for (tidno = 0, tid = &an->tid[tidno];
++ tidno < WME_NUM_TID; tidno++, tid++) {
++
++ if (!tid->sched)
++ continue;
++
++ ac = tid->ac;
++ txq = ac->txq;
++
++ spin_lock_bh(&txq->axq_lock);
++
++ if (!list_empty(&tid->buf_q))
++ buffered = true;
++
++ tid->sched = false;
++ list_del(&tid->list);
++
++ if (ac->sched) {
++ ac->sched = false;
++ list_del(&ac->list);
++ }
++
++ spin_unlock_bh(&txq->axq_lock);
++ }
++
++ return buffered;
++}
++
++void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
++{
++ struct ath_atx_tid *tid;
++ struct ath_atx_ac *ac;
++ struct ath_txq *txq;
++ int tidno;
++
++ for (tidno = 0, tid = &an->tid[tidno];
++ tidno < WME_NUM_TID; tidno++, tid++) {
++
++ ac = tid->ac;
++ txq = ac->txq;
++
++ spin_lock_bh(&txq->axq_lock);
++ ac->clear_ps_filter = true;
++
++ if (!list_empty(&tid->buf_q) && !tid->paused) {
++ ath_tx_queue_tid(txq, tid);
++ ath_txq_schedule(sc, txq);
++ }
++
++ spin_unlock_bh(&txq->axq_lock);
++ }
++}
++
+ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+ {
+ struct ath_atx_tid *txtid;
+@@ -1491,7 +1568,6 @@ static int setup_tx_flags(struct sk_buff
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ int flags = 0;
+
+- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+ flags |= ATH9K_TXDESC_INTREQ;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+@@ -1754,6 +1830,9 @@ static void ath_tx_start_dma(struct ath_
+ if (txctl->paprd)
+ bf->bf_state.bfs_paprd_timestamp = jiffies;
+
++ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
++ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
++
+ ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -128,6 +128,11 @@ static inline void ath9k_hw_set11n_virtu
+ ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
+ }
+
++static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
++{
++ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
++}
++
+ /* Private hardware call ops */
+
+ /* PHY ops */
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -642,6 +642,7 @@ struct ath_hw_ops {
+ u32 burstDuration);
+ void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
+ u32 vmf);
++ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
+ };
+
+ struct ath_nf_limits {
+--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(stru
+ | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(txPower, AR_XmitPower)
+ | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+ | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(stru
+ }
+ }
+
++static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
++{
++ struct ar5416_desc *ads = AR5416DESC(ds);
++
++ if (val)
++ ads->ds_ctl0 |= AR_ClrDestMask;
++ else
++ ads->ds_ctl0 &= ~AR_ClrDestMask;
++}
++
+ static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+ void *lastds,
+ u32 durUpdateEn, u32 rtsctsRate,
+@@ -460,4 +469,5 @@ void ar9002_hw_attach_mac_ops(struct ath
+ ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
+ ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
+ ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
++ ops->set_clrdmask = ar9002_hw_set_clrdmask;
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(stru
+ | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(txpower, AR_XmitPower)
+ | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
+ | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
+
+@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(stru
+ ads->ctl22 = 0;
+ }
+
++static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
++{
++ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
++
++ if (val)
++ ads->ctl11 |= AR_ClrDestMask;
++ else
++ ads->ctl11 &= ~AR_ClrDestMask;
++}
++
+ static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+ void *lastds,
+ u32 durUpdateEn, u32 rtsctsRate,
+@@ -522,6 +531,7 @@ void ar9003_hw_attach_mac_ops(struct ath
+ ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
+ ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
+ ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
++ ops->set_clrdmask = ar9003_hw_set_clrdmask;
+ }
+
+ void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -239,7 +239,6 @@ struct ath_desc {
+ void *ds_vdata;
+ } __packed __aligned(4);
+
+-#define ATH9K_TXDESC_CLRDMASK 0x0001
+ #define ATH9K_TXDESC_NOACK 0x0002
+ #define ATH9K_TXDESC_RTSENA 0x0004
+ #define ATH9K_TXDESC_CTSENA 0x0008
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -2223,33 +2223,6 @@ static void ath_tx_complete_poll_work(st
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+- } else {
+- /* If the queue has pending buffers, then it
+- * should be doing tx work (and have axq_depth).
+- * Shouldn't get to this state I think..but
+- * we do.
+- */
+- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
+- (txq->pending_frames > 0 ||
+- !list_empty(&txq->axq_acq) ||
+- txq->stopped)) {
+- ath_err(ath9k_hw_common(sc->sc_ah),
+- "txq: %p axq_qnum: %u,"
+- " mac80211_qnum: %i"
+- " axq_link: %p"
+- " pending frames: %i"
+- " axq_acq empty: %i"
+- " stopped: %i"
+- " axq_depth: 0 Attempting to"
+- " restart tx logic.\n",
+- txq, txq->axq_qnum,
+- txq->mac80211_qnum,
+- txq->axq_link,
+- txq->pending_frames,
+- list_empty(&txq->axq_acq),
+- txq->stopped);
+- ath_txq_schedule(sc, txq);
+- }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+++ /dev/null
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -2209,6 +2209,18 @@ static inline int ieee80211_sta_ps_trans
- #define IEEE80211_TX_STATUS_HEADROOM 13
-
- /**
-+ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
-+ *
-+ * If a driver buffers frames for a powersave station instead of passing
-+ * them back to mac80211 for retransmission, the station needs to be told
-+ * to wake up using the TIM bitmap in the beacon.
-+ *
-+ * This function sets the station's TIM bit - it will be cleared when the
-+ * station wakes up.
-+ */
-+void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
-+
-+/**
- * ieee80211_tx_status - transmit status callback
- *
- * Call this function for all transmitted frames after they have been
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -608,7 +608,8 @@ static bool sta_info_cleanup_expire_buff
- #endif
- dev_kfree_skb(skb);
-
-- if (skb_queue_empty(&sta->ps_tx_buf))
-+ if (skb_queue_empty(&sta->ps_tx_buf) &&
-+ !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
- sta_info_clear_tim_bit(sta);
- }
-
-@@ -899,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
- struct ieee80211_local *local = sdata->local;
- int sent, buffered;
-
-+ clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
- if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
- drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
-
-@@ -991,3 +993,12 @@ void ieee80211_sta_block_awake(struct ie
- ieee80211_queue_work(hw, &sta->drv_unblock_wk);
- }
- EXPORT_SYMBOL(ieee80211_sta_block_awake);
-+
-+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
-+{
-+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
-+
-+ set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
-+ sta_info_set_tim_bit(sta);
-+}
-+EXPORT_SYMBOL(ieee80211_sta_set_tim);
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -43,6 +43,8 @@
- * be in the queues
- * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
- * station in power-save mode, reply when the driver unblocks.
-+ * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
-+ * buffers. Automatically cleared on station wake-up.
- */
- enum ieee80211_sta_info_flags {
- WLAN_STA_AUTH = 1<<0,
-@@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags {
- WLAN_STA_BLOCK_BA = 1<<11,
- WLAN_STA_PS_DRIVER = 1<<12,
- WLAN_STA_PSPOLL = 1<<13,
-+ WLAN_STA_PS_DRIVER_BUF = 1<<14,
- };
-
- #define STA_TID_NUM 16
--- /dev/null
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1582,7 +1582,7 @@ ieee80211_drop_unencrypted_mgmt(struct i
+ }
+
+ static int
+-__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
++__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
+ {
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+@@ -1590,6 +1590,7 @@ __ieee80211_data_to_8023(struct ieee8021
+ struct ethhdr *ehdr;
+ int ret;
+
++ *port_control = false;
+ if (ieee80211_has_a4(hdr->frame_control) &&
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
+ return -1;
+@@ -1608,11 +1609,14 @@ __ieee80211_data_to_8023(struct ieee8021
+ return -1;
+
+ ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
+- if (ret < 0 || !check_port_control)
++ if (ret < 0)
+ return ret;
+
+ ehdr = (struct ethhdr *) rx->skb->data;
+- if (ehdr->h_proto != rx->sdata->control_port_protocol)
++ if (ehdr->h_proto == rx->sdata->control_port_protocol)
++ *port_control = true;
++
++ if (check_port_control && !*port_control)
+ return -1;
+
+ return 0;
+@@ -1913,6 +1917,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+ struct net_device *dev = sdata->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+ __le16 fc = hdr->frame_control;
++ bool port_control;
+ int err;
+
+ if (unlikely(!ieee80211_is_data(hdr->frame_control)))
+@@ -1929,13 +1934,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+ sdata->vif.type == NL80211_IFTYPE_AP)
+ return RX_DROP_MONITOR;
+
+- err = __ieee80211_data_to_8023(rx);
++ err = __ieee80211_data_to_8023(rx, &port_control);
+ if (unlikely(err))
+ return RX_DROP_UNUSABLE;
+
+ if (!ieee80211_frame_allowed(rx, fc))
+ return RX_DROP_MONITOR;
+
++ if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
++ unlikely(port_control) && sdata->bss) {
++ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
++ u.ap);
++ dev = sdata->dev;
++ rx->sdata = sdata;
++ }
++
+ rx->skb->dev = dev;
+
+ dev->stats.rx_packets++;
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -203,6 +203,7 @@ struct ath_atx_ac {
- int sched;
- struct list_head list;
- struct list_head tid_q;
-+ bool clear_ps_filter;
- };
-
- struct ath_frame_info {
-@@ -260,6 +261,8 @@ struct ath_node {
- struct ath_atx_ac ac[WME_NUM_AC];
- u16 maxampdu;
- u8 mpdudensity;
-+
-+ bool sleeping;
- };
-
- #define AGGR_CLEANUP BIT(1)
-@@ -341,6 +344,9 @@ int ath_tx_aggr_start(struct ath_softc *
- void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
- void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-
-+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
-+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
-+
- /********/
- /* VIFs */
- /********/
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1791,6 +1791,27 @@ static int ath9k_sta_remove(struct ieee8
- return 0;
- }
-
-+static void ath9k_sta_notify(struct ieee80211_hw *hw,
-+ struct ieee80211_vif *vif,
-+ enum sta_notify_cmd cmd,
-+ struct ieee80211_sta *sta)
-+{
-+ struct ath_softc *sc = hw->priv;
-+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
-+
-+ switch (cmd) {
-+ case STA_NOTIFY_SLEEP:
-+ an->sleeping = true;
-+ if (ath_tx_aggr_sleep(sc, an))
-+ ieee80211_sta_set_tim(sta);
-+ break;
-+ case STA_NOTIFY_AWAKE:
-+ an->sleeping = false;
-+ ath_tx_aggr_wakeup(sc, an);
-+ break;
-+ }
-+}
-+
- static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
- {
-@@ -2191,6 +2212,7 @@ struct ieee80211_ops ath9k_ops = {
- .configure_filter = ath9k_configure_filter,
- .sta_add = ath9k_sta_add,
- .sta_remove = ath9k_sta_remove,
-+ .sta_notify = ath9k_sta_notify,
- .conf_tx = ath9k_conf_tx,
- .bss_info_changed = ath9k_bss_info_changed,
- .set_key = ath9k_set_key,
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct
- struct ath_frame_info *fi;
- int nframes;
- u8 tidno;
-+ bool clear_filter;
-
- skb = bf->bf_mpdu;
- hdr = (struct ieee80211_hdr *)skb->data;
-@@ -442,7 +443,11 @@ static void ath_tx_complete_aggr(struct
- acked_cnt++;
- } else {
- if (!(tid->state & AGGR_CLEANUP) && retry) {
-- if (fi->retries < ATH_MAX_SW_RETRIES) {
-+ if (ts->ts_status & ATH9K_TXERR_FILT) {
-+ if (!an->sleeping)
-+ clear_filter = true;
-+ txpending = 1;
-+ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, txq, bf->bf_mpdu);
- txpending = 1;
- } else {
-@@ -496,6 +501,7 @@ static void ath_tx_complete_aggr(struct
- !txfail, sendbar);
- } else {
- /* retry the un-acked ones */
-+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
- if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
- if (bf->bf_next == NULL && bf_last->bf_stale) {
- struct ath_buf *tbf;
-@@ -546,7 +552,12 @@ static void ath_tx_complete_aggr(struct
-
- /* prepend un-acked frames to the beginning of the pending frame queue */
- if (!list_empty(&bf_pending)) {
-+ if (an->sleeping)
-+ ieee80211_sta_set_tim(sta);
-+
- spin_lock_bh(&txq->axq_lock);
-+ if (clear_filter)
-+ tid->ac->clear_ps_filter = true;
- list_splice(&bf_pending, &tid->buf_q);
- ath_tx_queue_tid(txq, tid);
- spin_unlock_bh(&txq->axq_lock);
-@@ -816,6 +827,11 @@ static void ath_tx_sched_aggr(struct ath
- bf = list_first_entry(&bf_q, struct ath_buf, list);
- bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
-
-+ if (tid->ac->clear_ps_filter) {
-+ tid->ac->clear_ps_filter = false;
-+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
-+ }
-+
- /* if only one frame, send as non-aggregate */
- if (bf == bf->bf_lastbf) {
- fi = get_frame_info(bf->bf_mpdu);
-@@ -896,6 +912,67 @@ void ath_tx_aggr_stop(struct ath_softc *
- ath_tx_flush_tid(sc, txtid);
- }
-
-+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
-+{
-+ struct ath_atx_tid *tid;
-+ struct ath_atx_ac *ac;
-+ struct ath_txq *txq;
-+ bool buffered = false;
-+ int tidno;
-+
-+ for (tidno = 0, tid = &an->tid[tidno];
-+ tidno < WME_NUM_TID; tidno++, tid++) {
-+
-+ if (!tid->sched)
-+ continue;
-+
-+ ac = tid->ac;
-+ txq = ac->txq;
-+
-+ spin_lock_bh(&txq->axq_lock);
-+
-+ if (!list_empty(&tid->buf_q))
-+ buffered = true;
-+
-+ tid->sched = false;
-+ list_del(&tid->list);
-+
-+ if (ac->sched) {
-+ ac->sched = false;
-+ list_del(&ac->list);
-+ }
-+
-+ spin_unlock_bh(&txq->axq_lock);
-+ }
-+
-+ return buffered;
-+}
-+
-+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
-+{
-+ struct ath_atx_tid *tid;
-+ struct ath_atx_ac *ac;
-+ struct ath_txq *txq;
-+ int tidno;
-+
-+ for (tidno = 0, tid = &an->tid[tidno];
-+ tidno < WME_NUM_TID; tidno++, tid++) {
-+
-+ ac = tid->ac;
-+ txq = ac->txq;
-+
-+ spin_lock_bh(&txq->axq_lock);
-+ ac->clear_ps_filter = true;
-+
-+ if (!list_empty(&tid->buf_q) && !tid->paused) {
-+ ath_tx_queue_tid(txq, tid);
-+ ath_txq_schedule(sc, txq);
-+ }
-+
-+ spin_unlock_bh(&txq->axq_lock);
-+ }
-+}
-+
- void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
- {
- struct ath_atx_tid *txtid;
-@@ -1493,7 +1570,6 @@ static int setup_tx_flags(struct sk_buff
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- int flags = 0;
-
-- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
- flags |= ATH9K_TXDESC_INTREQ;
-
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
-@@ -1756,6 +1832,9 @@ static void ath_tx_start_dma(struct ath_
- if (txctl->paprd)
- bf->bf_state.bfs_paprd_timestamp = jiffies;
-
-+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
-+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
-+
- ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
- }
-
---- a/drivers/net/wireless/ath/ath9k/hw-ops.h
-+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
-@@ -128,6 +128,11 @@ static inline void ath9k_hw_set11n_virtu
- ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
- }
-
-+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-+{
-+ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
-+}
-+
- /* Private hardware call ops */
-
- /* PHY ops */
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -642,6 +642,7 @@ struct ath_hw_ops {
- u32 burstDuration);
- void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
- u32 vmf);
-+ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
- };
-
- struct ath_nf_limits {
---- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(stru
- | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(txPower, AR_XmitPower)
- | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
- | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
- | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
-@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(stru
- }
- }
-
-+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-+{
-+ struct ar5416_desc *ads = AR5416DESC(ds);
-+
-+ if (val)
-+ ads->ds_ctl0 |= AR_ClrDestMask;
-+ else
-+ ads->ds_ctl0 &= ~AR_ClrDestMask;
-+}
-+
- static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
-@@ -460,4 +469,5 @@ void ar9002_hw_attach_mac_ops(struct ath
- ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
- ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
-+ ops->set_clrdmask = ar9002_hw_set_clrdmask;
- }
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(stru
- | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(txpower, AR_XmitPower)
- | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
- | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
- | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
-
-@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(stru
- ads->ctl22 = 0;
- }
-
-+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-+{
-+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-+
-+ if (val)
-+ ads->ctl11 |= AR_ClrDestMask;
-+ else
-+ ads->ctl11 &= ~AR_ClrDestMask;
-+}
-+
- static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
-@@ -522,6 +531,7 @@ void ar9003_hw_attach_mac_ops(struct ath
- ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
- ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
-+ ops->set_clrdmask = ar9003_hw_set_clrdmask;
- }
-
- void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
---- a/drivers/net/wireless/ath/ath9k/mac.h
-+++ b/drivers/net/wireless/ath/ath9k/mac.h
-@@ -239,7 +239,6 @@ struct ath_desc {
- void *ds_vdata;
- } __packed __aligned(4);
-
--#define ATH9K_TXDESC_CLRDMASK 0x0001
- #define ATH9K_TXDESC_NOACK 0x0002
- #define ATH9K_TXDESC_RTSENA 0x0004
- #define ATH9K_TXDESC_CTSENA 0x0008
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -2226,33 +2226,6 @@ static void ath_tx_complete_poll_work(st
- } else {
- txq->axq_tx_inprogress = true;
- }
-- } else {
-- /* If the queue has pending buffers, then it
-- * should be doing tx work (and have axq_depth).
-- * Shouldn't get to this state I think..but
-- * we do.
-- */
-- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
-- (txq->pending_frames > 0 ||
-- !list_empty(&txq->axq_acq) ||
-- txq->stopped)) {
-- ath_err(ath9k_hw_common(sc->sc_ah),
-- "txq: %p axq_qnum: %u,"
-- " mac80211_qnum: %i"
-- " axq_link: %p"
-- " pending frames: %i"
-- " axq_acq empty: %i"
-- " stopped: %i"
-- " axq_depth: 0 Attempting to"
-- " restart tx logic.\n",
-- txq, txq->axq_qnum,
-- txq->mac80211_qnum,
-- txq->axq_link,
-- txq->pending_frames,
-- list_empty(&txq->axq_acq),
-- txq->stopped);
-- ath_txq_schedule(sc, txq);
-- }
- }
- spin_unlock_bh(&txq->axq_lock);
- }
+++ /dev/null
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -414,7 +414,7 @@ struct station_parameters {
- * @STATION_INFO_PLID: @plid filled
- * @STATION_INFO_PLINK_STATE: @plink_state filled
- * @STATION_INFO_SIGNAL: @signal filled
-- * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
-+ * @STATION_INFO_TX_BITRATE: @txrate fields are filled
- * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
- * @STATION_INFO_RX_PACKETS: @rx_packets filled
- * @STATION_INFO_TX_PACKETS: @tx_packets filled
-@@ -422,6 +422,7 @@ struct station_parameters {
- * @STATION_INFO_TX_FAILED: @tx_failed filled
- * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
- * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
-+ * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
- */
- enum station_info_flags {
- STATION_INFO_INACTIVE_TIME = 1<<0,
-@@ -438,6 +439,7 @@ enum station_info_flags {
- STATION_INFO_TX_FAILED = 1<<11,
- STATION_INFO_RX_DROP_MISC = 1<<12,
- STATION_INFO_SIGNAL_AVG = 1<<13,
-+ STATION_INFO_RX_BITRATE = 1<<14,
- };
-
- /**
-@@ -507,6 +509,7 @@ struct station_info {
- s8 signal;
- s8 signal_avg;
- struct rate_info txrate;
-+ struct rate_info rxrate;
- u32 rx_packets;
- u32 tx_packets;
- u32 tx_retries;
---- a/include/linux/nl80211.h
-+++ b/include/linux/nl80211.h
-@@ -1243,6 +1243,8 @@ enum nl80211_rate_info {
- * @NL80211_STA_INFO_LLID: the station's mesh LLID
- * @NL80211_STA_INFO_PLID: the station's mesh PLID
- * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
-+ * @NL80211_STA_INFO_RX_BITRATE: last unicast rx rate, nested attribute
-+ * containing info as possible, see &enum nl80211_sta_info_txrate.
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
- */
-@@ -1261,6 +1263,7 @@ enum nl80211_sta_info {
- NL80211_STA_INFO_TX_RETRIES,
- NL80211_STA_INFO_TX_FAILED,
- NL80211_STA_INFO_SIGNAL_AVG,
-+ NL80211_STA_INFO_RX_BITRATE,
-
- /* keep last */
- __NL80211_STA_INFO_AFTER_LAST,
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -1968,13 +1968,41 @@ static int parse_station_flags(struct ge
- return 0;
- }
-
-+static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
-+ int attr)
-+{
-+ struct nlattr *rate;
-+ u16 bitrate;
-+
-+ rate = nla_nest_start(msg, attr);
-+ if (!rate)
-+ goto nla_put_failure;
-+
-+ /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
-+ bitrate = cfg80211_calculate_bitrate(info);
-+ if (bitrate > 0)
-+ NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
-+
-+ if (info->flags & RATE_INFO_FLAGS_MCS)
-+ NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
-+ if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
-+ NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
-+ if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
-+ NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
-+
-+ nla_nest_end(msg, rate);
-+ return true;
-+
-+nla_put_failure:
-+ return false;
-+}
-+
- static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
- int flags, struct net_device *dev,
- const u8 *mac_addr, struct station_info *sinfo)
- {
- void *hdr;
-- struct nlattr *sinfoattr, *txrate;
-- u16 bitrate;
-+ struct nlattr *sinfoattr;
-
- hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
- if (!hdr)
-@@ -2013,24 +2041,14 @@ static int nl80211_send_station(struct s
- NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG,
- sinfo->signal_avg);
- if (sinfo->filled & STATION_INFO_TX_BITRATE) {
-- txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
-- if (!txrate)
-+ if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
-+ NL80211_STA_INFO_TX_BITRATE))
-+ goto nla_put_failure;
-+ }
-+ if (sinfo->filled & STATION_INFO_RX_BITRATE) {
-+ if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
-+ NL80211_STA_INFO_RX_BITRATE))
- goto nla_put_failure;
--
-- /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
-- bitrate = cfg80211_calculate_bitrate(&sinfo->txrate);
-- if (bitrate > 0)
-- NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
--
-- if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
-- NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
-- sinfo->txrate.mcs);
-- if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
-- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
-- if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
-- NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
--
-- nla_nest_end(msg, txrate);
- }
- if (sinfo->filled & STATION_INFO_RX_PACKETS)
- NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -212,6 +212,8 @@ enum plink_state {
- * @rate_ctrl_priv: rate control private per-STA pointer
- * @last_tx_rate: rate used for last transmit, to report to userspace as
- * "the" transmit rate
-+ * @last_rx_rate_idx: rx status rate index of the last data packet
-+ * @last_rx_rate_flag: rx status flag of the last data packet
- * @lock: used for locking all fields that require locking, see comments
- * in the header file.
- * @flaglock: spinlock for flags accesses
-@@ -314,6 +316,8 @@ struct sta_info {
- unsigned long tx_bytes;
- unsigned long tx_fragments;
- struct ieee80211_tx_rate last_tx_rate;
-+ int last_rx_rate_idx;
-+ int last_rx_rate_flag;
- u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
-
- /*
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1156,14 +1156,23 @@ ieee80211_rx_h_sta_process(struct ieee80
- if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
- NL80211_IFTYPE_ADHOC);
-- if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
-+ if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) {
- sta->last_rx = jiffies;
-+ if (ieee80211_is_data(hdr->frame_control)) {
-+ sta->last_rx_rate_idx = status->rate_idx;
-+ sta->last_rx_rate_flag = status->flag;
-+ }
-+ }
- } else if (!is_multicast_ether_addr(hdr->addr1)) {
- /*
- * Mesh beacons will update last_rx when if they are found to
- * match the current local configuration when processed.
- */
- sta->last_rx = jiffies;
-+ if (ieee80211_is_data(hdr->frame_control)) {
-+ sta->last_rx_rate_idx = status->rate_idx;
-+ sta->last_rx_rate_flag = status->flag;
-+ }
- }
-
- if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -316,6 +316,17 @@ static int ieee80211_config_default_mgmt
- return 0;
- }
-
-+static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
-+{
-+ if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
-+ struct ieee80211_supported_band *sband;
-+ sband = sta->local->hw.wiphy->bands[
-+ sta->local->hw.conf.channel->band];
-+ rate->legacy = sband->bitrates[idx].bitrate;
-+ } else
-+ rate->mcs = idx;
-+}
-+
- static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
- {
- struct ieee80211_sub_if_data *sdata = sta->sdata;
-@@ -330,6 +341,7 @@ static void sta_set_sinfo(struct sta_inf
- STATION_INFO_TX_RETRIES |
- STATION_INFO_TX_FAILED |
- STATION_INFO_TX_BITRATE |
-+ STATION_INFO_RX_BITRATE |
- STATION_INFO_RX_DROP_MISC;
-
- sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
-@@ -355,15 +367,16 @@ static void sta_set_sinfo(struct sta_inf
- sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
- if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
- sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-+ rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx);
-
-- if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
-- struct ieee80211_supported_band *sband;
-- sband = sta->local->hw.wiphy->bands[
-- sta->local->hw.conf.channel->band];
-- sinfo->txrate.legacy =
-- sband->bitrates[sta->last_tx_rate.idx].bitrate;
-- } else
-- sinfo->txrate.mcs = sta->last_tx_rate.idx;
-+ sinfo->rxrate.flags = 0;
-+ if (sta->last_rx_rate_flag & RX_FLAG_HT)
-+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
-+ if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
-+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
-+ if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
-+ sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-+ rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
-
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- #ifdef CONFIG_MAC80211_MESH
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -413,9 +413,7 @@ u32 ath_calcrxfilter(struct ath_softc *s
- * mode interface or when in monitor mode. AP mode does not need this
- * since it receives all in-BSS frames anyway.
- */
-- if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
-- (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
-- (sc->sc_ah->is_monitoring))
-+ if (sc->sc_ah->is_monitoring)
- rfilt |= ATH9K_RX_FILTER_PROM;
-
- if (sc->rx.rxfilter & FIF_CONTROL)
+++ /dev/null
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -415,10 +415,8 @@ minstrel_ht_tx_status(void *priv, struct
- mi->sample_count--;
- }
-
-- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
-+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
- mi->sample_packets += info->status.ampdu_len;
-- minstrel_next_sample_idx(mi);
-- }
-
- for (i = 0; !last; i++) {
- last = (i == IEEE80211_TX_MAX_RATES - 1) ||
-@@ -553,13 +551,14 @@ minstrel_get_sample_rate(struct minstrel
- sample_idx = sample_table[mg->column][mg->index];
- mr = &mg->rates[sample_idx];
- sample_idx += mi->sample_group * MCS_GROUP_RATES;
-+ minstrel_next_sample_idx(mi);
-
- /*
- * When not using MRR, do not sample if the probability is already
- * higher than 95% to avoid wasting airtime
- */
- if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
-- goto next;
-+ return -1;
-
- /*
- * Make sure that lower rates get sampled only occasionally,
-@@ -568,17 +567,13 @@ minstrel_get_sample_rate(struct minstrel
- if (minstrel_get_duration(sample_idx) >
- minstrel_get_duration(mi->max_tp_rate)) {
- if (mr->sample_skipped < 20)
-- goto next;
-+ return -1;
-
- if (mi->sample_slow++ > 2)
-- goto next;
-+ return -1;
- }
-
- return sample_idx;
--
--next:
-- minstrel_next_sample_idx(mi);
-- return -1;
- }
-
- static void
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -95,9 +95,9 @@
- #define REG_READ_FIELD(_a, _r, _f) \
- (((REG_READ(_a, _r) & _f) >> _f##_S))
- #define REG_SET_BIT(_a, _r, _f) \
-- REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
-+ REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f))
- #define REG_CLR_BIT(_a, _r, _f) \
-- REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
-+ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f))
-
- #define DO_DELAY(x) do { \
- if ((++(x) % 64) == 0) \
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -1271,16 +1271,14 @@ bool ath_drain_all_txq(struct ath_softc
- if (sc->sc_flags & SC_OP_INVALID)
- return true;
-
-- /* Stop beacon queue */
-- ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
-+ ath9k_hw_abort_tx_dma(ah);
-
-- /* Stop data queues */
-+ /* Check if any queue remains active */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- if (ATH_TXQ_SETUP(sc, i)) {
-- txq = &sc->tx.txq[i];
-- ath9k_hw_stoptxdma(ah, txq->axq_qnum);
-- npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
-- }
-+ if (!ATH_TXQ_SETUP(sc, i))
-+ continue;
-+
-+ npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
- }
-
- if (npend)
---- a/drivers/net/wireless/ath/ath9k/mac.c
-+++ b/drivers/net/wireless/ath/ath9k/mac.c
-@@ -143,6 +143,34 @@ bool ath9k_hw_updatetxtriglevel(struct a
- }
- EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
-
-+void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
-+{
-+ int i, q;
-+
-+ REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
-+
-+ REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
-+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
-+ REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
-+
-+ for (q = 0; q < AR_NUM_QCU; q++) {
-+ for (i = 0; i < 1000; i++) {
-+ if (i)
-+ udelay(5);
-+
-+ if (!ath9k_hw_numtxpending(ah, q))
-+ break;
-+ }
-+ }
-+
-+ REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
-+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
-+ REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
-+
-+ REG_WRITE(ah, AR_Q_TXD, 0);
-+}
-+EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
-+
- bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
- {
- #define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
---- a/drivers/net/wireless/ath/ath9k/mac.h
-+++ b/drivers/net/wireless/ath/ath9k/mac.h
-@@ -676,6 +676,7 @@ void ath9k_hw_cleartxdesc(struct ath_hw
- u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
- bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
- bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
-+void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
- void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
- bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
- const struct ath9k_tx_queue_info *qinfo);
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -2149,56 +2149,42 @@ static void ath9k_set_coverage_class(str
-
- static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
- {
--#define ATH_FLUSH_TIMEOUT 60 /* ms */
- struct ath_softc *sc = hw->priv;
-- struct ath_txq *txq = NULL;
-- struct ath_hw *ah = sc->sc_ah;
-- struct ath_common *common = ath9k_hw_common(ah);
-- int i, j, npend = 0;
-+ int timeout = 200; /* ms */
-+ int i, j;
-
-+ ath9k_ps_wakeup(sc);
- mutex_lock(&sc->mutex);
-
- cancel_delayed_work_sync(&sc->tx_complete_work);
-
-- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- if (!ATH_TXQ_SETUP(sc, i))
-- continue;
-- txq = &sc->tx.txq[i];
--
-- if (!drop) {
-- for (j = 0; j < ATH_FLUSH_TIMEOUT; j++) {
-- if (!ath9k_has_pending_frames(sc, txq))
-- break;
-- usleep_range(1000, 2000);
-- }
-- }
-+ if (drop)
-+ timeout = 1;
-+
-+ for (j = 0; j < timeout; j++) {
-+ int npend = 0;
-+
-+ if (j)
-+ usleep_range(1000, 2000);
-
-- if (drop || ath9k_has_pending_frames(sc, txq)) {
-- ath_dbg(common, ATH_DBG_QUEUE, "Drop frames from hw queue:%d\n",
-- txq->axq_qnum);
-- spin_lock_bh(&txq->axq_lock);
-- txq->txq_flush_inprogress = true;
-- spin_unlock_bh(&txq->axq_lock);
--
-- ath9k_ps_wakeup(sc);
-- ath9k_hw_stoptxdma(ah, txq->axq_qnum);
-- npend = ath9k_hw_numtxpending(ah, txq->axq_qnum);
-- ath9k_ps_restore(sc);
-- if (npend)
-- break;
-+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-+ if (!ATH_TXQ_SETUP(sc, i))
-+ continue;
-
-- ath_draintxq(sc, txq, false);
-- txq->txq_flush_inprogress = false;
-+ npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
- }
-+
-+ if (!npend)
-+ goto out;
- }
-
-- if (npend) {
-+ if (!ath_drain_all_txq(sc, false))
- ath_reset(sc, false);
-- txq->txq_flush_inprogress = false;
-- }
-
-+out:
- ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
- mutex_unlock(&sc->mutex);
-+ ath9k_ps_restore(sc);
- }
-
- struct ieee80211_ops ath9k_ops = {
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -189,7 +189,6 @@ struct ath_txq {
- u32 axq_ampdu_depth;
- bool stopped;
- bool axq_tx_inprogress;
-- bool txq_flush_inprogress;
- struct list_head axq_acq;
- struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
- struct list_head txq_fifo_pending;
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -2091,8 +2091,7 @@ static void ath_tx_processq(struct ath_s
- spin_lock_bh(&txq->axq_lock);
- if (list_empty(&txq->axq_q)) {
- txq->axq_link = NULL;
-- if (sc->sc_flags & SC_OP_TXAGGR &&
-- !txq->txq_flush_inprogress)
-+ if (sc->sc_flags & SC_OP_TXAGGR)
- ath_txq_schedule(sc, txq);
- spin_unlock_bh(&txq->axq_lock);
- break;
-@@ -2173,7 +2172,7 @@ static void ath_tx_processq(struct ath_s
-
- spin_lock_bh(&txq->axq_lock);
-
-- if (sc->sc_flags & SC_OP_TXAGGR && !txq->txq_flush_inprogress)
-+ if (sc->sc_flags & SC_OP_TXAGGR)
- ath_txq_schedule(sc, txq);
- spin_unlock_bh(&txq->axq_lock);
- }
-@@ -2317,18 +2316,17 @@ void ath_tx_edma_tasklet(struct ath_soft
-
- spin_lock_bh(&txq->axq_lock);
-
-- if (!txq->txq_flush_inprogress) {
-- if (!list_empty(&txq->txq_fifo_pending)) {
-- INIT_LIST_HEAD(&bf_head);
-- bf = list_first_entry(&txq->txq_fifo_pending,
-- struct ath_buf, list);
-- list_cut_position(&bf_head,
-- &txq->txq_fifo_pending,
-- &bf->bf_lastbf->list);
-- ath_tx_txqaddbuf(sc, txq, &bf_head);
-- } else if (sc->sc_flags & SC_OP_TXAGGR)
-- ath_txq_schedule(sc, txq);
-- }
-+ if (!list_empty(&txq->txq_fifo_pending)) {
-+ INIT_LIST_HEAD(&bf_head);
-+ bf = list_first_entry(&txq->txq_fifo_pending,
-+ struct ath_buf, list);
-+ list_cut_position(&bf_head,
-+ &txq->txq_fifo_pending,
-+ &bf->bf_lastbf->list);
-+ ath_tx_txqaddbuf(sc, txq, &bf_head);
-+ } else if (sc->sc_flags & SC_OP_TXAGGR)
-+ ath_txq_schedule(sc, txq);
-+
- spin_unlock_bh(&txq->axq_lock);
- }
- }
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/mac.c
-+++ b/drivers/net/wireless/ath/ath9k/mac.c
-@@ -171,84 +171,31 @@ void ath9k_hw_abort_tx_dma(struct ath_hw
- }
- EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
-
--bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
-+bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
- {
--#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
-+#define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */
- #define ATH9K_TIME_QUANTUM 100 /* usec */
-- struct ath_common *common = ath9k_hw_common(ah);
-- struct ath9k_hw_capabilities *pCap = &ah->caps;
-- struct ath9k_tx_queue_info *qi;
-- u32 tsfLow, j, wait;
-- u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
--
-- if (q >= pCap->total_queues) {
-- ath_dbg(common, ATH_DBG_QUEUE,
-- "Stopping TX DMA, invalid queue: %u\n", q);
-- return false;
-- }
--
-- qi = &ah->txq[q];
-- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-- ath_dbg(common, ATH_DBG_QUEUE,
-- "Stopping TX DMA, inactive queue: %u\n", q);
-- return false;
-- }
-+ int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
-+ int wait;
-
- REG_WRITE(ah, AR_Q_TXD, 1 << q);
-
- for (wait = wait_time; wait != 0; wait--) {
-- if (ath9k_hw_numtxpending(ah, q) == 0)
-- break;
-- udelay(ATH9K_TIME_QUANTUM);
-- }
--
-- if (ath9k_hw_numtxpending(ah, q)) {
-- ath_dbg(common, ATH_DBG_QUEUE,
-- "%s: Num of pending TX Frames %d on Q %d\n",
-- __func__, ath9k_hw_numtxpending(ah, q), q);
--
-- for (j = 0; j < 2; j++) {
-- tsfLow = REG_READ(ah, AR_TSF_L32);
-- REG_WRITE(ah, AR_QUIET2,
-- SM(10, AR_QUIET2_QUIET_DUR));
-- REG_WRITE(ah, AR_QUIET_PERIOD, 100);
-- REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
-- REG_SET_BIT(ah, AR_TIMER_MODE,
-- AR_QUIET_TIMER_EN);
--
-- if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
-- break;
--
-- ath_dbg(common, ATH_DBG_QUEUE,
-- "TSF has moved while trying to set quiet time TSF: 0x%08x\n",
-- tsfLow);
-- }
--
-- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
--
-- udelay(200);
-- REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
--
-- wait = wait_time;
-- while (ath9k_hw_numtxpending(ah, q)) {
-- if ((--wait) == 0) {
-- ath_err(common,
-- "Failed to stop TX DMA in 100 msec after killing last frame\n");
-- break;
-- }
-+ if (wait != wait_time)
- udelay(ATH9K_TIME_QUANTUM);
-- }
-
-- REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
-+ if (ath9k_hw_numtxpending(ah, q) == 0)
-+ break;
- }
-
- REG_WRITE(ah, AR_Q_TXD, 0);
-+
- return wait != 0;
-
- #undef ATH9K_TX_STOP_DMA_TIMEOUT
- #undef ATH9K_TIME_QUANTUM
- }
--EXPORT_SYMBOL(ath9k_hw_stoptxdma);
-+EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
-
- void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
- {
---- a/drivers/net/wireless/ath/ath9k/mac.h
-+++ b/drivers/net/wireless/ath/ath9k/mac.h
-@@ -675,7 +675,7 @@ void ath9k_hw_txstart(struct ath_hw *ah,
- void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
- u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
- bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
--bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
-+bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
- void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
- void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
- bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -373,6 +373,7 @@ void ath_beacon_tasklet(unsigned long da
- ath_dbg(common, ATH_DBG_BSTUCK,
- "missed %u consecutive beacons\n",
- sc->beacon.bmisscnt);
-+ ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
- ath9k_hw_bstuck_nfcal(ah);
- } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
- ath_dbg(common, ATH_DBG_BSTUCK,
-@@ -450,16 +451,6 @@ void ath_beacon_tasklet(unsigned long da
- sc->beacon.updateslot = OK;
- }
- if (bfaddr != 0) {
-- /*
-- * Stop any current dma and put the new frame(s) on the queue.
-- * This should never fail since we check above that no frames
-- * are still pending on the queue.
-- */
-- if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
-- ath_err(common, "beacon queue %u did not stop?\n",
-- sc->beacon.beaconq);
-- }
--
- /* NB: cabq traffic should already be queued and primed */
- ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
- ath9k_hw_txstart(ah, sc->beacon.beaconq);
-@@ -780,7 +771,7 @@ void ath9k_set_beaconing_status(struct a
- ah->imask &= ~ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
- tasklet_kill(&sc->bcon_tasklet);
-- ath9k_hw_stoptxdma(ah, sc->beacon.beaconq);
-+ ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
- }
- ath9k_ps_restore(sc);
- }
+++ /dev/null
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1582,7 +1582,7 @@ ieee80211_drop_unencrypted_mgmt(struct i
- }
-
- static int
--__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
-+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
- {
- struct ieee80211_sub_if_data *sdata = rx->sdata;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-@@ -1590,6 +1590,7 @@ __ieee80211_data_to_8023(struct ieee8021
- struct ethhdr *ehdr;
- int ret;
-
-+ *port_control = false;
- if (ieee80211_has_a4(hdr->frame_control) &&
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
- return -1;
-@@ -1608,11 +1609,14 @@ __ieee80211_data_to_8023(struct ieee8021
- return -1;
-
- ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
-- if (ret < 0 || !check_port_control)
-+ if (ret < 0)
- return ret;
-
- ehdr = (struct ethhdr *) rx->skb->data;
-- if (ehdr->h_proto != rx->sdata->control_port_protocol)
-+ if (ehdr->h_proto == rx->sdata->control_port_protocol)
-+ *port_control = true;
-+
-+ if (check_port_control && !*port_control)
- return -1;
-
- return 0;
-@@ -1913,6 +1917,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- struct net_device *dev = sdata->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- __le16 fc = hdr->frame_control;
-+ bool port_control;
- int err;
-
- if (unlikely(!ieee80211_is_data(hdr->frame_control)))
-@@ -1929,13 +1934,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- sdata->vif.type == NL80211_IFTYPE_AP)
- return RX_DROP_MONITOR;
-
-- err = __ieee80211_data_to_8023(rx);
-+ err = __ieee80211_data_to_8023(rx, &port_control);
- if (unlikely(err))
- return RX_DROP_UNUSABLE;
-
- if (!ieee80211_frame_allowed(rx, fc))
- return RX_DROP_MONITOR;
-
-+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-+ unlikely(port_control) && sdata->bss) {
-+ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
-+ u.ap);
-+ dev = sdata->dev;
-+ rx->sdata = sdata;
-+ }
-+
- rx->skb->dev = dev;
-
- dev->stats.rx_packets++;
+++ /dev/null
---- a/net/mac80211/chan.c
-+++ b/net/mac80211/chan.c
-@@ -77,6 +77,9 @@ bool ieee80211_set_channel_type(struct i
- switch (tmp->vif.bss_conf.channel_type) {
- case NL80211_CHAN_NO_HT:
- case NL80211_CHAN_HT20:
-+ if (superchan > tmp->vif.bss_conf.channel_type)
-+ break;
-+
- superchan = tmp->vif.bss_conf.channel_type;
- break;
- case NL80211_CHAN_HT40PLUS:
+++ /dev/null
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -166,7 +166,7 @@ static void ath_tx_flush_tid(struct ath_
- fi = get_frame_info(bf->bf_mpdu);
- if (fi->retries) {
- ath_tx_update_baw(sc, tid, fi->seqno);
-- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
-+ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
- } else {
- ath_tx_send_normal(sc, txq, NULL, &bf_head);
- }
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
-@@ -4502,6 +4502,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+@@ -4500,6 +4500,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+++ /dev/null
---- a/drivers/net/wireless/p54/eeprom.c
-+++ b/drivers/net/wireless/p54/eeprom.c
-@@ -524,10 +524,13 @@ err_data:
-
- struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
- {
-- struct p54_rssi_db_entry *entry = (void *)(priv->rssi_db->data +
-- priv->rssi_db->offset);
-+ struct p54_rssi_db_entry *entry;
- int i, found = -1;
-
-+ if (!priv->rssi_db)
-+ return &p54_rssi_default;
-+
-+ entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
- for (i = 0; i < priv->rssi_db->entries; i++) {
- if (!same_band(freq, entry[i].freq))
- continue;
+++ /dev/null
-Index: compat-wireless-2011-02-25/net/mac80211/main.c
-===================================================================
---- compat-wireless-2011-02-25.orig/net/mac80211/main.c 2011-03-07 12:58:14.996968980 +0100
-+++ compat-wireless-2011-02-25/net/mac80211/main.c 2011-03-07 13:03:26.732273903 +0100
-@@ -384,6 +384,9 @@ void ieee80211_restart_hw(struct ieee802
-
- trace_api_restart_hw(local);
-
-+ wiphy_info(hw->wiphy,
-+ "Hardware restart was requested\n");
-+
- /* use this reason, ieee80211_reconfig will unblock it */
- ieee80211_stop_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+++ /dev/null
-Index: compat-wireless-2011-02-25/net/mac80211/scan.c
-===================================================================
---- compat-wireless-2011-02-25.orig/net/mac80211/scan.c 2011-03-07 14:43:55.695666042 +0100
-+++ compat-wireless-2011-02-25/net/mac80211/scan.c 2011-03-07 14:43:57.594439631 +0100
-@@ -258,10 +258,12 @@ static bool ieee80211_prep_hw_scan(struc
- return true;
- }
-
--static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
-+static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
- bool was_hw_scan)
- {
- struct ieee80211_local *local = hw_to_local(hw);
-+ bool on_oper_chan;
-+ bool enable_beacons = false;
-
- lockdep_assert_held(&local->mtx);
-
-@@ -275,12 +277,12 @@ static bool __ieee80211_scan_completed(s
- aborted = true;
-
- if (WARN_ON(!local->scan_req))
-- return false;
-+ return;
-
- if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
- int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
- if (rc == 0)
-- return false;
-+ return;
- }
-
- kfree(local->hw_scan_req);
-@@ -294,26 +296,13 @@ static bool __ieee80211_scan_completed(s
- local->scanning = 0;
- local->scan_channel = NULL;
-
-- return true;
--}
--
--static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
-- bool was_hw_scan)
--{
-- struct ieee80211_local *local = hw_to_local(hw);
-- bool on_oper_chan;
-- bool enable_beacons = false;
--
-- mutex_lock(&local->mtx);
- on_oper_chan = ieee80211_cfg_on_oper_channel(local);
-
- WARN_ON(local->scanning & (SCAN_SW_SCANNING | SCAN_HW_SCANNING));
-
-- if (was_hw_scan || !on_oper_chan) {
-- if (WARN_ON(local->scan_channel))
-- local->scan_channel = NULL;
-+ if (was_hw_scan || !on_oper_chan)
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-- } else
-+ else
- /* Set power back to normal operating levels. */
- ieee80211_hw_config(local, 0);
-
-@@ -331,7 +320,6 @@ static void __ieee80211_scan_completed_f
- }
-
- ieee80211_recalc_idle(local);
-- mutex_unlock(&local->mtx);
-
- ieee80211_mlme_notify_scan_completed(local);
- ieee80211_ibss_notify_scan_completed(local);
-@@ -686,12 +674,14 @@ void ieee80211_scan_work(struct work_str
- {
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local, scan_work.work);
-- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-+ struct ieee80211_sub_if_data *sdata;
- unsigned long next_delay = 0;
-- bool aborted, hw_scan, finish;
-+ bool aborted, hw_scan;
-
- mutex_lock(&local->mtx);
-
-+ sdata = local->scan_sdata;
-+
- if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
- aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
- goto out_complete;
-@@ -755,17 +745,11 @@ void ieee80211_scan_work(struct work_str
- } while (next_delay == 0);
-
- ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
-- mutex_unlock(&local->mtx);
-- return;
-+ goto out;
-
- out_complete:
- hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
-- finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
-- mutex_unlock(&local->mtx);
-- if (finish)
-- __ieee80211_scan_completed_finish(&local->hw, hw_scan);
-- return;
--
-+ __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
- out:
- mutex_unlock(&local->mtx);
- }
-@@ -835,7 +819,6 @@ int ieee80211_request_internal_scan(stru
- void ieee80211_scan_cancel(struct ieee80211_local *local)
- {
- bool abortscan;
-- bool finish = false;
-
- /*
- * We are only canceling software scan, or deferred scan that was not
-@@ -855,14 +838,17 @@ void ieee80211_scan_cancel(struct ieee80
-
- mutex_lock(&local->mtx);
- abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
-- if (abortscan)
-- finish = __ieee80211_scan_completed(&local->hw, true, false);
-- mutex_unlock(&local->mtx);
--
- if (abortscan) {
-- /* The scan is canceled, but stop work from being pending */
-- cancel_delayed_work_sync(&local->scan_work);
-+ /*
-+ * The scan is canceled, but stop work from being pending.
-+ *
-+ * If the work is currently running, it must be blocked on
-+ * the mutex, but we'll set scan_sdata = NULL and it'll
-+ * simply exit once it acquires the mutex.
-+ */
-+ cancel_delayed_work(&local->scan_work);
-+ /* and clean up */
-+ __ieee80211_scan_completed(&local->hw, true, false);
- }
-- if (finish)
-- __ieee80211_scan_completed_finish(&local->hw, false);
-+ mutex_unlock(&local->mtx);
- }