]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 8 Dec 2010 21:23:31 +0000 (16:23 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 8 Dec 2010 21:23:31 +0000 (16:23 -0500)
Conflicts:
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c

13 files changed:
1  2 
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/orinoco/wext.c
net/mac80211/tx.c

index bccea7450c384d34151f7db5a65a22209f5596ae,42ed923cdb1aad9479be7ed5f68a2b40c665ffcb..4e3b97c3d7c2de5a7b0cdb096af5e370a44426ac
@@@ -47,6 -47,8 +47,6 @@@
  #include <linux/io.h>
  #include <linux/netdevice.h>
  #include <linux/cache.h>
 -#include <linux/pci.h>
 -#include <linux/pci-aspm.h>
  #include <linux/ethtool.h>
  #include <linux/uaccess.h>
  #include <linux/slab.h>
@@@ -60,6 -62,7 +60,6 @@@
  #include "reg.h"
  #include "debug.h"
  #include "ani.h"
 -#include "../debug.h"
  
  static int modparam_nohwcrypt;
  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
@@@ -75,25 -78,39 +75,25 @@@ MODULE_AUTHOR("Nick Kossifidis")
  MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
  MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
  MODULE_LICENSE("Dual BSD/GPL");
 -MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
  
 -static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
 +static int ath5k_init(struct ieee80211_hw *hw);
 +static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
 +                                                              bool skip_pcu);
  static int ath5k_beacon_update(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif);
  static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
  
 -/* Known PCI ids */
 -static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
 -      { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
 -      { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
 -      { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
 -      { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
 -      { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
 -      { PCI_VDEVICE(3COM_2,  0x0013) }, /* 3com 5212 */
 -      { PCI_VDEVICE(3COM,    0x0013) }, /* 3com 3CRDAG675 5212 */
 -      { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
 -      { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
 -      { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
 -      { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
 -      { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
 -      { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
 -      { 0 }
 -};
 -MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
 -
  /* 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 },
        { "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 },
        { "2112B",      AR5K_VERSION_RAD,       AR5K_SREV_RAD_2112B },
        { "2413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2413 },
        { "5413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5413 },
 -      { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
 -      { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
        { "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 },
  };
  
@@@ -183,8 -197,8 +183,8 @@@ static inline void ath5k_txbuf_free_skb
        BUG_ON(!bf);
        if (!bf->skb)
                return;
 -      pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
 -                      PCI_DMA_TODEVICE);
 +      dma_unmap_single(sc->dev, bf->skbaddr, bf->skb->len,
 +                      DMA_TO_DEVICE);
        dev_kfree_skb_any(bf->skb);
        bf->skb = NULL;
        bf->skbaddr = 0;
@@@ -200,8 -214,8 +200,8 @@@ static inline void ath5k_rxbuf_free_skb
        BUG_ON(!bf);
        if (!bf->skb)
                return;
 -      pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
 -                      PCI_DMA_FROMDEVICE);
 +      dma_unmap_single(sc->dev, bf->skbaddr, common->rx_bufsize,
 +                      DMA_FROM_DEVICE);
        dev_kfree_skb_any(bf->skb);
        bf->skb = NULL;
        bf->skbaddr = 0;
@@@ -219,7 -233,7 +219,7 @@@ static inline u64 ath5k_extend_tsf(stru
        return (tsf & ~0x7fff) | rstamp;
  }
  
 -static const char *
 +const char *
  ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
  {
        const char *name = "xxxxx";
@@@ -313,12 -327,14 +313,12 @@@ ath5k_copy_channels(struct ath5k_hw *ah
  
        switch (mode) {
        case AR5K_MODE_11A:
 -      case AR5K_MODE_11A_TURBO:
                /* 1..220, but 2GHz frequencies are filtered by check_channel */
                size = 220 ;
                chfreq = CHANNEL_5GHZ;
                break;
        case AR5K_MODE_11B:
        case AR5K_MODE_11G:
 -      case AR5K_MODE_11G_TURBO:
                size = 26;
                chfreq = CHANNEL_2GHZ;
                break;
                case AR5K_MODE_11G:
                        channels[count].hw_value = chfreq | CHANNEL_OFDM;
                        break;
 -              case AR5K_MODE_11A_TURBO:
 -              case AR5K_MODE_11G_TURBO:
 -                      channels[count].hw_value = chfreq |
 -                              CHANNEL_OFDM | CHANNEL_TURBO;
 -                      break;
                case AR5K_MODE_11B:
                        channels[count].hw_value = CHANNEL_B;
                }
@@@ -475,7 -496,7 +475,7 @@@ ath5k_chan_set(struct ath5k_softc *sc, 
         * hardware at the new frequency, and then re-enable
         * the relevant bits of the h/w.
         */
 -      return ath5k_reset(sc, chan);
 +      return ath5k_reset(sc, chan, true);
  }
  
  static void
@@@ -528,7 -549,7 +528,7 @@@ static void ath_vif_iter(void *data, u
        /* Calculate combined mode - when APs are active, operate in AP mode.
         * Otherwise use the mode of the new interface. This can currently
         * only deal with combinations of APs and STAs. Only one ad-hoc
 -       * interfaces is allowed above.
 +       * interfaces is allowed.
         */
        if (avf->opmode == NL80211_IFTYPE_AP)
                iter_data->opmode = NL80211_IFTYPE_AP;
                        iter_data->opmode = avf->opmode;
  }
  
 -static void ath_do_set_opmode(struct ath5k_softc *sc)
 -{
 -      struct ath5k_hw *ah = sc->ah;
 -      ath5k_hw_set_opmode(ah, sc->opmode);
 -      ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n",
 -                sc->opmode, ath_opmode_to_string(sc->opmode));
 -}
 -
 -void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
 -                                      struct ieee80211_vif *vif)
 +static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
 +                                             struct ieee80211_vif *vif)
  {
        struct ath_common *common = ath5k_hw_common(sc->ah);
        struct ath_vif_iter_data iter_data;
                /* Nothing active, default to station mode */
                sc->opmode = NL80211_IFTYPE_STATION;
  
 -      ath_do_set_opmode(sc);
 +      ath5k_hw_set_opmode(sc->ah, sc->opmode);
 +      ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n",
 +                sc->opmode, ath_opmode_to_string(sc->opmode));
  
        if (iter_data.need_set_hw_addr && iter_data.found_active)
                ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac);
@@@ -632,11 -659,10 +632,11 @@@ struct sk_buff *ath5k_rx_skb_alloc(stru
                return NULL;
        }
  
 -      *skb_addr = pci_map_single(sc->pdev,
 +      *skb_addr = dma_map_single(sc->dev,
                                   skb->data, common->rx_bufsize,
 -                                 PCI_DMA_FROMDEVICE);
 -      if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
 +                                 DMA_FROM_DEVICE);
 +
 +      if (unlikely(dma_mapping_error(sc->dev, *skb_addr))) {
                ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
                dev_kfree_skb(skb);
                return NULL;
@@@ -732,8 -758,8 +732,8 @@@ ath5k_txbuf_setup(struct ath5k_softc *s
        flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
  
        /* XXX endianness */
 -      bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
 -                      PCI_DMA_TODEVICE);
 +      bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
 +                      DMA_TO_DEVICE);
  
        rate = ieee80211_get_tx_rate(sc->hw, info);
        if (!rate) {
  
        return 0;
  err_unmap:
 -      pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
 +      dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
        return ret;
  }
  
  \*******************/
  
  static int
 -ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
 +ath5k_desc_alloc(struct ath5k_softc *sc)
  {
        struct ath5k_desc *ds;
        struct ath5k_buf *bf;
        /* allocate descriptors */
        sc->desc_len = sizeof(struct ath5k_desc) *
                        (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
 -      sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
 +
 +      sc->desc = dma_alloc_coherent(sc->dev, sc->desc_len,
 +                              &sc->desc_daddr, GFP_KERNEL);
        if (sc->desc == NULL) {
                ATH5K_ERR(sc, "can't allocate descriptors\n");
                ret = -ENOMEM;
  
        return 0;
  err_free:
 -      pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
 +      dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
  err:
        sc->desc = NULL;
        return ret;
  }
  
  static void
 -ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
 +ath5k_desc_free(struct ath5k_softc *sc)
  {
        struct ath5k_buf *bf;
  
                ath5k_txbuf_free_skb(sc, bf);
  
        /* Free memory associated with all descriptors */
 -      pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
 +      dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
        sc->desc = NULL;
        sc->desc_daddr = 0;
  
        return ret;
  }
  
 +/**
 + * ath5k_drain_tx_buffs - Empty tx buffers
 + *
 + * @sc The &struct ath5k_softc
 + *
 + * Empty tx buffers from all queues in preparation
 + * of a reset or during shutdown.
 + *
 + * NB:        this assumes output has been stopped and
 + *    we do not need to block ath5k_tx_tasklet
 + */
  static void
 -ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
 +ath5k_drain_tx_buffs(struct ath5k_softc *sc)
  {
 +      struct ath5k_txq *txq;
        struct ath5k_buf *bf, *bf0;
 +      int i;
  
 -      /*
 -       * NB: this assumes output has been stopped and
 -       *     we do not need to block ath5k_tx_tasklet
 -       */
 -      spin_lock_bh(&txq->lock);
 -      list_for_each_entry_safe(bf, bf0, &txq->q, list) {
 -              ath5k_debug_printtxbuf(sc, bf);
 -
 -              ath5k_txbuf_free_skb(sc, bf);
 -
 -              spin_lock_bh(&sc->txbuflock);
 -              list_move_tail(&bf->list, &sc->txbuf);
 -              sc->txbuf_len++;
 -              txq->txq_len--;
 -              spin_unlock_bh(&sc->txbuflock);
 -      }
 -      txq->link = NULL;
 -      txq->txq_poll_mark = false;
 -      spin_unlock_bh(&txq->lock);
 -}
 +      for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
 +              if (sc->txqs[i].setup) {
 +                      txq = &sc->txqs[i];
 +                      spin_lock_bh(&txq->lock);
 +                      list_for_each_entry_safe(bf, bf0, &txq->q, list) {
 +                              ath5k_debug_printtxbuf(sc, bf);
  
 -/*
 - * Drain the transmit queues and reclaim resources.
 - */
 -static void
 -ath5k_txq_cleanup(struct ath5k_softc *sc)
 -{
 -      struct ath5k_hw *ah = sc->ah;
 -      unsigned int i;
 +                              ath5k_txbuf_free_skb(sc, bf);
  
 -      /* XXX return value */
 -      if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
 -              /* don't touch the hardware if marked invalid */
 -              ath5k_hw_stop_tx_dma(ah, sc->bhalq);
 -              ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
 -                      ath5k_hw_get_txdp(ah, sc->bhalq));
 -              for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
 -                      if (sc->txqs[i].setup) {
 -                              ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
 -                              ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
 -                                      "link %p\n",
 -                                      sc->txqs[i].qnum,
 -                                      ath5k_hw_get_txdp(ah,
 -                                                      sc->txqs[i].qnum),
 -                                      sc->txqs[i].link);
 +                              spin_lock_bh(&sc->txbuflock);
 +                              list_move_tail(&bf->list, &sc->txbuf);
 +                              sc->txbuf_len++;
 +                              txq->txq_len--;
 +                              spin_unlock_bh(&sc->txbuflock);
                        }
 +                      txq->link = NULL;
 +                      txq->txq_poll_mark = false;
 +                      spin_unlock_bh(&txq->lock);
 +              }
        }
 -
 -      for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
 -              if (sc->txqs[i].setup)
 -                      ath5k_txq_drainq(sc, &sc->txqs[i]);
  }
  
  static void
  }
  
  /*
 - * Disable the receive h/w in preparation for a reset.
 + * Disable the receive logic on PCU (DRU)
 + * In preparation for a shutdown.
 + *
 + * Note: Doesn't stop rx DMA, ath5k_hw_dma_stop
 + * does.
   */
  static void
  ath5k_rx_stop(struct ath5k_softc *sc)
  {
        struct ath5k_hw *ah = sc->ah;
  
 -      ath5k_hw_stop_rx_pcu(ah);       /* disable PCU */
        ath5k_hw_set_rx_filter(ah, 0);  /* clear recv filter */
 -      ath5k_hw_stop_rx_dma(ah);       /* disable DMA engine */
 +      ath5k_hw_stop_rx_pcu(ah);       /* disable PCU */
  
        ath5k_debug_printrxbuffs(sc, ah);
  }
@@@ -1268,7 -1307,8 +1268,7 @@@ ath5k_update_beacon_rssi(struct ath5k_s
            memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
                return;
  
 -      ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg,
 -                                                    rssi);
 +      ewma_add(&ah->ah_beacon_rssi_avg, rssi);
  
        /* in IBSS mode we should keep RSSI statistics per neighbour */
        /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
@@@ -1511,9 -1551,9 +1511,9 @@@ ath5k_tasklet_rx(unsigned long data
                        if (!next_skb)
                                goto next;
  
 -                      pci_unmap_single(sc->pdev, bf->skbaddr,
 +                      dma_unmap_single(sc->dev, bf->skbaddr,
                                         common->rx_bufsize,
 -                                       PCI_DMA_FROMDEVICE);
 +                                       DMA_FROM_DEVICE);
  
                        skb_put(skb, rs.rs_datalen);
  
@@@ -1676,9 -1716,8 +1676,9 @@@ ath5k_tx_processq(struct ath5k_softc *s
  
                        skb = bf->skb;
                        bf->skb = NULL;
 -                      pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
 -                                      PCI_DMA_TODEVICE);
 +
 +                      dma_unmap_single(sc->dev, bf->skbaddr, skb->len,
 +                                      DMA_TO_DEVICE);
                        ath5k_tx_frame_completed(sc, skb, &ts);
                }
  
@@@ -1732,13 -1771,12 +1732,13 @@@ ath5k_beacon_setup(struct ath5k_softc *
        u32 flags;
        const int padsize = 0;
  
 -      bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
 -                      PCI_DMA_TODEVICE);
 +      bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
 +                      DMA_TO_DEVICE);
        ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
                        "skbaddr %llx\n", skb, skb->data, skb->len,
                        (unsigned long long)bf->skbaddr);
 -      if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) {
 +
 +      if (dma_mapping_error(sc->dev, bf->skbaddr)) {
                ATH5K_ERR(sc, "beacon DMA mapping failed\n");
                return -EIO;
        }
  
        return 0;
  err_unmap:
 -      pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
 +      dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
        return ret;
  }
  
@@@ -1879,7 -1917,8 +1879,8 @@@ ath5k_beacon_send(struct ath5k_softc *s
                sc->bmisscount = 0;
        }
  
-       if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) {
+       if ((sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) ||
+                       sc->opmode == NL80211_IFTYPE_MESH_POINT) {
                u64 tsf = ath5k_hw_get_tsf64(ah);
                u32 tsftu = TSF_TO_TU(tsf);
                int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval;
         * This should never fail since we check above that no frames
         * are still pending on the queue.
         */
 -      if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
 +      if (unlikely(ath5k_hw_stop_beacon_queue(ah, sc->bhalq))) {
                ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq);
                /* NB: hw still stops DMA, so proceed */
        }
  
-       /* refresh the beacon for AP mode */
-       if (sc->opmode == NL80211_IFTYPE_AP)
+       /* refresh the beacon for AP or MESH mode */
+       if (sc->opmode == NL80211_IFTYPE_AP ||
+                       sc->opmode == NL80211_IFTYPE_MESH_POINT)
                ath5k_beacon_update(sc->hw, vif);
  
        ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
@@@ -2075,7 -2115,7 +2077,7 @@@ ath5k_beacon_config(struct ath5k_softc 
                } else
                        ath5k_beacon_update_timers(sc, -1);
        } else {
 -              ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
 +              ath5k_hw_stop_beacon_queue(sc->ah, sc->bhalq);
        }
  
        ath5k_hw_set_imr(ah, sc->imask);
@@@ -2137,7 -2177,7 +2139,7 @@@ ath5k_intr_calibration_poll(struct ath5
         * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
  }
  
 -static irqreturn_t
 +irqreturn_t
  ath5k_intr(int irq, void *dev_id)
  {
        struct ath5k_softc *sc = dev_id;
        unsigned int counter = 1000;
  
        if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
 -                              !ath5k_hw_is_intr_pending(ah)))
 +              ((ath5k_get_bus_type(ah) != ATH_AHB) &&
 +                              !ath5k_hw_is_intr_pending(ah))))
                return IRQ_NONE;
  
        do {
                                tasklet_schedule(&sc->rf_kill.toggleq);
  
                }
 +
 +              if (ath5k_get_bus_type(ah) == ATH_AHB)
 +                      break;
 +
        } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
  
        if (unlikely(!counter))
@@@ -2316,7 -2351,7 +2318,7 @@@ ath5k_tx_complete_poll_work(struct work
        if (needreset) {
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                          "TX queues stuck, resetting\n");
 -              ath5k_reset(sc, sc->curchan);
 +              ath5k_reset(sc, NULL, true);
        }
  
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
  * Initialization routines *
  \*************************/
  
 +int
 +ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
 +{
 +      struct ieee80211_hw *hw = sc->hw;
 +      struct ath_common *common;
 +      int ret;
 +      int csz;
 +
 +      /* Initialize driver private data */
 +      SET_IEEE80211_DEV(hw, sc->dev);
 +      hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 +                      IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 +                      IEEE80211_HW_SIGNAL_DBM |
 +                      IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 +
 +      hw->wiphy->interface_modes =
 +              BIT(NL80211_IFTYPE_AP) |
 +              BIT(NL80211_IFTYPE_STATION) |
 +              BIT(NL80211_IFTYPE_ADHOC) |
 +              BIT(NL80211_IFTYPE_MESH_POINT);
 +
 +      hw->extra_tx_headroom = 2;
 +      hw->channel_change_time = 5000;
 +
 +      /*
 +       * Mark the device as detached to avoid processing
 +       * interrupts until setup is complete.
 +       */
 +      __set_bit(ATH_STAT_INVALID, sc->status);
 +
 +      sc->opmode = NL80211_IFTYPE_STATION;
 +      sc->bintval = 1000;
 +      mutex_init(&sc->lock);
 +      spin_lock_init(&sc->rxbuflock);
 +      spin_lock_init(&sc->txbuflock);
 +      spin_lock_init(&sc->block);
 +
 +
 +      /* Setup interrupt handler */
 +      ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
 +      if (ret) {
 +              ATH5K_ERR(sc, "request_irq failed\n");
 +              goto err;
 +      }
 +
 +      /* If we passed the test, malloc an ath5k_hw struct */
 +      sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
 +      if (!sc->ah) {
 +              ret = -ENOMEM;
 +              ATH5K_ERR(sc, "out of memory\n");
 +              goto err_irq;
 +      }
 +
 +      sc->ah->ah_sc = sc;
 +      sc->ah->ah_iobase = sc->iobase;
 +      common = ath5k_hw_common(sc->ah);
 +      common->ops = &ath5k_common_ops;
 +      common->bus_ops = bus_ops;
 +      common->ah = sc->ah;
 +      common->hw = hw;
 +      common->priv = sc;
 +
 +      /*
 +       * Cache line size is used to size and align various
 +       * structures used to communicate with the hardware.
 +       */
 +      ath5k_read_cachesize(common, &csz);
 +      common->cachelsz = csz << 2; /* convert to bytes */
 +
 +      spin_lock_init(&common->cc_lock);
 +
 +      /* Initialize device */
 +      ret = ath5k_hw_init(sc);
 +      if (ret)
 +              goto err_free_ah;
 +
 +      /* set up multi-rate retry capabilities */
 +      if (sc->ah->ah_version == AR5K_AR5212) {
 +              hw->max_rates = 4;
 +              hw->max_rate_tries = 11;
 +      }
 +
 +      hw->vif_data_size = sizeof(struct ath5k_vif);
 +
 +      /* Finish private driver data initialization */
 +      ret = ath5k_init(hw);
 +      if (ret)
 +              goto err_ah;
 +
 +      ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
 +                      ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
 +                                      sc->ah->ah_mac_srev,
 +                                      sc->ah->ah_phy_revision);
 +
 +      if (!sc->ah->ah_single_chip) {
 +              /* Single chip radio (!RF5111) */
 +              if (sc->ah->ah_radio_5ghz_revision &&
 +                      !sc->ah->ah_radio_2ghz_revision) {
 +                      /* No 5GHz support -> report 2GHz radio */
 +                      if (!test_bit(AR5K_MODE_11A,
 +                              sc->ah->ah_capabilities.cap_mode)) {
 +                              ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
 +                                      ath5k_chip_name(AR5K_VERSION_RAD,
 +                                              sc->ah->ah_radio_5ghz_revision),
 +                                              sc->ah->ah_radio_5ghz_revision);
 +                      /* No 2GHz support (5110 and some
 +                       * 5Ghz only cards) -> report 5Ghz radio */
 +                      } else if (!test_bit(AR5K_MODE_11B,
 +                              sc->ah->ah_capabilities.cap_mode)) {
 +                              ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
 +                                      ath5k_chip_name(AR5K_VERSION_RAD,
 +                                              sc->ah->ah_radio_5ghz_revision),
 +                                              sc->ah->ah_radio_5ghz_revision);
 +                      /* Multiband radio */
 +                      } else {
 +                              ATH5K_INFO(sc, "RF%s multiband radio found"
 +                                      " (0x%x)\n",
 +                                      ath5k_chip_name(AR5K_VERSION_RAD,
 +                                              sc->ah->ah_radio_5ghz_revision),
 +                                              sc->ah->ah_radio_5ghz_revision);
 +                      }
 +              }
 +              /* Multi chip radio (RF5111 - RF2111) ->
 +               * report both 2GHz/5GHz radios */
 +              else if (sc->ah->ah_radio_5ghz_revision &&
 +                              sc->ah->ah_radio_2ghz_revision){
 +                      ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
 +                              ath5k_chip_name(AR5K_VERSION_RAD,
 +                                      sc->ah->ah_radio_5ghz_revision),
 +                                      sc->ah->ah_radio_5ghz_revision);
 +                      ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
 +                              ath5k_chip_name(AR5K_VERSION_RAD,
 +                                      sc->ah->ah_radio_2ghz_revision),
 +                                      sc->ah->ah_radio_2ghz_revision);
 +              }
 +      }
 +
 +      ath5k_debug_init_device(sc);
 +
 +      /* ready to process interrupts */
 +      __clear_bit(ATH_STAT_INVALID, sc->status);
 +
 +      return 0;
 +err_ah:
 +      ath5k_hw_deinit(sc->ah);
 +err_free_ah:
 +      kfree(sc->ah);
 +err_irq:
 +      free_irq(sc->irq, sc);
 +err:
 +      return ret;
 +}
 +
  static int
  ath5k_stop_locked(struct ath5k_softc *sc)
  {
        if (!test_bit(ATH_STAT_INVALID, sc->status)) {
                ath5k_led_off(sc);
                ath5k_hw_set_imr(ah, 0);
 -              synchronize_irq(sc->pdev->irq);
 -      }
 -      ath5k_txq_cleanup(sc);
 -      if (!test_bit(ATH_STAT_INVALID, sc->status)) {
 +              synchronize_irq(sc->irq);
                ath5k_rx_stop(sc);
 +              ath5k_hw_dma_stop(ah);
 +              ath5k_drain_tx_buffs(sc);
                ath5k_hw_phy_disable(ah);
        }
  
  }
  
  static int
 -ath5k_init(struct ath5k_softc *sc)
 +ath5k_init_hw(struct ath5k_softc *sc)
  {
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
                AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
                AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
  
 -      ret = ath5k_reset(sc, NULL);
 +      ret = ath5k_reset(sc, NULL, false);
        if (ret)
                goto done;
  
        for (i = 0; i < common->keymax; i++)
                ath_hw_keyreset(common, (u16) i);
  
 -      ath5k_hw_set_ack_bitrate_high(ah, true);
 +      /* Use higher rates for acks instead of base
 +       * rate */
 +      ah->ah_ack_bitrate_high = true;
  
        for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
                sc->bslot[i] = NULL;
@@@ -2648,34 -2529,25 +2650,34 @@@ ath5k_stop_hw(struct ath5k_softc *sc
   * This should be called with sc->lock.
   */
  static int
 -ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
 +ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
 +                                                      bool skip_pcu)
  {
        struct ath5k_hw *ah = sc->ah;
 -      int ret;
 +      int ret, ani_mode;
  
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
  
        ath5k_hw_set_imr(ah, 0);
 -      synchronize_irq(sc->pdev->irq);
 +      synchronize_irq(sc->irq);
        stop_tasklets(sc);
  
 -      if (chan) {
 -              ath5k_txq_cleanup(sc);
 -              ath5k_rx_stop(sc);
 +      /* Save ani mode and disable ANI durring
 +       * reset. If we don't we might get false
 +       * PHY error interrupts. */
 +      ani_mode = ah->ah_sc->ani_state.ani_mode;
 +      ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF);
  
 +      /* We are going to empty hw queues
 +       * so we should also free any remaining
 +       * tx buffers */
 +      ath5k_drain_tx_buffs(sc);
 +      if (chan) {
                sc->curchan = chan;
                sc->curband = &sc->sbands[chan->band];
        }
 -      ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
 +      ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
 +                                                              skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
                goto err;
                goto err;
        }
  
 -      ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
 +      ath5k_ani_init(ah, ani_mode);
  
        ah->ah_cal_next_full = jiffies;
        ah->ah_cal_next_ani = jiffies;
        ah->ah_cal_next_nf = jiffies;
 +      ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
  
        /*
         * Change channels and update the h/w rate map if we're switching;
@@@ -2721,14 -2592,13 +2723,14 @@@ static void ath5k_reset_work(struct wor
                reset_work);
  
        mutex_lock(&sc->lock);
 -      ath5k_reset(sc, sc->curchan);
 +      ath5k_reset(sc, NULL, true);
        mutex_unlock(&sc->lock);
  }
  
  static int
 -ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 +ath5k_init(struct ieee80211_hw *hw)
  {
 +
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
        struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
        u8 mac[ETH_ALEN] = {};
        int ret;
  
 -      ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
  
        /*
         * Check if the MAC has multi-rate retry support.
        /*
         * Allocate tx+rx descriptors and populate the lists.
         */
 -      ret = ath5k_desc_alloc(sc, pdev);
 +      ret = ath5k_desc_alloc(sc);
        if (ret) {
                ATH5K_ERR(sc, "can't allocate descriptors\n");
                goto err;
                goto err_bhal;
        }
  
 -      /* This order matches mac80211's queue priority, so we can
 -       * directly use the mac80211 queue number without any mapping */
 -      txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO);
 -      if (IS_ERR(txq)) {
 -              ATH5K_ERR(sc, "can't setup xmit queue\n");
 -              ret = PTR_ERR(txq);
 -              goto err_queues;
 -      }
 -      txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI);
 -      if (IS_ERR(txq)) {
 -              ATH5K_ERR(sc, "can't setup xmit queue\n");
 -              ret = PTR_ERR(txq);
 -              goto err_queues;
 -      }
 -      txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
 -      if (IS_ERR(txq)) {
 -              ATH5K_ERR(sc, "can't setup xmit queue\n");
 -              ret = PTR_ERR(txq);
 -              goto err_queues;
 -      }
 -      txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
 -      if (IS_ERR(txq)) {
 -              ATH5K_ERR(sc, "can't setup xmit queue\n");
 -              ret = PTR_ERR(txq);
 -              goto err_queues;
 +      /* 5211 and 5212 usually support 10 queues but we better rely on the
 +       * capability information */
 +      if (ah->ah_capabilities.cap_queues.q_tx_num >= 6) {
 +              /* This order matches mac80211's queue priority, so we can
 +              * directly use the mac80211 queue number without any mapping */
 +              txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO);
 +              if (IS_ERR(txq)) {
 +                      ATH5K_ERR(sc, "can't setup xmit queue\n");
 +                      ret = PTR_ERR(txq);
 +                      goto err_queues;
 +              }
 +              txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI);
 +              if (IS_ERR(txq)) {
 +                      ATH5K_ERR(sc, "can't setup xmit queue\n");
 +                      ret = PTR_ERR(txq);
 +                      goto err_queues;
 +              }
 +              txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
 +              if (IS_ERR(txq)) {
 +                      ATH5K_ERR(sc, "can't setup xmit queue\n");
 +                      ret = PTR_ERR(txq);
 +                      goto err_queues;
 +              }
 +              txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
 +              if (IS_ERR(txq)) {
 +                      ATH5K_ERR(sc, "can't setup xmit queue\n");
 +                      ret = PTR_ERR(txq);
 +                      goto err_queues;
 +              }
 +              hw->queues = 4;
 +      } else {
 +              /* older hardware (5210) can only support one data queue */
 +              txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
 +              if (IS_ERR(txq)) {
 +                      ATH5K_ERR(sc, "can't setup xmit queue\n");
 +                      ret = PTR_ERR(txq);
 +                      goto err_queues;
 +              }
 +              hw->queues = 1;
        }
 -      hw->queues = 4;
  
        tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
        tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
  
        ret = ath5k_eeprom_read_mac(ah, mac);
        if (ret) {
 -              ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
 -                      sc->pdev->device);
 +              ATH5K_ERR(sc, "unable to read address from EEPROM\n");
                goto err_queues;
        }
  
@@@ -2884,15 -2743,15 +2886,15 @@@ err_queues
  err_bhal:
        ath5k_hw_release_tx_queue(ah, sc->bhalq);
  err_desc:
 -      ath5k_desc_free(sc, pdev);
 +      ath5k_desc_free(sc);
  err:
        return ret;
  }
  
 -static void
 -ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 +void
 +ath5k_deinit_softc(struct ath5k_softc *sc)
  {
 -      struct ath5k_softc *sc = hw->priv;
 +      struct ieee80211_hw *hw = sc->hw;
  
        /*
         * NB: the order of these is important:
         * XXX: ??? detach ath5k_hw ???
         * Other than that, it's straightforward...
         */
 +      ath5k_debug_finish_device(sc);
        ieee80211_unregister_hw(hw);
 -      ath5k_desc_free(sc, pdev);
 +      ath5k_desc_free(sc);
        ath5k_txq_release(sc);
        ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
        ath5k_unregister_leds(sc);
         * returns because we'll get called back to reclaim node
         * state and potentially want to use them.
         */
 +      ath5k_hw_deinit(sc->ah);
 +      free_irq(sc->irq, sc);
  }
  
  /********************\
@@@ -2944,7 -2800,7 +2946,7 @@@ ath5k_tx(struct ieee80211_hw *hw, struc
  
  static int ath5k_start(struct ieee80211_hw *hw)
  {
 -      return ath5k_init(hw->priv);
 +      return ath5k_init_hw(hw->priv);
  }
  
  static void ath5k_stop(struct ieee80211_hw *hw)
@@@ -2997,7 -2853,8 +2999,8 @@@ static int ath5k_add_interface(struct i
  
        /* Assign the vap/adhoc to a beacon xmit slot. */
        if ((avf->opmode == NL80211_IFTYPE_AP) ||
-           (avf->opmode == NL80211_IFTYPE_ADHOC)) {
+           (avf->opmode == NL80211_IFTYPE_ADHOC) ||
+           (avf->opmode == NL80211_IFTYPE_MESH_POINT)) {
                int slot;
  
                WARN_ON(list_empty(&sc->bcbuf));
                sc->bslot[avf->bslot] = vif;
                if (avf->opmode == NL80211_IFTYPE_AP)
                        sc->num_ap_vifs++;
-               else
+               else if (avf->opmode == NL80211_IFTYPE_ADHOC)
                        sc->num_adhoc_vifs++;
        }
  
@@@ -3352,32 -3209,14 +3355,32 @@@ static int ath5k_get_survey(struct ieee
  {
        struct ath5k_softc *sc = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
 +      struct ath_common *common = ath5k_hw_common(sc->ah);
 +      struct ath_cycle_counters *cc = &common->cc_survey;
 +      unsigned int div = common->clockrate * 1000;
  
 -       if (idx != 0)
 +      if (idx != 0)
                return -ENOENT;
  
        survey->channel = conf->channel;
        survey->filled = SURVEY_INFO_NOISE_DBM;
        survey->noise = sc->ah->ah_noise_floor;
  
 +      spin_lock_bh(&common->cc_lock);
 +      ath_hw_cycle_counters_update(common);
 +      if (cc->cycles > 0) {
 +              survey->filled |= SURVEY_INFO_CHANNEL_TIME |
 +                      SURVEY_INFO_CHANNEL_TIME_BUSY |
 +                      SURVEY_INFO_CHANNEL_TIME_RX |
 +                      SURVEY_INFO_CHANNEL_TIME_TX;
 +              survey->channel_time += cc->cycles / div;
 +              survey->channel_time_busy += cc->rx_busy / div;
 +              survey->channel_time_rx += cc->rx_frame / div;
 +              survey->channel_time_tx += cc->tx_frame / div;
 +      }
 +      memset(cc, 0, sizeof(*cc));
 +      spin_unlock_bh(&common->cc_lock);
 +
        return 0;
  }
  
@@@ -3559,37 -3398,7 +3562,37 @@@ static int ath5k_conf_tx(struct ieee802
        return ret;
  }
  
 -static const struct ieee80211_ops ath5k_hw_ops = {
 +static int ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 +{
 +      struct ath5k_softc *sc = hw->priv;
 +
 +      if (tx_ant == 1 && rx_ant == 1)
 +              ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
 +      else if (tx_ant == 2 && rx_ant == 2)
 +              ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
 +      else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3)
 +              ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
 +      else
 +              return -EINVAL;
 +      return 0;
 +}
 +
 +static int ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 +{
 +      struct ath5k_softc *sc = hw->priv;
 +
 +      switch (sc->ah->ah_ant_mode) {
 +      case AR5K_ANTMODE_FIXED_A:
 +              *tx_ant = 1; *rx_ant = 1; break;
 +      case AR5K_ANTMODE_FIXED_B:
 +              *tx_ant = 2; *rx_ant = 2; break;
 +      case AR5K_ANTMODE_DEFAULT:
 +              *tx_ant = 3; *rx_ant = 3; break;
 +      }
 +      return 0;
 +}
 +
 +const struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
        .start          = ath5k_start,
        .stop           = ath5k_stop,
        .sw_scan_start  = ath5k_sw_scan_start,
        .sw_scan_complete = ath5k_sw_scan_complete,
        .set_coverage_class = ath5k_set_coverage_class,
 +      .set_antenna    = ath5k_set_antenna,
 +      .get_antenna    = ath5k_get_antenna,
  };
 -
 -/********************\
 -* PCI Initialization *
 -\********************/
 -
 -static int __devinit
 -ath5k_pci_probe(struct pci_dev *pdev,
 -              const struct pci_device_id *id)
 -{
 -      void __iomem *mem;
 -      struct ath5k_softc *sc;
 -      struct ath_common *common;
 -      struct ieee80211_hw *hw;
 -      int ret;
 -      u8 csz;
 -
 -      /*
 -       * L0s needs to be disabled on all ath5k cards.
 -       *
 -       * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
 -       * by default in the future in 2.6.36) this will also mean both L1 and
 -       * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
 -       * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
 -       * though but cannot currently undue the effect of a blacklist, for
 -       * details you can read pcie_aspm_sanity_check() and see how it adjusts
 -       * the device link capability.
 -       *
 -       * It may be possible in the future to implement some PCI API to allow
 -       * drivers to override blacklists for pre 1.1 PCIe but for now it is
 -       * best to accept that both L0s and L1 will be disabled completely for
 -       * distributions shipping with CONFIG_PCIEASPM rather than having this
 -       * issue present. Motivation for adding this new API will be to help
 -       * with power consumption for some of these devices.
 -       */
 -      pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
 -
 -      ret = pci_enable_device(pdev);
 -      if (ret) {
 -              dev_err(&pdev->dev, "can't enable device\n");
 -              goto err;
 -      }
 -
 -      /* XXX 32-bit addressing only */
 -      ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 -      if (ret) {
 -              dev_err(&pdev->dev, "32-bit DMA not available\n");
 -              goto err_dis;
 -      }
 -
 -      /*
 -       * Cache line size is used to size and align various
 -       * structures used to communicate with the hardware.
 -       */
 -      pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
 -      if (csz == 0) {
 -              /*
 -               * Linux 2.4.18 (at least) writes the cache line size
 -               * register as a 16-bit wide register which is wrong.
 -               * We must have this setup properly for rx buffer
 -               * DMA to work so force a reasonable value here if it
 -               * comes up zero.
 -               */
 -              csz = L1_CACHE_BYTES >> 2;
 -              pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
 -      }
 -      /*
 -       * The default setting of latency timer yields poor results,
 -       * set it to the value used by other systems.  It may be worth
 -       * tweaking this setting more.
 -       */
 -      pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
 -
 -      /* Enable bus mastering */
 -      pci_set_master(pdev);
 -
 -      /*
 -       * Disable the RETRY_TIMEOUT register (0x41) to keep
 -       * PCI Tx retries from interfering with C3 CPU state.
 -       */
 -      pci_write_config_byte(pdev, 0x41, 0);
 -
 -      ret = pci_request_region(pdev, 0, "ath5k");
 -      if (ret) {
 -              dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
 -              goto err_dis;
 -      }
 -
 -      mem = pci_iomap(pdev, 0, 0);
 -      if (!mem) {
 -              dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
 -              ret = -EIO;
 -              goto err_reg;
 -      }
 -
 -      /*
 -       * Allocate hw (mac80211 main struct)
 -       * and hw->priv (driver private data)
 -       */
 -      hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
 -      if (hw == NULL) {
 -              dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
 -              ret = -ENOMEM;
 -              goto err_map;
 -      }
 -
 -      dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
 -
 -      /* Initialize driver private data */
 -      SET_IEEE80211_DEV(hw, &pdev->dev);
 -      hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 -                  IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
 -                  IEEE80211_HW_SIGNAL_DBM;
 -
 -      hw->wiphy->interface_modes =
 -              BIT(NL80211_IFTYPE_AP) |
 -              BIT(NL80211_IFTYPE_STATION) |
 -              BIT(NL80211_IFTYPE_ADHOC) |
 -              BIT(NL80211_IFTYPE_MESH_POINT);
 -
 -      hw->extra_tx_headroom = 2;
 -      hw->channel_change_time = 5000;
 -      sc = hw->priv;
 -      sc->hw = hw;
 -      sc->pdev = pdev;
 -
 -      /*
 -       * Mark the device as detached to avoid processing
 -       * interrupts until setup is complete.
 -       */
 -      __set_bit(ATH_STAT_INVALID, sc->status);
 -
 -      sc->iobase = mem; /* So we can unmap it on detach */
 -      sc->opmode = NL80211_IFTYPE_STATION;
 -      sc->bintval = 1000;
 -      mutex_init(&sc->lock);
 -      spin_lock_init(&sc->rxbuflock);
 -      spin_lock_init(&sc->txbuflock);
 -      spin_lock_init(&sc->block);
 -
 -      /* Set private data */
 -      pci_set_drvdata(pdev, sc);
 -
 -      /* Setup interrupt handler */
 -      ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
 -      if (ret) {
 -              ATH5K_ERR(sc, "request_irq failed\n");
 -              goto err_free;
 -      }
 -
 -      /* If we passed the test, malloc an ath5k_hw struct */
 -      sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
 -      if (!sc->ah) {
 -              ret = -ENOMEM;
 -              ATH5K_ERR(sc, "out of memory\n");
 -              goto err_irq;
 -      }
 -
 -      sc->ah->ah_sc = sc;
 -      sc->ah->ah_iobase = sc->iobase;
 -      common = ath5k_hw_common(sc->ah);
 -      common->ops = &ath5k_common_ops;
 -      common->ah = sc->ah;
 -      common->hw = hw;
 -      common->cachelsz = csz << 2; /* convert to bytes */
 -      spin_lock_init(&common->cc_lock);
 -
 -      /* Initialize device */
 -      ret = ath5k_hw_attach(sc);
 -      if (ret) {
 -              goto err_free_ah;
 -      }
 -
 -      /* set up multi-rate retry capabilities */
 -      if (sc->ah->ah_version == AR5K_AR5212) {
 -              hw->max_rates = 4;
 -              hw->max_rate_tries = 11;
 -      }
 -
 -      hw->vif_data_size = sizeof(struct ath5k_vif);
 -
 -      /* Finish private driver data initialization */
 -      ret = ath5k_attach(pdev, hw);
 -      if (ret)
 -              goto err_ah;
 -
 -      ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
 -                      ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
 -                                      sc->ah->ah_mac_srev,
 -                                      sc->ah->ah_phy_revision);
 -
 -      if (!sc->ah->ah_single_chip) {
 -              /* Single chip radio (!RF5111) */
 -              if (sc->ah->ah_radio_5ghz_revision &&
 -                      !sc->ah->ah_radio_2ghz_revision) {
 -                      /* No 5GHz support -> report 2GHz radio */
 -                      if (!test_bit(AR5K_MODE_11A,
 -                              sc->ah->ah_capabilities.cap_mode)) {
 -                              ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
 -                                      ath5k_chip_name(AR5K_VERSION_RAD,
 -                                              sc->ah->ah_radio_5ghz_revision),
 -                                              sc->ah->ah_radio_5ghz_revision);
 -                      /* No 2GHz support (5110 and some
 -                       * 5Ghz only cards) -> report 5Ghz radio */
 -                      } else if (!test_bit(AR5K_MODE_11B,
 -                              sc->ah->ah_capabilities.cap_mode)) {
 -                              ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
 -                                      ath5k_chip_name(AR5K_VERSION_RAD,
 -                                              sc->ah->ah_radio_5ghz_revision),
 -                                              sc->ah->ah_radio_5ghz_revision);
 -                      /* Multiband radio */
 -                      } else {
 -                              ATH5K_INFO(sc, "RF%s multiband radio found"
 -                                      " (0x%x)\n",
 -                                      ath5k_chip_name(AR5K_VERSION_RAD,
 -                                              sc->ah->ah_radio_5ghz_revision),
 -                                              sc->ah->ah_radio_5ghz_revision);
 -                      }
 -              }
 -              /* Multi chip radio (RF5111 - RF2111) ->
 -               * report both 2GHz/5GHz radios */
 -              else if (sc->ah->ah_radio_5ghz_revision &&
 -                              sc->ah->ah_radio_2ghz_revision){
 -                      ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
 -                              ath5k_chip_name(AR5K_VERSION_RAD,
 -                                      sc->ah->ah_radio_5ghz_revision),
 -                                      sc->ah->ah_radio_5ghz_revision);
 -                      ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
 -                              ath5k_chip_name(AR5K_VERSION_RAD,
 -                                      sc->ah->ah_radio_2ghz_revision),
 -                                      sc->ah->ah_radio_2ghz_revision);
 -              }
 -      }
 -
 -      ath5k_debug_init_device(sc);
 -
 -      /* ready to process interrupts */
 -      __clear_bit(ATH_STAT_INVALID, sc->status);
 -
 -      return 0;
 -err_ah:
 -      ath5k_hw_detach(sc->ah);
 -err_free_ah:
 -      kfree(sc->ah);
 -err_irq:
 -      free_irq(pdev->irq, sc);
 -err_free:
 -      ieee80211_free_hw(hw);
 -err_map:
 -      pci_iounmap(pdev, mem);
 -err_reg:
 -      pci_release_region(pdev, 0);
 -err_dis:
 -      pci_disable_device(pdev);
 -err:
 -      return ret;
 -}
 -
 -static void __devexit
 -ath5k_pci_remove(struct pci_dev *pdev)
 -{
 -      struct ath5k_softc *sc = pci_get_drvdata(pdev);
 -
 -      ath5k_debug_finish_device(sc);
 -      ath5k_detach(pdev, sc->hw);
 -      ath5k_hw_detach(sc->ah);
 -      kfree(sc->ah);
 -      free_irq(pdev->irq, sc);
 -      pci_iounmap(pdev, sc->iobase);
 -      pci_release_region(pdev, 0);
 -      pci_disable_device(pdev);
 -      ieee80211_free_hw(sc->hw);
 -}
 -
 -#ifdef CONFIG_PM_SLEEP
 -static int ath5k_pci_suspend(struct device *dev)
 -{
 -      struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
 -
 -      ath5k_led_off(sc);
 -      return 0;
 -}
 -
 -static int ath5k_pci_resume(struct device *dev)
 -{
 -      struct pci_dev *pdev = to_pci_dev(dev);
 -      struct ath5k_softc *sc = pci_get_drvdata(pdev);
 -
 -      /*
 -       * Suspend/Resume resets the PCI configuration space, so we have to
 -       * re-disable the RETRY_TIMEOUT register (0x41) to keep
 -       * PCI Tx retries from interfering with C3 CPU state
 -       */
 -      pci_write_config_byte(pdev, 0x41, 0);
 -
 -      ath5k_led_enable(sc);
 -      return 0;
 -}
 -
 -static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
 -#define ATH5K_PM_OPS  (&ath5k_pm_ops)
 -#else
 -#define ATH5K_PM_OPS  NULL
 -#endif /* CONFIG_PM_SLEEP */
 -
 -static struct pci_driver ath5k_pci_driver = {
 -      .name           = KBUILD_MODNAME,
 -      .id_table       = ath5k_pci_id_table,
 -      .probe          = ath5k_pci_probe,
 -      .remove         = __devexit_p(ath5k_pci_remove),
 -      .driver.pm      = ATH5K_PM_OPS,
 -};
 -
 -/*
 - * Module init/exit functions
 - */
 -static int __init
 -init_ath5k_pci(void)
 -{
 -      int ret;
 -
 -      ret = pci_register_driver(&ath5k_pci_driver);
 -      if (ret) {
 -              printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
 -              return ret;
 -      }
 -
 -      return 0;
 -}
 -
 -static void __exit
 -exit_ath5k_pci(void)
 -{
 -      pci_unregister_driver(&ath5k_pci_driver);
 -}
 -
 -module_init(init_ath5k_pci);
 -module_exit(exit_ath5k_pci);
index 4210a9306955f500674985357655c52ee7674637,0963071e8f908c15ebec8131c84b792d931e56d9..9b5501f900100ea47580f1b4f36b1341dad8168a
@@@ -87,19 -87,33 +87,19 @@@ struct ath_config 
  /**
   * enum buffer_type - Buffer type flags
   *
 - * @BUF_HT: Send this buffer using HT capabilities
   * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
   * @BUF_AGGR: Indicates whether the buffer can be aggregated
   *    (used in aggregation scheduling)
 - * @BUF_RETRY: Indicates whether the buffer is retried
   * @BUF_XRETRY: To denote excessive retries of the buffer
   */
  enum buffer_type {
 -      BUF_HT                  = BIT(1),
        BUF_AMPDU               = BIT(2),
        BUF_AGGR                = BIT(3),
 -      BUF_RETRY               = BIT(4),
        BUF_XRETRY              = BIT(5),
  };
  
 -#define bf_nframes            bf_state.bfs_nframes
 -#define bf_al                 bf_state.bfs_al
 -#define bf_frmlen             bf_state.bfs_frmlen
 -#define bf_retries            bf_state.bfs_retries
 -#define bf_seqno              bf_state.bfs_seqno
 -#define bf_tidno              bf_state.bfs_tidno
 -#define bf_keyix                bf_state.bfs_keyix
 -#define bf_keytype            bf_state.bfs_keytype
 -#define bf_isht(bf)           (bf->bf_state.bf_type & BUF_HT)
  #define bf_isampdu(bf)                (bf->bf_state.bf_type & BUF_AMPDU)
  #define bf_isaggr(bf)         (bf->bf_state.bf_type & BUF_AGGR)
 -#define bf_isretried(bf)      (bf->bf_state.bf_type & BUF_RETRY)
  #define bf_isxretried(bf)     (bf->bf_state.bf_type & BUF_XRETRY)
  
  #define ATH_TXSTATUS_RING_SIZE 64
@@@ -164,8 -178,8 +164,8 @@@ void ath_descdma_cleanup(struct ath_sof
  
  /* returns delimiter padding required given the packet length */
  #define ATH_AGGR_GET_NDELIM(_len)                                     \
 -      (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ?           \
 -        (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
 +       (((_len) >= ATH_AGGR_MINPLEN) ? 0 :                             \
 +        DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ))
  
  #define BAW_WITHIN(_start, _bawsz, _seqno) \
        ((((_seqno) - (_start)) & 4095) < (_bawsz))
@@@ -182,6 -196,7 +182,6 @@@ enum ATH_AGGR_STATUS 
  
  #define ATH_TXFIFO_DEPTH 8
  struct ath_txq {
 -      int axq_class;
        u32 axq_qnum;
        u32 *axq_link;
        struct list_head axq_q;
        struct list_head txq_fifo_pending;
        u8 txq_headidx;
        u8 txq_tailidx;
 +      int pending_frames;
  };
  
  struct ath_atx_ac {
 +      struct ath_txq *txq;
        int sched;
 -      int qnum;
        struct list_head list;
        struct list_head tid_q;
  };
  
 +struct ath_frame_info {
 +      int framelen;
 +      u32 keyix;
 +      enum ath9k_key_type keytype;
 +      u8 retries;
 +      u16 seqno;
 +};
 +
  struct ath_buf_state {
 -      int bfs_nframes;
 -      u16 bfs_al;
 -      u16 bfs_frmlen;
 -      int bfs_seqno;
 -      int bfs_tidno;
 -      int bfs_retries;
        u8 bf_type;
        u8 bfs_paprd;
 -      unsigned long bfs_paprd_timestamp;
 -      u32 bfs_keyix;
 -      enum ath9k_key_type bfs_keytype;
 +      enum ath9k_internal_frame_type bfs_ftype;
  };
  
  struct ath_buf {
        dma_addr_t bf_daddr;            /* physical addr of desc */
        dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
        bool bf_stale;
 -      bool bf_tx_aborted;
        u16 bf_flags;
        struct ath_buf_state bf_state;
        struct ath_wiphy *aphy;
@@@ -256,6 -271,7 +256,6 @@@ struct ath_node 
        struct ath_atx_ac ac[WME_NUM_AC];
        u16 maxampdu;
        u8 mpdudensity;
 -      int last_rssi;
  };
  
  #define AGGR_CLEANUP         BIT(1)
  
  struct ath_tx_control {
        struct ath_txq *txq;
 +      struct ath_node *an;
        int if_id;
        enum ath9k_internal_frame_type frame_type;
        u8 paprd;
  struct ath_tx {
        u16 seq_no;
        u32 txqsetup;
 -      int hwq_map[WME_NUM_AC];
        spinlock_t txbuflock;
        struct list_head txbuf;
        struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
        struct ath_descdma txdma;
 -      int pending_frames[WME_NUM_AC];
 +      struct ath_txq *txq_map[WME_NUM_AC];
  };
  
  struct ath_rx_edma {
@@@ -295,6 -311,7 +295,6 @@@ struct ath_rx 
        u8 rxotherant;
        u32 *rxlink;
        unsigned int rxfilter;
 -      spinlock_t pcu_lock;
        spinlock_t rxbuflock;
        struct list_head rxbuf;
        struct ath_descdma rxdma;
@@@ -311,7 -328,8 +311,7 @@@ void ath_rx_cleanup(struct ath_softc *s
  int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
  struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
  void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
- void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
 -int ath_tx_setup(struct ath_softc *sc, int haltype);
+ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
  void ath_draintxq(struct ath_softc *sc,
                     struct ath_txq *txq, bool retry_tx);
  void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
@@@ -325,6 -343,7 +325,6 @@@ int ath_tx_start(struct ieee80211_hw *h
                 struct ath_tx_control *txctl);
  void ath_tx_tasklet(struct ath_softc *sc);
  void ath_tx_edma_tasklet(struct ath_softc *sc);
 -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
  int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn);
  void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
@@@ -545,7 -564,6 +545,7 @@@ struct ath_ant_comb 
  #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
  #define SC_OP_BT_SCAN              BIT(13)
  #define SC_OP_ANI_RUN              BIT(14)
 +#define SC_OP_ENABLE_APM           BIT(15)
  
  /* Powersave flags */
  #define PS_WAIT_FOR_BEACON        BIT(0)
@@@ -583,14 -601,13 +583,14 @@@ struct ath_softc 
        struct ath_hw *sc_ah;
        void __iomem *mem;
        int irq;
 -      spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
        spinlock_t sc_pm_lock;
 +      spinlock_t sc_pcu_lock;
        struct mutex mutex;
        struct work_struct paprd_work;
        struct work_struct hw_check_work;
        struct completion paprd_complete;
 +      bool paprd_pending;
  
        u32 intrstatus;
        u32 sc_flags; /* SC_OP_* */
@@@ -648,11 -665,11 +648,11 @@@ struct ath_wiphy 
        bool idle;
        int chan_idx;
        int chan_is_ht;
 +      int last_rssi;
  };
  
  void ath9k_tasklet(unsigned long data);
  int ath_reset(struct ath_softc *sc, bool retry_tx);
 -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
  int ath_cabq_update(struct ath_softc *);
  
  static inline void ath_read_cachesize(struct ath_common *common, int *csz)
@@@ -698,12 -715,10 +698,12 @@@ static inline void ath_ahb_exit(void) {
  void ath9k_ps_wakeup(struct ath_softc *sc);
  void ath9k_ps_restore(struct ath_softc *sc);
  
 +u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
 +
  void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
  int ath9k_wiphy_add(struct ath_softc *sc);
  int ath9k_wiphy_del(struct ath_wiphy *aphy);
 -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
 +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype);
  int ath9k_wiphy_pause(struct ath_wiphy *aphy);
  int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
  int ath9k_wiphy_select(struct ath_wiphy *aphy);
index c2b4bba7410c8dfb77caa9c76340cee4cc21c611,a3ccb1b9638d7b8b44f32ba651d519d042b806ec..5bfa031545f498fd96db38f151e86828b20289db
@@@ -96,8 -96,8 +96,8 @@@ static bool ath9k_hw_def_fill_eeprom(st
        for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
                if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc,
                                         eep_data)) {
 -                      ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
 -                                "Unable to read eeprom region\n");
 +                      ath_err(ath9k_hw_common(ah),
 +                              "Unable to read eeprom region\n");
                        return false;
                }
                eep_data++;
@@@ -117,13 -117,13 +117,13 @@@ static int ath9k_hw_def_check_eeprom(st
        int i, addr, size;
  
        if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
 -              ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n");
 +              ath_err(common, "Reading Magic # failed\n");
                return false;
        }
  
        if (!ath9k_hw_use_flash(ah)) {
 -              ath_print(common, ATH_DBG_EEPROM,
 -                        "Read Magic = 0x%04X\n", magic);
 +              ath_dbg(common, ATH_DBG_EEPROM,
 +                      "Read Magic = 0x%04X\n", magic);
  
                if (magic != AR5416_EEPROM_MAGIC) {
                        magic2 = swab16(magic);
                                        eepdata++;
                                }
                        } else {
 -                              ath_print(common, ATH_DBG_FATAL,
 -                                        "Invalid EEPROM Magic. "
 -                                        "Endianness mismatch.\n");
 +                              ath_err(common,
 +                                      "Invalid EEPROM Magic. Endianness mismatch.\n");
                                return -EINVAL;
                        }
                }
        }
  
 -      ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
 -                need_swap ? "True" : "False");
 +      ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
 +              need_swap ? "True" : "False");
  
        if (need_swap)
                el = swab16(ah->eeprom.def.baseEepHeader.length);
                u32 integer, j;
                u16 word;
  
 -              ath_print(common, ATH_DBG_EEPROM,
 -                        "EEPROM Endianness is not native.. Changing.\n");
 +              ath_dbg(common, ATH_DBG_EEPROM,
 +                      "EEPROM Endianness is not native.. Changing.\n");
  
                word = swab16(eep->baseEepHeader.length);
                eep->baseEepHeader.length = word;
  
        if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
            ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
 +              ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
                        sum, ah->eep_ops->get_eeprom_ver(ah));
                return -EINVAL;
        }
@@@ -964,19 -966,20 +964,19 @@@ static void ath9k_hw_set_def_power_cal_
                                        ((pdadcValues[4 * j + 3] & 0xFF) << 24);
                                REG_WRITE(ah, regOffset, reg32);
  
 -                              ath_print(common, ATH_DBG_EEPROM,
 -                                        "PDADC (%d,%4x): %4.4x %8.8x\n",
 -                                        i, regChainOffset, regOffset,
 -                                        reg32);
 -                              ath_print(common, ATH_DBG_EEPROM,
 -                                        "PDADC: Chain %d | PDADC %3d "
 -                                        "Value %3d | PDADC %3d Value %3d | "
 -                                        "PDADC %3d Value %3d | PDADC %3d "
 -                                        "Value %3d |\n",
 -                                        i, 4 * j, pdadcValues[4 * j],
 -                                        4 * j + 1, pdadcValues[4 * j + 1],
 -                                        4 * j + 2, pdadcValues[4 * j + 2],
 -                                        4 * j + 3,
 -                                        pdadcValues[4 * j + 3]);
 +                              ath_dbg(common, ATH_DBG_EEPROM,
 +                                      "PDADC (%d,%4x): %4.4x %8.8x\n",
 +                                      i, regChainOffset, regOffset,
 +                                      reg32);
 +                              ath_dbg(common, ATH_DBG_EEPROM,
 +                                      "PDADC: Chain %d | PDADC %3d "
 +                                      "Value %3d | PDADC %3d Value %3d | "
 +                                      "PDADC %3d Value %3d | PDADC %3d "
 +                                      "Value %3d |\n",
 +                                      i, 4 * j, pdadcValues[4 * j],
 +                                      4 * j + 1, pdadcValues[4 * j + 1],
 +                                      4 * j + 2, pdadcValues[4 * j + 2],
 +                                      4 * j + 3, pdadcValues[4 * j + 3]);
  
                                regOffset += 4;
                        }
@@@ -1019,16 -1022,13 +1019,16 @@@ static void ath9k_hw_set_def_power_per_
                0, {0, 0, 0, 0}
        };
        u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
 -      u16 ctlModesFor11a[] =
 -              { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
 -      u16 ctlModesFor11g[] =
 -              { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
 -                CTL_2GHT40
 -              };
 -      u16 numCtlModes, *pCtlMode, ctlMode, freq;
 +      static const u16 ctlModesFor11a[] = {
 +              CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
 +      };
 +      static const u16 ctlModesFor11g[] = {
 +              CTL_11B, CTL_11G, CTL_2GHT20,
 +              CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
 +      };
 +      u16 numCtlModes;
 +      const u16 *pCtlMode;
 +      u16 ctlMode, freq;
        struct chan_centers centers;
        int tx_chainmask;
        u16 twiceMinEdgePower;
        case 1:
                break;
        case 2:
-               scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        case 3:
-               scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        }
  
-       scaledPower = max((u16)0, scaledPower);
        if (IS_CHAN_2GHZ(chan)) {
                numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
                        SUB_NUM_CTL_MODES_AT_2G_40;
@@@ -1259,7 -1263,7 +1263,7 @@@ static void ath9k_hw_def_set_txpower(st
                                    u16 cfgCtl,
                                    u8 twiceAntennaReduction,
                                    u8 twiceMaxRegulatoryPower,
 -                                  u8 powerLimit)
 +                                  u8 powerLimit, bool test)
  {
  #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
  
        ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
  
 +      regulatory->max_power_level = 0;
        for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
                ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
                if (ratesArray[i] > AR5416_MAX_RATE_POWER)
                        ratesArray[i] = AR5416_MAX_RATE_POWER;
 +              if (ratesArray[i] > regulatory->max_power_level)
 +                      regulatory->max_power_level = ratesArray[i];
 +      }
 +
 +      if (!test) {
 +              i = rate6mb;
 +
 +              if (IS_CHAN_HT40(chan))
 +                      i = rateHt40_0;
 +              else if (IS_CHAN_HT20(chan))
 +                      i = rateHt20_0;
 +
 +              regulatory->max_power_level = ratesArray[i];
 +      }
 +
 +      switch(ar5416_get_ntxchains(ah->txchainmask)) {
 +      case 1:
 +              break;
 +      case 2:
 +              regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
 +              break;
 +      case 3:
 +              regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
 +              break;
 +      default:
 +              ath_dbg(ath9k_hw_common(ah), ATH_DBG_EEPROM,
 +                      "Invalid chainmask configuration\n");
 +              break;
        }
  
 +      if (test)
 +              return;
 +
        if (AR_SREV_9280_20_OR_LATER(ah)) {
                for (i = 0; i < Ar5416RateSize; i++) {
                        int8_t pwr_table_offset;
        REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
                  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
                  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
 -
 -      i = rate6mb;
 -
 -      if (IS_CHAN_HT40(chan))
 -              i = rateHt40_0;
 -      else if (IS_CHAN_HT20(chan))
 -              i = rateHt20_0;
 -
 -      if (AR_SREV_9280_20_OR_LATER(ah))
 -              regulatory->max_power_level =
 -                      ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
 -      else
 -              regulatory->max_power_level = ratesArray[i];
 -
 -      switch(ar5416_get_ntxchains(ah->txchainmask)) {
 -      case 1:
 -              break;
 -      case 2:
 -              regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
 -              break;
 -      case 3:
 -              regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
 -              break;
 -      default:
 -              ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
 -                        "Invalid chainmask configuration\n");
 -              break;
 -      }
  }
  
  static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
@@@ -1458,17 -1458,17 +1462,17 @@@ static u16 ath9k_hw_def_get_spur_channe
  
        u16 spur_val = AR_NO_SPUR;
  
 -      ath_print(common, ATH_DBG_ANI,
 -                "Getting spur idx %d is2Ghz. %d val %x\n",
 -                i, is2GHz, ah->config.spurchans[i][is2GHz]);
 +      ath_dbg(common, ATH_DBG_ANI,
 +              "Getting spur idx:%d is2Ghz:%d val:%x\n",
 +              i, is2GHz, ah->config.spurchans[i][is2GHz]);
  
        switch (ah->config.spurmode) {
        case SPUR_DISABLE:
                break;
        case SPUR_ENABLE_IOCTL:
                spur_val = ah->config.spurchans[i][is2GHz];
 -              ath_print(common, ATH_DBG_ANI,
 -                        "Getting spur val from new loc. %d\n", spur_val);
 +              ath_dbg(common, ATH_DBG_ANI,
 +                      "Getting spur val from new loc. %d\n", spur_val);
                break;
        case SPUR_ENABLE_EEPROM:
                spur_val = EEP_DEF_SPURCHAN;
index 45d4b2403a52653a7a531a39171d2be433279c0e,0de3c3d3c245c2ad5f71f0a419a7ba4fab96e60c..d0918bd23b8e7d7cb0c2018f20df5a00666072e4
@@@ -28,7 -28,10 +28,7 @@@ MODULE_FIRMWARE(FIRMWARE_AR9271)
  static struct usb_device_id ath9k_hif_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
        { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
 -      { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */
 -      { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */
        { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
 -      { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */
        { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
        { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
        { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
        { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */
        { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
        { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
 -      { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
        { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
 -      { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */
 +
 +      { USB_DEVICE(0x0cf3, 0x7015),
 +        .driver_info = AR9287_USB },  /* Atheros */
 +      { USB_DEVICE(0x1668, 0x1200),
 +        .driver_info = AR9287_USB },  /* Verizon */
 +
 +      { USB_DEVICE(0x0cf3, 0x7010),
 +        .driver_info = AR9280_USB },  /* Atheros */
 +      { USB_DEVICE(0x0846, 0x9018),
 +        .driver_info = AR9280_USB },  /* Netgear WNDA3200 */
 +      { USB_DEVICE(0x083A, 0xA704),
 +        .driver_info = AR9280_USB },  /* SMC Networks */
 +
        { },
  };
  
@@@ -361,9 -353,9 +361,9 @@@ static void ath9k_hif_usb_rx_stream(str
                                    struct sk_buff *skb)
  {
        struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
 -      int index = 0, i = 0, chk_idx, len = skb->len;
 -      int rx_remain_len = 0, rx_pkt_len = 0;
 -      u16 pkt_len, pkt_tag, pool_index = 0;
 +      int index = 0, i = 0, len = skb->len;
 +      int rx_remain_len, rx_pkt_len;
 +      u16 pool_index = 0;
        u8 *ptr;
  
        spin_lock(&hif_dev->rx_lock);
        spin_unlock(&hif_dev->rx_lock);
  
        while (index < len) {
 +              u16 pkt_len;
 +              u16 pkt_tag;
 +              u16 pad_len;
 +              int chk_idx;
 +
                ptr = (u8 *) skb->data;
  
                pkt_len = ptr[index] + (ptr[index+1] << 8);
                pkt_tag = ptr[index+2] + (ptr[index+3] << 8);
  
 -              if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) {
 -                      u16 pad_len;
 -
 -                      pad_len = 4 - (pkt_len & 0x3);
 -                      if (pad_len == 4)
 -                              pad_len = 0;
 -
 -                      chk_idx = index;
 -                      index = index + 4 + pkt_len + pad_len;
 -
 -                      if (index > MAX_RX_BUF_SIZE) {
 -                              spin_lock(&hif_dev->rx_lock);
 -                              hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
 -                              hif_dev->rx_transfer_len =
 -                                      MAX_RX_BUF_SIZE - chk_idx - 4;
 -                              hif_dev->rx_pad_len = pad_len;
 -
 -                              nskb = __dev_alloc_skb(pkt_len + 32,
 -                                                     GFP_ATOMIC);
 -                              if (!nskb) {
 -                                      dev_err(&hif_dev->udev->dev,
 -                                      "ath9k_htc: RX memory allocation"
 -                                      " error\n");
 -                                      spin_unlock(&hif_dev->rx_lock);
 -                                      goto err;
 -                              }
 -                              skb_reserve(nskb, 32);
 -                              RX_STAT_INC(skb_allocated);
 -
 -                              memcpy(nskb->data, &(skb->data[chk_idx+4]),
 -                                     hif_dev->rx_transfer_len);
 -
 -                              /* Record the buffer pointer */
 -                              hif_dev->remain_skb = nskb;
 +              if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) {
 +                      RX_STAT_INC(skb_dropped);
 +                      return;
 +              }
 +
 +              pad_len = 4 - (pkt_len & 0x3);
 +              if (pad_len == 4)
 +                      pad_len = 0;
 +
 +              chk_idx = index;
 +              index = index + 4 + pkt_len + pad_len;
 +
 +              if (index > MAX_RX_BUF_SIZE) {
 +                      spin_lock(&hif_dev->rx_lock);
 +                      hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
 +                      hif_dev->rx_transfer_len =
 +                              MAX_RX_BUF_SIZE - chk_idx - 4;
 +                      hif_dev->rx_pad_len = pad_len;
 +
 +                      nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
 +                      if (!nskb) {
 +                              dev_err(&hif_dev->udev->dev,
 +                                      "ath9k_htc: RX memory allocation error\n");
                                spin_unlock(&hif_dev->rx_lock);
 -                      } else {
 -                              nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
 -                              if (!nskb) {
 -                                      dev_err(&hif_dev->udev->dev,
 -                                      "ath9k_htc: RX memory allocation"
 -                                      " error\n");
 -                                      goto err;
 -                              }
 -                              skb_reserve(nskb, 32);
 -                              RX_STAT_INC(skb_allocated);
 -
 -                              memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
 -                              skb_put(nskb, pkt_len);
 -                              skb_pool[pool_index++] = nskb;
 +                              goto err;
                        }
 +                      skb_reserve(nskb, 32);
 +                      RX_STAT_INC(skb_allocated);
 +
 +                      memcpy(nskb->data, &(skb->data[chk_idx+4]),
 +                             hif_dev->rx_transfer_len);
 +
 +                      /* Record the buffer pointer */
 +                      hif_dev->remain_skb = nskb;
 +                      spin_unlock(&hif_dev->rx_lock);
                } else {
 -                      RX_STAT_INC(skb_dropped);
 -                      return;
 +                      nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
 +                      if (!nskb) {
 +                              dev_err(&hif_dev->udev->dev,
 +                                      "ath9k_htc: RX memory allocation error\n");
 +                              goto err;
 +                      }
 +                      skb_reserve(nskb, 32);
 +                      RX_STAT_INC(skb_allocated);
 +
 +                      memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
 +                      skb_put(nskb, pkt_len);
 +                      skb_pool[pool_index++] = nskb;
                }
        }
  
@@@ -469,7 -461,7 +469,7 @@@ err
  static void ath9k_hif_usb_rx_cb(struct urb *urb)
  {
        struct sk_buff *skb = (struct sk_buff *) urb->context;
 -      struct hif_device_usb *hif_dev = (struct hif_device_usb *)
 +      struct hif_device_usb *hif_dev =
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
  
@@@ -516,7 -508,7 +516,7 @@@ static void ath9k_hif_usb_reg_in_cb(str
  {
        struct sk_buff *skb = (struct sk_buff *) urb->context;
        struct sk_buff *nskb;
 -      struct hif_device_usb *hif_dev = (struct hif_device_usb *)
 +      struct hif_device_usb *hif_dev =
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
  
@@@ -784,8 -776,7 +784,8 @@@ static void ath9k_hif_usb_dealloc_urbs(
        ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
  }
  
 -static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
 +static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev,
 +                                   u32 drv_info)
  {
        int transfer, err;
        const void *data = hif_dev->firmware->data;
        }
        kfree(buf);
  
 -      switch (hif_dev->device_id) {
 -      case 0x7010:
 -      case 0x7015:
 -      case 0x9018:
 -      case 0xA704:
 -      case 0x1200:
 +      if (IS_AR7010_DEVICE(drv_info))
                firm_offset = AR7010_FIRMWARE_TEXT;
 -              break;
 -      default:
 +      else
                firm_offset = AR9271_FIRMWARE_TEXT;
 -              break;
 -      }
  
        /*
         * Issue FW download complete command to firmware.
        return 0;
  }
  
 -static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
 +static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info)
  {
        int ret, idx;
        struct usb_host_interface *alt = &hif_dev->interface->altsetting[0];
        }
  
        /* Download firmware */
 -      ret = ath9k_hif_usb_download_fw(hif_dev);
 +      ret = ath9k_hif_usb_download_fw(hif_dev, drv_info);
        if (ret) {
                dev_err(&hif_dev->udev->dev,
                        "ath9k_htc: Firmware - %s download failed\n",
  
        return 0;
  
 -err_fw_download:
 -      ath9k_hif_usb_dealloc_urbs(hif_dev);
  err_urb:
 +      ath9k_hif_usb_dealloc_urbs(hif_dev);
 +err_fw_download:
        release_firmware(hif_dev->firmware);
  err_fw_req:
        hif_dev->firmware = NULL;
@@@ -932,15 -931,23 +932,15 @@@ static int ath9k_hif_usb_probe(struct u
  
        /* Find out which firmware to load */
  
 -      switch(hif_dev->device_id) {
 -      case 0x7010:
 -      case 0x7015:
 -      case 0x9018:
 -      case 0xA704:
 -      case 0x1200:
 +      if (IS_AR7010_DEVICE(id->driver_info))
                if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
                        hif_dev->fw_name = FIRMWARE_AR7010_1_1;
                else
                        hif_dev->fw_name = FIRMWARE_AR7010;
 -              break;
 -      default:
 +      else
                hif_dev->fw_name = FIRMWARE_AR9271;
 -              break;
 -      }
  
 -      ret = ath9k_hif_usb_dev_init(hif_dev);
 +      ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info);
        if (ret) {
                ret = -EINVAL;
                goto err_hif_init_usb;
  
        ret = ath9k_htc_hw_init(hif_dev->htc_handle,
                                &hif_dev->udev->dev, hif_dev->device_id,
 -                              hif_dev->udev->product);
 +                              hif_dev->udev->product, id->driver_info);
        if (ret) {
                ret = -EINVAL;
                goto err_htc_hw_init;
@@@ -991,7 -998,8 +991,7 @@@ static void ath9k_hif_usb_reboot(struc
  static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
  {
        struct usb_device *udev = interface_to_usbdev(interface);
 -      struct hif_device_usb *hif_dev =
 -              (struct hif_device_usb *) usb_get_intfdata(interface);
 +      struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
  
        if (hif_dev) {
                ath9k_htc_hw_deinit(hif_dev->htc_handle,
  static int ath9k_hif_usb_suspend(struct usb_interface *interface,
                                 pm_message_t message)
  {
 -      struct hif_device_usb *hif_dev =
 -              (struct hif_device_usb *) usb_get_intfdata(interface);
 +      struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
  
+       /*
+        * The device has to be set to FULLSLEEP mode in case no
+        * interface is up.
+        */
+       if (!(hif_dev->flags & HIF_USB_START))
+               ath9k_htc_suspend(hif_dev->htc_handle);
        ath9k_hif_usb_dealloc_urbs(hif_dev);
  
        return 0;
  
  static int ath9k_hif_usb_resume(struct usb_interface *interface)
  {
 -      struct hif_device_usb *hif_dev =
 -              (struct hif_device_usb *) usb_get_intfdata(interface);
 +      struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
 +      struct htc_target *htc_handle = hif_dev->htc_handle;
        int ret;
  
        ret = ath9k_hif_usb_alloc_urbs(hif_dev);
                return ret;
  
        if (hif_dev->firmware) {
 -              ret = ath9k_hif_usb_download_fw(hif_dev);
 +              ret = ath9k_hif_usb_download_fw(hif_dev,
 +                              htc_handle->drv_priv->ah->hw_version.usbdev);
                if (ret)
                        goto fail_resume;
        } else {
  
        mdelay(100);
  
 -      ret = ath9k_htc_resume(hif_dev->htc_handle);
 +      ret = ath9k_htc_resume(htc_handle);
  
        if (ret)
                goto fail_resume;
index afe39a911906d4e5546a02fc90a36f77d5f26dce,c3b561daa6c1035a68f4b27da92914ba4e601399..fdf9d5fe8cc0bc7c41d6a8682dfcc9521f165e10
@@@ -368,7 -368,7 +368,7 @@@ struct ath9k_htc_priv 
        u16 seq_no;
        u32 bmiss_cnt;
  
 -      struct ath9k_hw_cal_data caldata[38];
 +      struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS];
  
        spinlock_t beacon_lock;
  
@@@ -455,15 -455,18 +455,18 @@@ u32 ath9k_htc_calcrxfilter(struct ath9k
  void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv);
  void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
  void ath9k_ps_work(struct work_struct *work);
+ bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+                       enum ath9k_power_mode mode);
  
  void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
  void ath9k_init_leds(struct ath9k_htc_priv *priv);
  void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
  
  int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
 -                         u16 devid, char *product);
 +                         u16 devid, char *product, u32 drv_info);
  void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
  #ifdef CONFIG_PM
+ void ath9k_htc_suspend(struct htc_target *htc_handle);
  int ath9k_htc_resume(struct htc_target *htc_handle);
  #endif
  #ifdef CONFIG_ATH9K_HTC_DEBUGFS
index 93f3f615218be9d866afdb4f8b7c7bbeac863258,8776f49ffd41bf2a40f080798fe6c5173b80c9b4..0f6be350fd3cce6db5f9dbffd4c994f6780ff9ca
@@@ -181,8 -181,7 +181,8 @@@ static inline int ath9k_htc_connect_svc
        return htc_connect_service(priv->htc, &req, ep_id);
  }
  
 -static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
 +static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
 +                                 u32 drv_info)
  {
        int ret;
  
         * the HIF layer, shouldn't matter much.
         */
  
 -      switch(devid) {
 -      case 0x7010:
 -      case 0x7015:
 -      case 0x9018:
 -      case 0xA704:
 -      case 0x1200:
 +      if (IS_AR7010_DEVICE(drv_info))
                priv->htc->credits = 45;
 -              break;
 -      default:
 +      else
                priv->htc->credits = 33;
 -      }
  
        ret = htc_init(priv->htc);
        if (ret)
@@@ -288,9 -294,9 +288,9 @@@ static unsigned int ath9k_regread(void 
                          (u8 *) &val, sizeof(val),
                          100);
        if (unlikely(r)) {
 -              ath_print(common, ATH_DBG_WMI,
 -                        "REGISTER READ FAILED: (0x%04x, %d)\n",
 -                         reg_offset, r);
 +              ath_dbg(common, ATH_DBG_WMI,
 +                      "REGISTER READ FAILED: (0x%04x, %d)\n",
 +                      reg_offset, r);
                return -EIO;
        }
  
@@@ -302,7 -308,7 +302,7 @@@ static void ath9k_regwrite_single(void 
        struct ath_hw *ah = (struct ath_hw *) hw_priv;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
 -      __be32 buf[2] = {
 +      const __be32 buf[2] = {
                cpu_to_be32(reg_offset),
                cpu_to_be32(val),
        };
                          (u8 *) &val, sizeof(val),
                          100);
        if (unlikely(r)) {
 -              ath_print(common, ATH_DBG_WMI,
 -                        "REGISTER WRITE FAILED:(0x%04x, %d)\n",
 -                        reg_offset, r);
 +              ath_dbg(common, ATH_DBG_WMI,
 +                      "REGISTER WRITE FAILED:(0x%04x, %d)\n",
 +                      reg_offset, r);
        }
  }
  
@@@ -345,9 -351,9 +345,9 @@@ static void ath9k_regwrite_buffer(void 
                          (u8 *) &rsp_status, sizeof(rsp_status),
                          100);
                if (unlikely(r)) {
 -                      ath_print(common, ATH_DBG_WMI,
 -                                "REGISTER WRITE FAILED, multi len: %d\n",
 -                                priv->wmi->multi_write_idx);
 +                      ath_dbg(common, ATH_DBG_WMI,
 +                              "REGISTER WRITE FAILED, multi len: %d\n",
 +                              priv->wmi->multi_write_idx);
                }
                priv->wmi->multi_write_idx = 0;
        }
@@@ -395,9 -401,9 +395,9 @@@ static void ath9k_regwrite_flush(void *
                          (u8 *) &rsp_status, sizeof(rsp_status),
                          100);
                if (unlikely(r)) {
 -                      ath_print(common, ATH_DBG_WMI,
 -                                "REGISTER WRITE FAILED, multi len: %d\n",
 -                                priv->wmi->multi_write_idx);
 +                      ath_dbg(common, ATH_DBG_WMI,
 +                              "REGISTER WRITE FAILED, multi len: %d\n",
 +                              priv->wmi->multi_write_idx);
                }
                priv->wmi->multi_write_idx = 0;
        }
@@@ -469,9 -475,9 +469,9 @@@ static void setup_ht_cap(struct ath9k_h
        tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
        rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "TX streams %d, RX streams: %d\n",
 -                tx_streams, rx_streams);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "TX streams %d, RX streams: %d\n",
 +              tx_streams, rx_streams);
  
        if (tx_streams != rx_streams) {
                ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
@@@ -495,31 -501,37 +495,31 @@@ static int ath9k_init_queues(struct ath
  
        priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
        if (priv->beaconq == -1) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup BEACON xmit queue\n");
 +              ath_err(common, "Unable to setup BEACON xmit queue\n");
                goto err;
        }
  
        priv->cabq = ath9k_htc_cabq_setup(priv);
        if (priv->cabq == -1) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup CAB xmit queue\n");
 +              ath_err(common, "Unable to setup CAB xmit queue\n");
                goto err;
        }
  
        if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup xmit queue for BE traffic\n");
 +              ath_err(common, "Unable to setup xmit queue for BE traffic\n");
                goto err;
        }
  
        if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup xmit queue for BK traffic\n");
 +              ath_err(common, "Unable to setup xmit queue for BK traffic\n");
                goto err;
        }
        if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup xmit queue for VI traffic\n");
 +              ath_err(common, "Unable to setup xmit queue for VI traffic\n");
                goto err;
        }
        if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to setup xmit queue for VO traffic\n");
 +              ath_err(common, "Unable to setup xmit queue for VO traffic\n");
                goto err;
        }
  
@@@ -537,9 -549,9 +537,9 @@@ static void ath9k_init_crypto(struct at
        /* Get the hardware key cache size. */
        common->keymax = priv->ah->caps.keycache_size;
        if (common->keymax > ATH_KEYMAX) {
 -              ath_print(common, ATH_DBG_ANY,
 -                        "Warning, using only %u entries in %u key cache\n",
 -                        ATH_KEYMAX, common->keymax);
 +              ath_dbg(common, ATH_DBG_ANY,
 +                      "Warning, using only %u entries in %u key cache\n",
 +                      ATH_KEYMAX, common->keymax);
                common->keymax = ATH_KEYMAX;
        }
  
@@@ -615,8 -627,7 +615,8 @@@ static void ath9k_init_btcoex(struct at
  }
  
  static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 -                         u16 devid, char *product)
 +                         u16 devid, char *product,
 +                         u32 drv_info)
  {
        struct ath_hw *ah = NULL;
        struct ath_common *common;
  
        ah->hw_version.devid = devid;
        ah->hw_version.subsysid = 0; /* FIXME */
 +      ah->hw_version.usbdev = drv_info;
 +      ah->ah_flags |= AH_USE_EEPROM;
        priv->ah = ah;
  
        common = ath9k_hw_common(ah);
  
        ret = ath9k_hw_init(ah);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to initialize hardware; "
 -                        "initialization status: %d\n", ret);
 +              ath_err(common,
 +                      "Unable to initialize hardware; initialization status: %d\n",
 +                      ret);
                goto err_hw;
        }
  
        ret = ath9k_htc_init_debug(ah);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to create debugfs files\n");
 +              ath_err(common, "Unable to create debugfs files\n");
                goto err_debug;
        }
  
@@@ -714,8 -724,7 +714,8 @@@ static void ath9k_set_hw_capab(struct a
                IEEE80211_HW_HAS_RATE_CONTROL |
                IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_SUPPORTS_PS |
 -              IEEE80211_HW_PS_NULLFUNC_STACK;
 +              IEEE80211_HW_PS_NULLFUNC_STACK |
 +              IEEE80211_HW_NEED_DTIM_PERIOD;
  
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
  }
  
  static int ath9k_init_device(struct ath9k_htc_priv *priv,
 -                           u16 devid, char *product)
 +                           u16 devid, char *product, u32 drv_info)
  {
        struct ieee80211_hw *hw = priv->hw;
        struct ath_common *common;
        struct ath_regulatory *reg;
  
        /* Bring up device */
 -      error = ath9k_init_priv(priv, devid, product);
 +      error = ath9k_init_priv(priv, devid, product, drv_info);
        if (error != 0)
                goto err_init;
  
@@@ -820,7 -829,7 +820,7 @@@ err_init
  }
  
  int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
 -                         u16 devid, char *product)
 +                         u16 devid, char *product, u32 drv_info)
  {
        struct ieee80211_hw *hw;
        struct ath9k_htc_priv *priv;
                goto err_free;
        }
  
 -      ret = ath9k_init_htc_services(priv, devid);
 +      ret = ath9k_init_htc_services(priv, devid, drv_info);
        if (ret)
                goto err_init;
  
        /* The device may have been unplugged earlier. */
        priv->op_flags &= ~OP_UNPLUGGED;
  
 -      ret = ath9k_init_device(priv, devid, product);
 +      ret = ath9k_init_device(priv, devid, product, drv_info);
        if (ret)
                goto err_init;
  
@@@ -882,17 -891,22 +882,23 @@@ void ath9k_htc_disconnect_device(struc
  }
  
  #ifdef CONFIG_PM
+ void ath9k_htc_suspend(struct htc_target *htc_handle)
+ {
+       ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
+ }
  int ath9k_htc_resume(struct htc_target *htc_handle)
  {
 +      struct ath9k_htc_priv *priv = htc_handle->drv_priv;
        int ret;
  
 -      ret = ath9k_htc_wait_for_target(htc_handle->drv_priv);
 +      ret = ath9k_htc_wait_for_target(priv);
        if (ret)
                return ret;
  
 -      ret = ath9k_init_htc_services(htc_handle->drv_priv,
 -                            htc_handle->drv_priv->ah->hw_version.devid);
 +      ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
 +                                    priv->ah->hw_version.usbdev);
        return ret;
  }
  #endif
index fe82e5e30d82ed2849cb86b02cf1174687c7a202,51977caca47fd6d456e521cff4511e1079f2e09a..20ea75a44e52eec6cf35bee1675221765a01e93d
@@@ -29,7 -29,7 +29,7 @@@ static void ath_update_txpow(struct ath
        struct ath_hw *ah = priv->ah;
  
        if (priv->curtxpow != priv->txpowlimit) {
 -              ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
 +              ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false);
                /* read back in case value is clamped */
                priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
        }
@@@ -63,8 -63,8 +63,8 @@@ static enum htc_phymode ath9k_htc_get_c
        return mode;
  }
  
static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
-                              enum ath9k_power_mode mode)
+ bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+                       enum ath9k_power_mode mode)
  {
        bool ret;
  
@@@ -143,18 -143,18 +143,18 @@@ static int ath9k_htc_set_channel(struc
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
        WMI_CMD(WMI_STOP_RECV_CMDID);
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
 -                priv->ah->curchan->channel,
 -                channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
 -                fastcc);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
 +              priv->ah->curchan->channel,
 +              channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
 +              fastcc);
  
        caldata = &priv->caldata[channel->hw_value];
        ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset channel (%u Mhz) "
 -                        "reset status %d\n", channel->center_freq, ret);
 +              ath_err(common,
 +                      "Unable to reset channel (%u Mhz) reset status %d\n",
 +                      channel->center_freq, ret);
                goto err;
        }
  
@@@ -263,16 -263,15 +263,16 @@@ static int ath9k_htc_add_station(struc
        WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
        if (ret) {
                if (sta)
 -                      ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to add station entry for: %pM\n", sta->addr);
 +                      ath_err(common,
 +                              "Unable to add station entry for: %pM\n",
 +                              sta->addr);
                return ret;
        }
  
        if (sta)
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Added a station entry for: %pM (idx: %d)\n",
 -                        sta->addr, tsta.sta_index);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Added a station entry for: %pM (idx: %d)\n",
 +                      sta->addr, tsta.sta_index);
  
        priv->nstations++;
        return 0;
@@@ -297,16 -296,16 +297,16 @@@ static int ath9k_htc_remove_station(str
        WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
        if (ret) {
                if (sta)
 -                      ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to remove station entry for: %pM\n",
 -                        sta->addr);
 +                      ath_err(common,
 +                              "Unable to remove station entry for: %pM\n",
 +                              sta->addr);
                return ret;
        }
  
        if (sta)
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Removed a station entry for: %pM (idx: %d)\n",
 -                        sta->addr, sta_idx);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Removed a station entry for: %pM (idx: %d)\n",
 +                      sta->addr, sta_idx);
  
        priv->nstations--;
        return 0;
@@@ -391,8 -390,8 +391,8 @@@ static int ath9k_htc_send_rate_cmd(stru
  
        WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to initialize Rate information on target\n");
 +              ath_err(common,
 +                      "Unable to initialize Rate information on target\n");
        }
  
        return ret;
@@@ -409,9 -408,9 +409,9 @@@ static void ath9k_htc_init_rate(struct 
        ath9k_htc_setup_rate(priv, sta, &trate);
        ret = ath9k_htc_send_rate_cmd(priv, &trate);
        if (!ret)
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Updated target sta: %pM, rate caps: 0x%X\n",
 -                        sta->addr, be32_to_cpu(trate.capflags));
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Updated target sta: %pM, rate caps: 0x%X\n",
 +                      sta->addr, be32_to_cpu(trate.capflags));
  }
  
  static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
  
        ret = ath9k_htc_send_rate_cmd(priv, &trate);
        if (!ret)
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Updated target sta: %pM, rate caps: 0x%X\n",
 -                        bss_conf->bssid, be32_to_cpu(trate.capflags));
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Updated target sta: %pM, rate caps: 0x%X\n",
 +                      bss_conf->bssid, be32_to_cpu(trate.capflags));
  }
  
  static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
  
        WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
        if (ret)
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Unable to %s TX aggregation for (%pM, %d)\n",
 -                        (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Unable to %s TX aggregation for (%pM, %d)\n",
 +                      (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
        else
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "%s TX aggregation for (%pM, %d)\n",
 -                        (aggr.aggr_enable) ? "Starting" : "Stopping",
 -                        sta->addr, tid);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "%s TX aggregation for (%pM, %d)\n",
 +                      (aggr.aggr_enable) ? "Starting" : "Stopping",
 +                      sta->addr, tid);
  
        spin_lock_bh(&priv->tx_lock);
        ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
@@@ -725,7 -724,7 +725,7 @@@ void ath9k_ani_work(struct work_struct 
        /* Long calibration runs independently of short calibration. */
        if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
                longcal = true;
 -              ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
 +              ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
                common->ani.longcal_timer = timestamp;
        }
  
                if ((timestamp - common->ani.shortcal_timer) >=
                    short_cal_interval) {
                        shortcal = true;
 -                      ath_print(common, ATH_DBG_ANI,
 -                                "shortcal @%lu\n", jiffies);
 +                      ath_dbg(common, ATH_DBG_ANI,
 +                              "shortcal @%lu\n", jiffies);
                        common->ani.shortcal_timer = timestamp;
                        common->ani.resetcal_timer = timestamp;
                }
@@@ -896,8 -895,8 +896,8 @@@ static int ath9k_register_led(struct at
  
        ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
        if (ret)
 -              ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
 -                        "Failed to register led:%s", led->name);
 +              ath_err(ath9k_hw_common(priv->ah),
 +                      "Failed to register led:%s", led->name);
        else
                led->registered = 1;
  
@@@ -1025,9 -1024,9 +1025,9 @@@ static void ath9k_htc_radio_enable(stru
        /* Reset the HW */
        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset hardware; reset status %d "
 -                        "(freq %u MHz)\n", ret, ah->curchan->channel);
 +              ath_err(common,
 +                      "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 +                      ret, ah->curchan->channel);
        }
  
        ath_update_txpow(priv);
@@@ -1088,9 -1087,9 +1088,9 @@@ static void ath9k_htc_radio_disable(str
        /* Reset the HW */
        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset hardware; reset status %d "
 -                        "(freq %u MHz)\n", ret, ah->curchan->channel);
 +              ath_err(common,
 +                      "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 +                      ret, ah->curchan->channel);
        }
  
        /* Disable the PHY */
@@@ -1125,15 -1124,15 +1125,15 @@@ static int ath9k_htc_tx(struct ieee8021
        ret = ath9k_htc_tx_start(priv, skb);
        if (ret != 0) {
                if (ret == -ENOMEM) {
 -                      ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
 -                                "Stopping TX queues\n");
 +                      ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
 +                              "Stopping TX queues\n");
                        ieee80211_stop_queues(hw);
                        spin_lock_bh(&priv->tx_lock);
                        priv->tx_queues_stop = true;
                        spin_unlock_bh(&priv->tx_lock);
                } else {
 -                      ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
 -                                "Tx failed");
 +                      ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
 +                              "Tx failed\n");
                }
                goto fail_tx;
        }
@@@ -1159,9 -1158,9 +1159,9 @@@ static int ath9k_htc_start(struct ieee8
  
        mutex_lock(&priv->mutex);
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Starting driver with initial channel: %d MHz\n",
 -                curchan->center_freq);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Starting driver with initial channel: %d MHz\n",
 +              curchan->center_freq);
  
        /* Ensure that HW is awake before flushing RX */
        ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
        ath9k_hw_htc_resetinit(ah);
        ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset hardware; reset status %d "
 -                        "(freq %u MHz)\n", ret, curchan->center_freq);
 +              ath_err(common,
 +                      "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 +                      ret, curchan->center_freq);
                mutex_unlock(&priv->mutex);
                return ret;
        }
@@@ -1224,7 -1223,7 +1224,7 @@@ static void ath9k_htc_stop(struct ieee8
        mutex_lock(&priv->mutex);
  
        if (priv->op_flags & OP_INVALID) {
 -              ath_print(common, ATH_DBG_ANY, "Device not present\n");
 +              ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
                mutex_unlock(&priv->mutex);
                return;
        }
        /* Remove monitor interface here */
        if (ah->opmode == NL80211_IFTYPE_MONITOR) {
                if (ath9k_htc_remove_monitor_interface(priv))
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "Unable to remove monitor interface\n");
 +                      ath_err(common, "Unable to remove monitor interface\n");
                else
 -                      ath_print(common, ATH_DBG_CONFIG,
 -                                "Monitor interface removed\n");
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "Monitor interface removed\n");
        }
  
        if (ah->btcoex_hw.enabled) {
  
        priv->op_flags |= OP_INVALID;
  
 -      ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
        mutex_unlock(&priv->mutex);
  }
  
@@@ -1298,14 -1298,14 +1298,14 @@@ static int ath9k_htc_add_interface(stru
                hvif.opmode = cpu_to_be32(HTC_M_IBSS);
                break;
        default:
 -              ath_print(common, ATH_DBG_FATAL,
 +              ath_err(common,
                        "Interface type %d not yet supported\n", vif->type);
                ret = -EOPNOTSUPP;
                goto out;
        }
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Attach a VIF of type: %d\n", vif->type);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Attach a VIF of type: %d\n", vif->type);
  
        priv->ah->opmode = vif->type;
  
  
        ret = ath9k_htc_update_cap_target(priv);
        if (ret)
 -              ath_print(common, ATH_DBG_CONFIG, "Failed to update"
 -                        " capability in target \n");
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Failed to update capability in target\n");
  
        priv->vif = vif;
  out:
@@@ -1349,7 -1349,7 +1349,7 @@@ static void ath9k_htc_remove_interface(
        int ret = 0;
        u8 cmd_rsp;
  
 -      ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
  
        mutex_lock(&priv->mutex);
        ath9k_htc_ps_wakeup(priv);
@@@ -1386,8 -1386,8 +1386,8 @@@ static int ath9k_htc_config(struct ieee
                mutex_unlock(&priv->htc_pm_lock);
  
                if (enable_radio) {
 -                      ath_print(common, ATH_DBG_CONFIG,
 -                                "not-idle: enabling radio\n");
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "not-idle: enabling radio\n");
                        ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
                        ath9k_htc_radio_enable(hw);
                }
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
  
 -              ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 -                        curchan->center_freq);
 +              ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 +                      curchan->center_freq);
  
 -              ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
 +              ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
 +                                        hw->conf.channel,
 +                                        hw->conf.channel_type);
  
                if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "Unable to set channel\n");
 +                      ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&priv->mutex);
                        return -EINVAL;
                }
  
        }
 +
        if (changed & IEEE80211_CONF_CHANGE_PS) {
                if (conf->flags & IEEE80211_CONF_PS) {
                        ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
                }
        }
  
 +      if (changed & IEEE80211_CONF_CHANGE_POWER) {
 +              priv->txpowlimit = 2 * conf->power_level;
 +              ath_update_txpow(priv);
 +      }
 +
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
                        if (ath9k_htc_add_monitor_interface(priv))
 -                              ath_print(common, ATH_DBG_FATAL,
 -                                        "Failed to set monitor mode\n");
 +                              ath_err(common, "Failed to set monitor mode\n");
                        else
 -                              ath_print(common, ATH_DBG_CONFIG,
 -                                        "HW opmode set to Monitor mode\n");
 +                              ath_dbg(common, ATH_DBG_CONFIG,
 +                                      "HW opmode set to Monitor mode\n");
                }
        }
  
                }
                mutex_unlock(&priv->htc_pm_lock);
  
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "idle: disabling radio\n");
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "idle: disabling radio\n");
                ath9k_htc_radio_disable(hw);
        }
  
@@@ -1484,8 -1478,8 +1484,8 @@@ static void ath9k_htc_configure_filter(
        rfilt = ath9k_htc_calcrxfilter(priv);
        ath9k_hw_setrxfilter(priv->ah, rfilt);
  
 -      ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
 -                "Set HW RX filter: 0x%x\n", rfilt);
 +      ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
 +              "Set HW RX filter: 0x%x\n", rfilt);
  
        ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
@@@ -1548,14 -1542,15 +1548,14 @@@ static int ath9k_htc_conf_tx(struct iee
  
        qnum = get_hw_qnum(queue, priv->hwq_map);
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Configure tx [queue/hwq] [%d/%d],  "
 -                "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 -                queue, qnum, params->aifs, params->cw_min,
 -                params->cw_max, params->txop);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Configure tx [queue/hwq] [%d/%d],  aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 +              queue, qnum, params->aifs, params->cw_min,
 +              params->cw_max, params->txop);
  
        ret = ath_htc_txq_update(priv, qnum, &qi);
        if (ret) {
 -              ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
 +              ath_err(common, "TXQ Update failed\n");
                goto out;
        }
  
@@@ -1583,7 -1578,7 +1583,7 @@@ static int ath9k_htc_set_key(struct iee
                return -ENOSPC;
  
        mutex_lock(&priv->mutex);
 -      ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
        ath9k_htc_ps_wakeup(priv);
  
        switch (cmd) {
@@@ -1629,7 -1624,7 +1629,7 @@@ static void ath9k_htc_bss_info_changed(
        if (changed & BSS_CHANGED_ASSOC) {
                common->curaid = bss_conf->assoc ?
                                 bss_conf->aid : 0;
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
                        bss_conf->assoc);
  
                if (bss_conf->assoc) {
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                ath9k_hw_write_associd(ah);
  
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "BSSID: %pM aid: 0x%x\n",
 -                        common->curbssid, common->curaid);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "BSSID: %pM aid: 0x%x\n",
 +                      common->curbssid, common->curaid);
        }
  
        if ((changed & BSS_CHANGED_BEACON_INT) ||
        }
  
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 -                        bss_conf->use_short_preamble);
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 +                      bss_conf->use_short_preamble);
                if (bss_conf->use_short_preamble)
                        priv->op_flags |= OP_PREAMBLE_SHORT;
                else
        }
  
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 -                        bss_conf->use_cts_prot);
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 +                      bss_conf->use_cts_prot);
                if (bss_conf->use_cts_prot &&
                    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
                        priv->op_flags |= OP_PROTECT_ENABLE;
@@@ -1767,7 -1762,8 +1767,7 @@@ static int ath9k_htc_ampdu_action(struc
                spin_unlock_bh(&priv->tx_lock);
                break;
        default:
 -              ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
 -                        "Unknown AMPDU action\n");
 +              ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
        }
  
        return ret;
index f05462ace4e85b56c4293de092acfced89498ca7,c996963ab33927c027f3fb019200261c0ac07d18..e3d2ebf00e2ed58b1c67540bdb28023f4c25958f
  static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
                                        struct ath9k_tx_queue_info *qi)
  {
 -      ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
 -                "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
 -                ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
 -                ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
 -                ah->txurn_interrupt_mask);
 +      ath_dbg(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
 +              "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
 +              ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
 +              ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
 +              ah->txurn_interrupt_mask);
  
        ENABLE_REGWRITE_BUFFER(ah);
  
@@@ -56,8 -56,8 +56,8 @@@ EXPORT_SYMBOL(ath9k_hw_puttxbuf)
  
  void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
  {
 -      ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
 -                "Enable TXE on queue: %u\n", q);
 +      ath_dbg(ath9k_hw_common(ah), ATH_DBG_QUEUE,
 +              "Enable TXE on queue: %u\n", q);
        REG_WRITE(ah, AR_Q_TXE, 1 << q);
  }
  EXPORT_SYMBOL(ath9k_hw_txstart);
@@@ -117,11 -117,12 +117,11 @@@ EXPORT_SYMBOL(ath9k_hw_numtxpending)
  bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
  {
        u32 txcfg, curLevel, newLevel;
 -      enum ath9k_int omask;
  
        if (ah->tx_trig_level >= ah->config.max_txtrig_level)
                return false;
  
 -      omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
 +      ath9k_hw_disable_interrupts(ah);
  
        txcfg = REG_READ(ah, AR_TXCFG);
        curLevel = MS(txcfg, AR_FTRIG);
                REG_WRITE(ah, AR_TXCFG,
                          (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
  
 -      ath9k_hw_set_interrupts(ah, omask);
 +      ath9k_hw_enable_interrupts(ah);
  
        ah->tx_trig_level = newLevel;
  
@@@ -154,15 -155,15 +154,15 @@@ bool ath9k_hw_stoptxdma(struct ath_hw *
        u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
  
        if (q >= pCap->total_queues) {
 -              ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
 -                        "invalid queue: %u\n", q);
 +              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_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
 -                        "inactive queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Stopping TX DMA, inactive queue: %u\n", q);
                return false;
        }
  
        }
  
        if (ath9k_hw_numtxpending(ah, q)) {
 -              ath_print(common, ATH_DBG_QUEUE,
 -                        "%s: Num of pending TX Frames %d on Q %d\n",
 -                        __func__, ath9k_hw_numtxpending(ah, q), 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);
                        if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
                                break;
  
 -                      ath_print(common, ATH_DBG_QUEUE,
 -                                "TSF has moved while trying to set "
 -                                "quiet time TSF: 0x%08x\n", tsfLow);
 +                      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);
                wait = wait_time;
                while (ath9k_hw_numtxpending(ah, q)) {
                        if ((--wait) == 0) {
 -                              ath_print(common, ATH_DBG_FATAL,
 -                                        "Failed to stop TX DMA in 100 "
 -                                        "msec after killing last frame\n");
 +                              ath_err(common,
 +                                      "Failed to stop TX DMA in 100 msec after killing last frame\n");
                                break;
                        }
                        udelay(ATH9K_TIME_QUANTUM);
@@@ -238,19 -240,19 +238,19 @@@ bool ath9k_hw_set_txq_props(struct ath_
        struct ath9k_tx_queue_info *qi;
  
        if (q >= pCap->total_queues) {
 -              ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
 -                        "invalid queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Set TXQ properties, invalid queue: %u\n", q);
                return false;
        }
  
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 -              ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
 -                        "inactive queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Set TXQ properties, inactive queue: %u\n", q);
                return false;
        }
  
 -      ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
 +      ath_dbg(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
  
        qi->tqi_ver = qinfo->tqi_ver;
        qi->tqi_subtype = qinfo->tqi_subtype;
@@@ -309,15 -311,15 +309,15 @@@ bool ath9k_hw_get_txq_props(struct ath_
        struct ath9k_tx_queue_info *qi;
  
        if (q >= pCap->total_queues) {
 -              ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
 -                        "invalid queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Get TXQ properties, invalid queue: %u\n", q);
                return false;
        }
  
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 -              ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
 -                        "inactive queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Get TXQ properties, inactive queue: %u\n", q);
                return false;
        }
  
@@@ -367,20 -369,23 +367,20 @@@ int ath9k_hw_setuptxqueue(struct ath_h
                            ATH9K_TX_QUEUE_INACTIVE)
                                break;
                if (q == pCap->total_queues) {
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "No available TX queue\n");
 +                      ath_err(common, "No available TX queue\n");
                        return -1;
                }
                break;
        default:
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Invalid TX queue type: %u\n", type);
 +              ath_err(common, "Invalid TX queue type: %u\n", type);
                return -1;
        }
  
 -      ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
 +      ath_dbg(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
  
        qi = &ah->txq[q];
        if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "TX queue: %u already active\n", q);
 +              ath_err(common, "TX queue: %u already active\n", q);
                return -1;
        }
        memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
@@@ -412,18 -417,18 +412,18 @@@ bool ath9k_hw_releasetxqueue(struct ath
        struct ath9k_tx_queue_info *qi;
  
        if (q >= pCap->total_queues) {
 -              ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
 -                        "invalid queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Release TXQ, invalid queue: %u\n", q);
                return false;
        }
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 -              ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
 -                        "inactive queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Release TXQ, inactive queue: %u\n", q);
                return false;
        }
  
 -      ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
 +      ath_dbg(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
  
        qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
        ah->txok_interrupt_mask &= ~(1 << q);
@@@ -446,19 -451,19 +446,19 @@@ bool ath9k_hw_resettxqueue(struct ath_h
        u32 cwMin, chanCwMin, value;
  
        if (q >= pCap->total_queues) {
 -              ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
 -                        "invalid queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Reset TXQ, invalid queue: %u\n", q);
                return false;
        }
  
        qi = &ah->txq[q];
        if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
 -              ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
 -                        "inactive queue: %u\n", q);
 +              ath_dbg(common, ATH_DBG_QUEUE,
 +                      "Reset TXQ, inactive queue: %u\n", q);
                return true;
        }
  
 -      ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
 +      ath_dbg(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
  
        if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
                if (chan && IS_CHAN_B(chan))
@@@ -698,8 -703,7 +698,7 @@@ int ath9k_hw_rxprocdesc(struct ath_hw *
                        rs->rs_phyerr = phyerr;
                } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
-               else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
-                        rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
+               else if (ads.ds_rxstatus8 & AR_MichaelErr)
                        rs->rs_status |= ATH9K_RXERR_MIC;
                else if (ads.ds_rxstatus8 & AR_KeyMiss)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
@@@ -731,9 -735,9 +730,9 @@@ bool ath9k_hw_setrxabort(struct ath_hw 
                                     AR_DIAG_RX_ABORT));
  
                        reg = REG_READ(ah, AR_OBS_BUS_1);
 -                      ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
 -                                "RX failed to go idle in 10 ms RXSM=0x%x\n",
 -                                reg);
 +                      ath_err(ath9k_hw_common(ah),
 +                              "RX failed to go idle in 10 ms RXSM=0x%x\n",
 +                              reg);
  
                        return false;
                }
@@@ -762,6 -766,14 +761,6 @@@ void ath9k_hw_startpcureceive(struct at
  }
  EXPORT_SYMBOL(ath9k_hw_startpcureceive);
  
 -void ath9k_hw_stoppcurecv(struct ath_hw *ah)
 -{
 -      REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
 -
 -      ath9k_hw_disable_mib_counters(ah);
 -}
 -EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
 -
  void ath9k_hw_abortpcurecv(struct ath_hw *ah)
  {
        REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
@@@ -787,11 -799,12 +786,11 @@@ bool ath9k_hw_stopdmarecv(struct ath_h
        }
  
        if (i == 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "DMA failed to stop in %d ms "
 -                        "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
 -                        AH_RX_STOP_DMA_TIMEOUT / 1000,
 -                        REG_READ(ah, AR_CR),
 -                        REG_READ(ah, AR_DIAG_SW));
 +              ath_err(common,
 +                      "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
 +                      AH_RX_STOP_DMA_TIMEOUT / 1000,
 +                      REG_READ(ah, AR_CR),
 +                      REG_READ(ah, AR_DIAG_SW));
                return false;
        } else {
                return true;
@@@ -835,59 -848,28 +834,59 @@@ bool ath9k_hw_intrpend(struct ath_hw *a
  }
  EXPORT_SYMBOL(ath9k_hw_intrpend);
  
 -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
 -                                            enum ath9k_int ints)
 +void ath9k_hw_disable_interrupts(struct ath_hw *ah)
 +{
 +      struct ath_common *common = ath9k_hw_common(ah);
 +
 +      ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
 +      REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
 +      (void) REG_READ(ah, AR_IER);
 +      if (!AR_SREV_9100(ah)) {
 +              REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
 +              (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
 +
 +              REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
 +              (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
 +      }
 +}
 +EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 +
 +void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 +{
 +      struct ath_common *common = ath9k_hw_common(ah);
 +
 +      if (!(ah->imask & ATH9K_INT_GLOBAL))
 +              return;
 +
 +      ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
 +      REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
 +      if (!AR_SREV_9100(ah)) {
 +              REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
 +                        AR_INTR_MAC_IRQ);
 +              REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
 +
 +
 +              REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
 +                        AR_INTR_SYNC_DEFAULT);
 +              REG_WRITE(ah, AR_INTR_SYNC_MASK,
 +                        AR_INTR_SYNC_DEFAULT);
 +      }
 +      ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
 +              REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
 +}
 +EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
 +
 +void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
  {
        enum ath9k_int omask = ah->imask;
        u32 mask, mask2;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
  
 -      ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 +      if (!(ints & ATH9K_INT_GLOBAL))
 +              ath9k_hw_enable_interrupts(ah);
  
 -      if (omask & ATH9K_INT_GLOBAL) {
 -              ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
 -              REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
 -              (void) REG_READ(ah, AR_IER);
 -              if (!AR_SREV_9100(ah)) {
 -                      REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
 -                      (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
 -
 -                      REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
 -                      (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
 -              }
 -      }
 +      ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
  
        /* TODO: global int Ref count */
        mask = ints & ATH9K_INT_COMMON;
                        mask2 |= AR_IMR_S2_CST;
        }
  
 -      ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
 +      ath_dbg(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
        REG_WRITE(ah, AR_IMR, mask);
        ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
                           AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
                        REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
        }
  
 -      if (ints & ATH9K_INT_GLOBAL) {
 -              ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
 -              REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
 -              if (!AR_SREV_9100(ah)) {
 -                      REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
 -                                AR_INTR_MAC_IRQ);
 -                      REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
 -
 -
 -                      REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
 -                                AR_INTR_SYNC_DEFAULT);
 -                      REG_WRITE(ah, AR_INTR_SYNC_MASK,
 -                                AR_INTR_SYNC_DEFAULT);
 -              }
 -              ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
 -                        REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
 -      }
 +      ath9k_hw_enable_interrupts(ah);
  
 -      return omask;
 +      return;
  }
  EXPORT_SYMBOL(ath9k_hw_set_interrupts);
index 41a312a3d40125ce725641c3e87fbe21c762e4c1,c0c3464d3a861162e1142a0e2931a73aedae1fab..daa3c9feca66b8b5ec5f8913aaf09ae42627064e
@@@ -23,7 -23,7 +23,7 @@@ static void ath_update_txpow(struct ath
        struct ath_hw *ah = sc->sc_ah;
  
        if (sc->curtxpow != sc->config.txpowlimit) {
 -              ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
 +              ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
                /* read back in case value is clamped */
                sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
        }
@@@ -234,8 -234,6 +234,8 @@@ int ath_set_channel(struct ath_softc *s
  
        ath9k_ps_wakeup(sc);
  
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        /*
         * This is only performed if the channel settings have
         * actually changed.
         * hardware at the new frequency, and then re-enable
         * the relevant bits of the h/w.
         */
 -      ath9k_hw_set_interrupts(ah, 0);
 +      ath9k_hw_disable_interrupts(ah);
-       ath_drain_all_txq(sc, false);
+       stopped = ath_drain_all_txq(sc, false);
  
-       stopped = ath_stoprecv(sc);
 -      spin_lock_bh(&sc->rx.pcu_lock);
 -
+       if (!ath_stoprecv(sc))
+               stopped = false;
  
        /* XXX: do not flush receive queue here. We don't want
         * to flush data frames already in queue because of
        if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
                caldata = &aphy->caldata;
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
 -                sc->sc_ah->curchan->channel,
 -                channel->center_freq, conf_is_ht40(conf),
 -                fastcc);
 -
 -      spin_lock_bh(&sc->sc_resetlock);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
 +              sc->sc_ah->curchan->channel,
 +              channel->center_freq, conf_is_ht40(conf),
 +              fastcc);
  
        r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
        if (r) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset channel (%u MHz), "
 -                        "reset status %d\n",
 -                        channel->center_freq, r);
 -              spin_unlock_bh(&sc->sc_resetlock);
 -              spin_unlock_bh(&sc->rx.pcu_lock);
 +              ath_err(common,
 +                      "Unable to reset channel (%u MHz), reset status %d\n",
 +                      channel->center_freq, r);
                goto ps_restore;
        }
 -      spin_unlock_bh(&sc->sc_resetlock);
  
        if (ath_startrecv(sc) != 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to restart recv logic\n");
 +              ath_err(common, "Unable to restart recv logic\n");
                r = -EIO;
 -              spin_unlock_bh(&sc->rx.pcu_lock);
                goto ps_restore;
        }
  
 -      spin_unlock_bh(&sc->rx.pcu_lock);
 -
        ath_update_txpow(sc);
        ath9k_hw_set_interrupts(ah, ah->imask);
  
        }
  
   ps_restore:
 +      spin_unlock_bh(&sc->sc_pcu_lock);
 +
        ath9k_ps_restore(sc);
        return r;
  }
@@@ -332,7 -341,7 +333,7 @@@ void ath_paprd_calibrate(struct work_st
        struct ath_tx_control txctl;
        struct ath9k_hw_cal_data *caldata = ah->caldata;
        struct ath_common *common = ath9k_hw_common(ah);
 -      int qnum, ftype;
 +      int ftype;
        int chain_ok = 0;
        int chain;
        int len = 1800;
        memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
  
        memset(&txctl, 0, sizeof(txctl));
 -      qnum = sc->tx.hwq_map[WME_AC_BE];
 -      txctl.txq = &sc->tx.txq[qnum];
 +      txctl.txq = sc->tx.txq_map[WME_AC_BE];
  
        ath9k_ps_wakeup(sc);
        ar9003_paprd_init_table(ah);
                }
  
                init_completion(&sc->paprd_complete);
 +              sc->paprd_pending = true;
                ar9003_paprd_setup_gain_table(ah, chain);
                txctl.paprd = BIT(chain);
                if (ath_tx_start(hw, skb, &txctl) != 0)
  
                time_left = wait_for_completion_timeout(&sc->paprd_complete,
                                msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
 +              sc->paprd_pending = false;
                if (!time_left) {
 -                      ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
 -                                "Timeout waiting for paprd training on "
 -                                "TX chain %d\n",
 -                                chain);
 +                      ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
 +                              "Timeout waiting for paprd training on TX chain %d\n",
 +                              chain);
                        goto fail_paprd;
                }
  
@@@ -448,7 -457,7 +449,7 @@@ void ath_ani_calibrate(unsigned long da
        /* Long calibration runs independently of short calibration. */
        if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
                longcal = true;
 -              ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
 +              ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
                common->ani.longcal_timer = timestamp;
        }
  
        if (!common->ani.caldone) {
                if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
                        shortcal = true;
 -                      ath_print(common, ATH_DBG_ANI,
 -                                "shortcal @%lu\n", jiffies);
 +                      ath_dbg(common, ATH_DBG_ANI,
 +                              "shortcal @%lu\n", jiffies);
                        common->ani.shortcal_timer = timestamp;
                        common->ani.resetcal_timer = timestamp;
                }
@@@ -541,26 -550,24 +542,26 @@@ void ath_update_chainmask(struct ath_so
                common->rx_chainmask = 1;
        }
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "tx chmask: %d, rx chmask: %d\n",
 -                common->tx_chainmask,
 -                common->rx_chainmask);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "tx chmask: %d, rx chmask: %d\n",
 +              common->tx_chainmask,
 +              common->rx_chainmask);
  }
  
  static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
  {
        struct ath_node *an;
 -
 +      struct ath_hw *ah = sc->sc_ah;
        an = (struct ath_node *)sta->drv_priv;
  
 +      if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
 +              sc->sc_flags |= SC_OP_ENABLE_APM;
 +
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
                an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
                                     sta->ht_cap.ampdu_factor);
                an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
 -              an->last_rssi = ATH_RSSI_DUMMY_MARKER;
        }
  }
  
@@@ -608,8 -615,6 +609,8 @@@ void ath9k_tasklet(unsigned long data
                return;
        }
  
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        if (!ath9k_hw_check_alive(ah))
                ieee80211_queue_work(sc->hw, &sc->hw_check_work);
  
                rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
  
        if (status & rxmask) {
 -              spin_lock_bh(&sc->rx.pcu_lock);
 -
                /* Check for high priority Rx first */
                if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
                    (status & ATH9K_INT_RXHP))
                        ath_rx_tasklet(sc, 0, true);
  
                ath_rx_tasklet(sc, 0, false);
 -              spin_unlock_bh(&sc->rx.pcu_lock);
        }
  
        if (status & ATH9K_INT_TX) {
                 * TSF sync does not look correct; remain awake to sync with
                 * the next Beacon.
                 */
 -              ath_print(common, ATH_DBG_PS,
 -                        "TSFOOR - Sync with next Beacon\n");
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "TSFOOR - Sync with next Beacon\n");
                sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
  
                        ath_gen_timer_isr(sc->sc_ah);
  
        /* re-enable hardware interrupt */
 -      ath9k_hw_set_interrupts(ah, ah->imask);
 +      ath9k_hw_enable_interrupts(ah);
 +
 +      spin_unlock_bh(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
  }
  
@@@ -751,7 -757,7 +752,7 @@@ irqreturn_t ath_isr(int irq, void *dev
                 * interrupt; otherwise it will continue to
                 * fire.
                 */
 -              ath9k_hw_set_interrupts(ah, 0);
 +              ath9k_hw_disable_interrupts(ah);
                /*
                 * Let the hal handle the event. We assume
                 * it will clear whatever condition caused
                spin_lock(&common->cc_lock);
                ath9k_hw_proc_mib_event(ah);
                spin_unlock(&common->cc_lock);
 -              ath9k_hw_set_interrupts(ah, ah->imask);
 +              ath9k_hw_enable_interrupts(ah);
        }
  
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                if (status & ATH9K_INT_TIM_TIMER) {
 +                      if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
 +                              goto chip_reset;
                        /* Clear RxAbort bit so that we can
                         * receive frames */
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
@@@ -779,8 -783,8 +780,8 @@@ chip_reset
        ath_debug_stat_interrupt(sc, status);
  
        if (sched) {
 -              /* turn off every interrupt except SWBA */
 -              ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA));
 +              /* turn off every interrupt */
 +              ath9k_hw_disable_interrupts(ah);
                tasklet_schedule(&sc->intr_tq);
        }
  
@@@ -832,18 -836,16 +833,18 @@@ static u32 ath_get_extchanmode(struct a
  }
  
  static void ath9k_bss_assoc_info(struct ath_softc *sc,
 +                               struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
  {
 +      struct ath_wiphy *aphy = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
  
        if (bss_conf->assoc) {
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "Bss Info ASSOC %d, bssid: %pM\n",
 -                         bss_conf->aid, common->curbssid);
 +              ath_dbg(common, ATH_DBG_CONFIG,
 +                      "Bss Info ASSOC %d, bssid: %pM\n",
 +                      bss_conf->aid, common->curbssid);
  
                /* New association, store aid */
                common->curaid = bss_conf->aid;
                ath_beacon_config(sc, vif);
  
                /* Reset rssi stats */
 +              aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
  
                sc->sc_flags |= SC_OP_ANI_RUN;
                ath_start_ani(common);
        } else {
 -              ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
 +              ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
                common->curaid = 0;
                /* Stop ANI */
                sc->sc_flags &= ~SC_OP_ANI_RUN;
@@@ -882,26 -883,31 +883,26 @@@ void ath_radio_enable(struct ath_softc 
        int r;
  
        ath9k_ps_wakeup(sc);
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        ath9k_hw_configpcipowersave(ah, 0, 0);
  
        if (!ah->curchan)
                ah->curchan = ath_get_curchannel(sc, sc->hw);
  
 -      spin_lock_bh(&sc->rx.pcu_lock);
 -      spin_lock_bh(&sc->sc_resetlock);
        r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (r) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset channel (%u MHz), "
 -                        "reset status %d\n",
 -                        channel->center_freq, r);
 +              ath_err(common,
 +                      "Unable to reset channel (%u MHz), reset status %d\n",
 +                      channel->center_freq, r);
        }
 -      spin_unlock_bh(&sc->sc_resetlock);
  
        ath_update_txpow(sc);
        if (ath_startrecv(sc) != 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to restart recv logic\n");
 -              spin_unlock_bh(&sc->rx.pcu_lock);
 +              ath_err(common, "Unable to restart recv logic\n");
 +              spin_unlock_bh(&sc->sc_pcu_lock);
                return;
        }
 -      spin_unlock_bh(&sc->rx.pcu_lock);
 -
        if (sc->sc_flags & SC_OP_BEACONS)
                ath_beacon_config(sc, NULL);    /* restart beacons */
  
        ath9k_hw_set_gpio(ah, ah->led_pin, 0);
  
        ieee80211_wake_queues(hw);
 +      spin_unlock_bh(&sc->sc_pcu_lock);
 +
        ath9k_ps_restore(sc);
  }
  
@@@ -926,8 -930,6 +927,8 @@@ void ath_radio_disable(struct ath_soft
        int r;
  
        ath9k_ps_wakeup(sc);
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        ieee80211_stop_queues(hw);
  
        /*
        }
  
        /* Disable interrupts */
 -      ath9k_hw_set_interrupts(ah, 0);
 +      ath9k_hw_disable_interrupts(ah);
  
        ath_drain_all_txq(sc, false);   /* clear pending tx frames */
  
 -      spin_lock_bh(&sc->rx.pcu_lock);
 -
        ath_stoprecv(sc);               /* turn off frame recv */
        ath_flushrecv(sc);              /* flush recv queue */
  
        if (!ah->curchan)
                ah->curchan = ath_get_curchannel(sc, hw);
  
 -      spin_lock_bh(&sc->sc_resetlock);
        r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        if (r) {
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 -                        "Unable to reset channel (%u MHz), "
 -                        "reset status %d\n",
 -                        channel->center_freq, r);
 +              ath_err(ath9k_hw_common(sc->sc_ah),
 +                      "Unable to reset channel (%u MHz), reset status %d\n",
 +                      channel->center_freq, r);
        }
 -      spin_unlock_bh(&sc->sc_resetlock);
  
        ath9k_hw_phy_disable(ah);
  
 -      spin_unlock_bh(&sc->rx.pcu_lock);
 -
        ath9k_hw_configpcipowersave(ah, 1, 1);
 +
 +      spin_unlock_bh(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
 +
        ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
  }
  
@@@ -977,23 -983,28 +978,23 @@@ int ath_reset(struct ath_softc *sc, boo
        /* Stop ANI */
        del_timer_sync(&common->ani.timer);
  
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        ieee80211_stop_queues(hw);
  
 -      ath9k_hw_set_interrupts(ah, 0);
 +      ath9k_hw_disable_interrupts(ah);
        ath_drain_all_txq(sc, retry_tx);
  
 -      spin_lock_bh(&sc->rx.pcu_lock);
 -
        ath_stoprecv(sc);
        ath_flushrecv(sc);
  
 -      spin_lock_bh(&sc->sc_resetlock);
        r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
        if (r)
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset hardware; reset status %d\n", r);
 -      spin_unlock_bh(&sc->sc_resetlock);
 +              ath_err(common,
 +                      "Unable to reset hardware; reset status %d\n", r);
  
        if (ath_startrecv(sc) != 0)
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to start recv logic\n");
 -
 -      spin_unlock_bh(&sc->rx.pcu_lock);
 +              ath_err(common, "Unable to start recv logic\n");
  
        /*
         * We may be doing a reset in response to a request
        }
  
        ieee80211_wake_queues(hw);
 +      spin_unlock_bh(&sc->sc_pcu_lock);
  
        /* Start ANI */
        ath_start_ani(common);
        return r;
  }
  
 -static int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
 -{
 -      int qnum;
 -
 -      switch (queue) {
 -      case 0:
 -              qnum = sc->tx.hwq_map[WME_AC_VO];
 -              break;
 -      case 1:
 -              qnum = sc->tx.hwq_map[WME_AC_VI];
 -              break;
 -      case 2:
 -              qnum = sc->tx.hwq_map[WME_AC_BE];
 -              break;
 -      case 3:
 -              qnum = sc->tx.hwq_map[WME_AC_BK];
 -              break;
 -      default:
 -              qnum = sc->tx.hwq_map[WME_AC_BE];
 -              break;
 -      }
 -
 -      return qnum;
 -}
 -
 -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
 -{
 -      int qnum;
 -
 -      switch (queue) {
 -      case WME_AC_VO:
 -              qnum = 0;
 -              break;
 -      case WME_AC_VI:
 -              qnum = 1;
 -              break;
 -      case WME_AC_BE:
 -              qnum = 2;
 -              break;
 -      case WME_AC_BK:
 -              qnum = 3;
 -              break;
 -      default:
 -              qnum = -1;
 -              break;
 -      }
 -
 -      return qnum;
 -}
 -
  /* XXX: Remove me once we don't depend on ath9k_channel for all
   * this redundant data */
  void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
@@@ -1065,9 -1125,9 +1066,9 @@@ static int ath9k_start(struct ieee80211
        struct ath9k_channel *init_channel;
        int r;
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Starting driver with initial channel: %d MHz\n",
 -                curchan->center_freq);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Starting driver with initial channel: %d MHz\n",
 +              curchan->center_freq);
  
        mutex_lock(&sc->mutex);
  
         * be followed by initialization of the appropriate bits
         * and then setup of the interrupt mask.
         */
 -      spin_lock_bh(&sc->rx.pcu_lock);
 -      spin_lock_bh(&sc->sc_resetlock);
 +      spin_lock_bh(&sc->sc_pcu_lock);
        r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (r) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to reset hardware; reset status %d "
 -                        "(freq %u MHz)\n", r,
 -                        curchan->center_freq);
 -              spin_unlock_bh(&sc->sc_resetlock);
 -              spin_unlock_bh(&sc->rx.pcu_lock);
 +              ath_err(common,
 +                      "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 +                      r, curchan->center_freq);
 +              spin_unlock_bh(&sc->sc_pcu_lock);
                goto mutex_unlock;
        }
 -      spin_unlock_bh(&sc->sc_resetlock);
  
        /*
         * This is needed only to setup initial state
         * here except setup the interrupt mask.
         */
        if (ath_startrecv(sc) != 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Unable to start recv logic\n");
 +              ath_err(common, "Unable to start recv logic\n");
                r = -EIO;
 -              spin_unlock_bh(&sc->rx.pcu_lock);
 +              spin_unlock_bh(&sc->sc_pcu_lock);
                goto mutex_unlock;
        }
 -      spin_unlock_bh(&sc->rx.pcu_lock);
 +      spin_unlock_bh(&sc->sc_pcu_lock);
  
        /* Setup our intr mask. */
        ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
  
        pm_qos_update_request(&sc->pm_qos_req, 55);
  
 +      if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
 +              common->bus_ops->extn_synch_en(common);
 +
  mutex_unlock:
        mutex_unlock(&sc->mutex);
  
  static int ath9k_tx(struct ieee80211_hw *hw,
                    struct sk_buff *skb)
  {
 -      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_tx_control txctl;
 -      int padpos, padsize;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 -      int qnum;
  
        if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
 -              ath_print(common, ATH_DBG_XMIT,
 -                        "ath9k: %s: TX in unexpected wiphy state "
 -                        "%d\n", wiphy_name(hw->wiphy), aphy->state);
 +              ath_dbg(common, ATH_DBG_XMIT,
 +                      "ath9k: %s: TX in unexpected wiphy state %d\n",
 +                      wiphy_name(hw->wiphy), aphy->state);
                goto exit;
        }
  
                if (ieee80211_is_data(hdr->frame_control) &&
                    !ieee80211_is_nullfunc(hdr->frame_control) &&
                    !ieee80211_has_pm(hdr->frame_control)) {
 -                      ath_print(common, ATH_DBG_PS, "Add PM=1 for a TX frame "
 -                                "while in PS mode\n");
 +                      ath_dbg(common, ATH_DBG_PS,
 +                              "Add PM=1 for a TX frame while in PS mode\n");
                        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
                }
        }
                if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                if (ieee80211_is_pspoll(hdr->frame_control)) {
 -                      ath_print(common, ATH_DBG_PS,
 -                                "Sending PS-Poll to pick a buffered frame\n");
 +                      ath_dbg(common, ATH_DBG_PS,
 +                              "Sending PS-Poll to pick a buffered frame\n");
                        sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
                } else {
 -                      ath_print(common, ATH_DBG_PS,
 -                                "Wake up to complete TX\n");
 +                      ath_dbg(common, ATH_DBG_PS,
 +                              "Wake up to complete TX\n");
                        sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
                }
                /*
        }
  
        memset(&txctl, 0, sizeof(struct ath_tx_control));
 +      txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
  
 -      /*
 -       * As a temporary workaround, assign seq# here; this will likely need
 -       * to be cleaned up to work better with Beacon transmission and virtual
 -       * BSSes.
 -       */
 -      if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 -              if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 -                      sc->tx.seq_no += 0x10;
 -              hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
 -              hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
 -      }
 -
 -      /* Add the padding after the header if this is not already done */
 -      padpos = ath9k_cmn_padpos(hdr->frame_control);
 -      padsize = padpos & 3;
 -      if (padsize && skb->len>padpos) {
 -              if (skb_headroom(skb) < padsize)
 -                      return -1;
 -              skb_push(skb, padsize);
 -              memmove(skb->data, skb->data + padsize, padpos);
 -      }
 -
 -      qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
 -      txctl.txq = &sc->tx.txq[qnum];
 -
 -      ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
 +      ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
  
        if (ath_tx_start(hw, skb, &txctl) != 0) {
 -              ath_print(common, ATH_DBG_XMIT, "TX failed\n");
 +              ath_dbg(common, ATH_DBG_XMIT, "TX failed\n");
                goto exit;
        }
  
@@@ -1292,7 -1381,7 +1293,7 @@@ static void ath9k_stop(struct ieee80211
        }
  
        if (sc->sc_flags & SC_OP_INVALID) {
 -              ath_print(common, ATH_DBG_ANY, "Device not present\n");
 +              ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
        }
                        ath9k_btcoex_timer_pause(sc);
        }
  
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
        /* make sure h/w will not generate any interrupt
         * before setting the invalid flag. */
 -      ath9k_hw_set_interrupts(ah, 0);
 +      ath9k_hw_disable_interrupts(ah);
  
 -      spin_lock_bh(&sc->rx.pcu_lock);
        if (!(sc->sc_flags & SC_OP_INVALID)) {
                ath_drain_all_txq(sc, false);
                ath_stoprecv(sc);
                ath9k_hw_phy_disable(ah);
        } else
                sc->rx.rxlink = NULL;
 -      spin_unlock_bh(&sc->rx.pcu_lock);
  
        /* disable HAL and put h/w to sleep */
        ath9k_hw_disable(ah);
        ath9k_hw_configpcipowersave(ah, 1, 1);
 +
 +      spin_unlock_bh(&sc->sc_pcu_lock);
 +
        ath9k_ps_restore(sc);
  
        /* Finally, put the chip in FULL SLEEP mode */
  
        mutex_unlock(&sc->mutex);
  
 -      ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
  }
  
  static int ath9k_add_interface(struct ieee80211_hw *hw,
                ic_opmode = vif->type;
                break;
        default:
 -              ath_print(common, ATH_DBG_FATAL,
 -                      "Interface type %d not yet supported\n", vif->type);
 +              ath_err(common, "Interface type %d not yet supported\n",
 +                      vif->type);
                ret = -EOPNOTSUPP;
                goto out;
        }
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Attach a VIF of type: %d\n", ic_opmode);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Attach a VIF of type: %d\n", ic_opmode);
  
        /* Set the VIF opmode */
        avp->av_opmode = ic_opmode;
@@@ -1434,10 -1520,8 +1435,8 @@@ static void ath9k_remove_interface(stru
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
-       bool bs_valid = false;
-       int i;
  
 -      ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
  
        mutex_lock(&sc->mutex);
  
        if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
            (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
            (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) {
+               /* Disable SWBA interrupt */
+               sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
                ath9k_ps_wakeup(sc);
+               ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
                ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
                ath9k_ps_restore(sc);
+               tasklet_kill(&sc->bcon_tasklet);
        }
  
        ath_beacon_return(sc, avp);
        sc->sc_flags &= ~SC_OP_BEACONS;
  
-       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
-               if (sc->beacon.bslot[i] == vif) {
-                       printk(KERN_DEBUG "%s: vif had allocated beacon "
-                              "slot\n", __func__);
-                       sc->beacon.bslot[i] = NULL;
-                       sc->beacon.bslot_aphy[i] = NULL;
-               } else if (sc->beacon.bslot[i])
-                       bs_valid = true;
-       }
-       if (!bs_valid && (sc->sc_ah->imask & ATH9K_INT_SWBA)) {
-               /* Disable SWBA interrupt */
-               sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
+       if (sc->nbcnvifs) {
+               /* Re-enable SWBA interrupt */
+               sc->sc_ah->imask |= ATH9K_INT_SWBA;
                ath9k_ps_wakeup(sc);
                ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
                ath9k_ps_restore(sc);
@@@ -1552,8 -1631,8 +1546,8 @@@ static int ath9k_config(struct ieee8021
                if (enable_radio) {
                        sc->ps_idle = false;
                        ath_radio_enable(sc, hw);
 -                      ath_print(common, ATH_DBG_CONFIG,
 -                                "not-idle: enabling radio\n");
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "not-idle: enabling radio\n");
                }
        }
  
  
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
 -                      ath_print(common, ATH_DBG_CONFIG,
 -                                "Monitor mode is enabled\n");
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "Monitor mode is enabled\n");
                        sc->sc_ah->is_monitoring = true;
                } else {
 -                      ath_print(common, ATH_DBG_CONFIG,
 -                                "Monitor mode is disabled\n");
 +                      ath_dbg(common, ATH_DBG_CONFIG,
 +                              "Monitor mode is disabled\n");
                        sc->sc_ah->is_monitoring = false;
                }
        }
                        goto skip_chan_change;
                }
  
 -              ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 -                        curchan->center_freq);
 +              ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
 +                      curchan->center_freq);
  
                /* XXX: remove me eventualy */
                ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
                }
  
                if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "Unable to set channel\n");
 +                      ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
                        return -EINVAL;
                }
@@@ -1671,7 -1751,7 +1665,7 @@@ skip_chan_change
        spin_unlock_bh(&sc->wiphy_lock);
  
        if (disable_radio) {
 -              ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
 +              ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
                sc->ps_idle = true;
                ath_radio_disable(sc, hw);
        }
@@@ -1710,8 -1790,8 +1704,8 @@@ static void ath9k_configure_filter(stru
        ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
        ath9k_ps_restore(sc);
  
 -      ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
 -                "Set HW RX filter: 0x%x\n", rfilt);
 +      ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
 +              "Set HW RX filter: 0x%x\n", rfilt);
  }
  
  static int ath9k_sta_add(struct ieee80211_hw *hw,
@@@ -1744,15 -1824,12 +1738,15 @@@ static int ath9k_conf_tx(struct ieee802
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ath_txq *txq;
        struct ath9k_tx_queue_info qi;
 -      int ret = 0, qnum;
 +      int ret = 0;
  
        if (queue >= WME_NUM_AC)
                return 0;
  
 +      txq = sc->tx.txq_map[queue];
 +
        mutex_lock(&sc->mutex);
  
        memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
        qi.tqi_cwmin = params->cw_min;
        qi.tqi_cwmax = params->cw_max;
        qi.tqi_burstTime = params->txop;
 -      qnum = ath_get_hal_qnum(queue, sc);
  
 -      ath_print(common, ATH_DBG_CONFIG,
 -                "Configure tx [queue/halq] [%d/%d],  "
 -                "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 -                queue, qnum, params->aifs, params->cw_min,
 -                params->cw_max, params->txop);
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
 +              queue, txq->axq_qnum, params->aifs, params->cw_min,
 +              params->cw_max, params->txop);
  
 -      ret = ath_txq_update(sc, qnum, &qi);
 +      ret = ath_txq_update(sc, txq->axq_qnum, &qi);
        if (ret)
 -              ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
 +              ath_err(common, "TXQ Update failed\n");
  
        if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
 -              if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret)
 +              if (queue == WME_AC_BE && !ret)
                        ath_beaconq_config(sc);
  
        mutex_unlock(&sc->mutex);
@@@ -1796,7 -1875,7 +1790,7 @@@ static int ath9k_set_key(struct ieee802
  
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
 -      ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
 +      ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
  
        switch (cmd) {
        case SET_KEY:
@@@ -1855,8 -1934,9 +1849,8 @@@ static void ath9k_bss_info_changed(stru
                if (vif->type == NL80211_IFTYPE_ADHOC)
                        ath_update_chainmask(sc, 0);
  
 -              ath_print(common, ATH_DBG_CONFIG,
 -                        "BSSID: %pM aid: 0x%x\n",
 -                        common->curbssid, common->curaid);
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
 +                      common->curbssid, common->curaid);
  
                /* need to reconfigure the beacon */
                sc->sc_flags &= ~SC_OP_BEACONS ;
        }
  
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 -                        bss_conf->use_short_preamble);
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 +                      bss_conf->use_short_preamble);
                if (bss_conf->use_short_preamble)
                        sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
                else
        }
  
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 -                        bss_conf->use_cts_prot);
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 +                      bss_conf->use_cts_prot);
                if (bss_conf->use_cts_prot &&
                    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
                        sc->sc_flags |= SC_OP_PROTECT_ENABLE;
        }
  
        if (changed & BSS_CHANGED_ASSOC) {
 -              ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 +              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
                        bss_conf->assoc);
 -              ath9k_bss_assoc_info(sc, vif, bss_conf);
 +              ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
        }
  
        mutex_unlock(&sc->mutex);
@@@ -1996,9 -2076,6 +1990,9 @@@ static int ath9k_ampdu_action(struct ie
        case IEEE80211_AMPDU_RX_STOP:
                break;
        case IEEE80211_AMPDU_TX_START:
 +              if (!(sc->sc_flags & SC_OP_TXAGGR))
 +                      return -EOPNOTSUPP;
 +
                ath9k_ps_wakeup(sc);
                ret = ath_tx_aggr_start(sc, sta, tid, ssn);
                if (!ret)
                ath9k_ps_restore(sc);
                break;
        default:
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 -                        "Unknown AMPDU action\n");
 +              ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
        }
  
        local_bh_enable();
index c3129db7828f4173f0e1d51120fc3cd953a9937f,fdc2ec52b42fcd5647df2c967598e94bcfc13c9a..00ebed3f9158af4db1c62c98c50a4bcb0920e4e2
@@@ -165,7 -165,7 +165,7 @@@ static void ath_rx_addbuffer_edma(struc
        u32 nbuf = 0;
  
        if (list_empty(&sc->rx.rxbuf)) {
 -              ath_print(common, ATH_DBG_QUEUE, "No free rx buf available\n");
 +              ath_dbg(common, ATH_DBG_QUEUE, "No free rx buf available\n");
                return;
        }
  
@@@ -269,7 -269,7 +269,7 @@@ static int ath_rx_edma_init(struct ath_
                                dev_kfree_skb_any(skb);
                                bf->bf_mpdu = NULL;
                                bf->bf_buf_addr = 0;
 -                              ath_print(common, ATH_DBG_FATAL,
 +                              ath_err(common,
                                        "dma_mapping_error() on RX init\n");
                                error = -ENOMEM;
                                goto rx_init_fail;
@@@ -317,7 -317,7 +317,7 @@@ int ath_rx_init(struct ath_softc *sc, i
        struct ath_buf *bf;
        int error = 0;
  
 -      spin_lock_init(&sc->rx.pcu_lock);
 +      spin_lock_init(&sc->sc_pcu_lock);
        sc->sc_flags &= ~SC_OP_RXFLUSH;
        spin_lock_init(&sc->rx.rxbuflock);
  
                common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
                                min(common->cachelsz, (u16)64));
  
 -              ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
 -                              common->cachelsz, common->rx_bufsize);
 +              ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
 +                      common->cachelsz, common->rx_bufsize);
  
                /* Initialize rx descriptors */
  
                error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
                                "rx", nbufs, 1, 0);
                if (error != 0) {
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "failed to allocate rx descriptors: %d\n",
 -                                error);
 +                      ath_err(common,
 +                              "failed to allocate rx descriptors: %d\n",
 +                              error);
                        goto err;
                }
  
                                dev_kfree_skb_any(skb);
                                bf->bf_mpdu = NULL;
                                bf->bf_buf_addr = 0;
 -                              ath_print(common, ATH_DBG_FATAL,
 -                                        "dma_mapping_error() on RX init\n");
 +                              ath_err(common,
 +                                      "dma_mapping_error() on RX init\n");
                                error = -ENOMEM;
                                goto err;
                        }
@@@ -528,12 -528,6 +528,12 @@@ bool ath_stoprecv(struct ath_softc *sc
                sc->rx.rxlink = NULL;
        spin_unlock_bh(&sc->rx.rxbuflock);
  
 +      if (unlikely(!stopped)) {
 +              ath_err(ath9k_hw_common(sc->sc_ah),
 +                      "Could not stop RX, we could be "
 +                      "confusing the DMA engine when we start RX up\n");
 +              ATH_DBG_WARN_ON_ONCE(!stopped);
 +      }
        return stopped;
  }
  
@@@ -594,8 -588,9 +594,8 @@@ static void ath_rx_ps_beacon(struct ath
  
        if (sc->ps_flags & PS_BEACON_SYNC) {
                sc->ps_flags &= ~PS_BEACON_SYNC;
 -              ath_print(common, ATH_DBG_PS,
 -                        "Reconfigure Beacon timers based on "
 -                        "timestamp from the AP\n");
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "Reconfigure Beacon timers based on timestamp from the AP\n");
                ath_beacon_config(sc, NULL);
        }
  
                 * a backup trigger for returning into NETWORK SLEEP state,
                 * so we are waiting for it as well.
                 */
 -              ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
 -                        "buffered broadcast/multicast frame(s)\n");
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "Received DTIM beacon indicating buffered broadcast/multicast frame(s)\n");
                sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON;
                return;
        }
                 * been delivered.
                 */
                sc->ps_flags &= ~PS_WAIT_FOR_CAB;
 -              ath_print(common, ATH_DBG_PS,
 -                        "PS wait for CAB frames timed out\n");
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "PS wait for CAB frames timed out\n");
        }
  }
  
@@@ -646,14 -641,15 +646,14 @@@ static void ath_rx_ps(struct ath_softc 
                 * point.
                 */
                sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON);
 -              ath_print(common, ATH_DBG_PS,
 -                        "All PS CAB frames received, back to sleep\n");
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "All PS CAB frames received, back to sleep\n");
        } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
                   !is_multicast_ether_addr(hdr->addr1) &&
                   !ieee80211_has_morefrags(hdr->frame_control)) {
                sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
 -              ath_print(common, ATH_DBG_PS,
 -                        "Going back to sleep after having received "
 -                        "PS-Poll data (0x%lx)\n",
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "Going back to sleep after having received PS-Poll data (0x%lx)\n",
                        sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                        PS_WAIT_FOR_CAB |
                                        PS_WAIT_FOR_PSPOLL_DATA |
  }
  
  static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
 -                                  struct ath_softc *sc, struct sk_buff *skb,
 -                                  struct ieee80211_rx_status *rxs)
 +                                  struct ath_softc *sc, struct sk_buff *skb)
  {
        struct ieee80211_hdr *hdr;
  
@@@ -841,6 -838,10 +841,10 @@@ static bool ath9k_rx_accept(struct ath_
                            struct ath_rx_status *rx_stats,
                            bool *decrypt_error)
  {
+ #define is_mc_or_valid_tkip_keyix ((is_mc ||                  \
+               (rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && \
+               test_bit(rx_stats->rs_keyix, common->tkip_keymap))))
        struct ath_hw *ah = common->ah;
        __le16 fc;
        u8 rx_status_len = ah->caps.rx_status_len;
                if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
                        *decrypt_error = true;
                } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+                       bool is_mc;
                        /*
                         * The MIC error bit is only valid if the frame
                         * is not a control frame or fragment, and it was
                         * decrypted using a valid TKIP key.
                         */
+                       is_mc = !!is_multicast_ether_addr(hdr->addr1);
                        if (!ieee80211_is_ctl(fc) &&
                            !ieee80211_has_morefrags(fc) &&
                            !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
-                           test_bit(rx_stats->rs_keyix, common->tkip_keymap))
+                           is_mc_or_valid_tkip_keyix)
                                rxs->flag |= RX_FLAG_MMIC_ERROR;
                        else
                                rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
@@@ -954,9 -958,8 +961,9 @@@ static int ath9k_process_rate(struct at
         * No valid hardware bitrate found -- we should not get here
         * because hardware has already validated this frame as OK.
         */
 -      ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
 -                "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
 +      ath_dbg(common, ATH_DBG_XMIT,
 +              "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
 +              rx_stats->rs_rate);
  
        return -EINVAL;
  }
@@@ -966,23 -969,36 +973,23 @@@ static void ath9k_process_rssi(struct a
                               struct ieee80211_hdr *hdr,
                               struct ath_rx_status *rx_stats)
  {
 +      struct ath_wiphy *aphy = hw->priv;
        struct ath_hw *ah = common->ah;
 -      struct ieee80211_sta *sta;
 -      struct ath_node *an;
 -      int last_rssi = ATH_RSSI_DUMMY_MARKER;
 +      int last_rssi;
        __le16 fc;
  
 +      if (ah->opmode != NL80211_IFTYPE_STATION)
 +              return;
 +
        fc = hdr->frame_control;
 +      if (!ieee80211_is_beacon(fc) ||
 +          compare_ether_addr(hdr->addr3, common->curbssid))
 +              return;
  
 -      rcu_read_lock();
 -      /*
 -       * XXX: use ieee80211_find_sta! This requires quite a bit of work
 -       * under the current ath9k virtual wiphy implementation as we have
 -       * no way of tying a vif to wiphy. Typically vifs are attached to
 -       * at least one sdata of a wiphy on mac80211 but with ath9k virtual
 -       * wiphy you'd have to iterate over every wiphy and each sdata.
 -       */
 -      if (is_multicast_ether_addr(hdr->addr1))
 -              sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
 -      else
 -              sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, hdr->addr1);
 -
 -      if (sta) {
 -              an = (struct ath_node *) sta->drv_priv;
 -              if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
 -                 !rx_stats->rs_moreaggr)
 -                      ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
 -              last_rssi = an->last_rssi;
 -      }
 -      rcu_read_unlock();
 +      if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
 +              ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi);
  
 +      last_rssi = aphy->last_rssi;
        if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
                rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
                                              ATH_RSSI_EP_MULTIPLIER);
                rx_stats->rs_rssi = 0;
  
        /* Update Beacon RSSI, this is used by ANI. */
 -      if (ieee80211_is_beacon(fc))
 -              ah->stats.avgbrssi = rx_stats->rs_rssi;
 +      ah->stats.avgbrssi = rx_stats->rs_rssi;
  }
  
  /*
@@@ -1620,7 -1637,7 +1627,7 @@@ int ath_rx_tasklet(struct ath_softc *sc
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        /*
 -       * The hw can techncically differ from common->hw when using ath9k
 +       * The hw can technically differ from common->hw when using ath9k
         * virtual wiphy so to account for that we iterate over the active
         * wiphys and find the appropriate wiphy and therefore hw.
         */
                        dev_kfree_skb_any(requeue_skb);
                        bf->bf_mpdu = NULL;
                        bf->bf_buf_addr = 0;
 -                      ath_print(common, ATH_DBG_FATAL,
 -                                "dma_mapping_error() on RX\n");
 -                      ath_rx_send_to_mac80211(hw, sc, skb, rxs);
 +                      ath_err(common, "dma_mapping_error() on RX\n");
 +                      ath_rx_send_to_mac80211(hw, sc, skb);
                        break;
                }
  
                }
  
                spin_lock_irqsave(&sc->sc_pm_lock, flags);
 -              if (unlikely(ath9k_check_auto_sleep(sc) ||
 -                           (sc->ps_flags & (PS_WAIT_FOR_BEACON |
 +
 +              if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                              PS_WAIT_FOR_CAB |
 -                                            PS_WAIT_FOR_PSPOLL_DATA))))
 +                                            PS_WAIT_FOR_PSPOLL_DATA)) ||
 +                                      unlikely(ath9k_check_auto_sleep(sc)))
                        ath_rx_ps(sc, skb);
                spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
  
                if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
                        ath_ant_comb_scan(sc, &rs);
  
 -              ath_rx_send_to_mac80211(hw, sc, skb, rxs);
 +              ath_rx_send_to_mac80211(hw, sc, skb);
  
  requeue:
                if (edma) {
index bce313e85cff158161d66e0ae56c58864db307bc,aff04789f794ee805bf50f1f13d28783f79851d3..43c0109f202c8962e874387fe36ed2c3d3969dab
@@@ -48,17 -48,19 +48,17 @@@ static u16 bits_per_symbol[][2] = 
  
  #define IS_HT_RATE(_rate)     ((_rate) & 0x80)
  
 -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
 -                                struct ath_atx_tid *tid,
 -                                struct list_head *bf_head);
 +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 +                             struct ath_atx_tid *tid,
 +                             struct list_head *bf_head);
  static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
                                struct ath_txq *txq, struct list_head *bf_q,
                                struct ath_tx_status *ts, int txok, int sendbar);
  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                             struct list_head *head);
 -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
 -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
 -                            struct ath_tx_status *ts, int txok);
 +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
  static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
 -                           int nbad, int txok, bool update_rc);
 +                           int nframes, int nbad, int txok, bool update_rc);
  static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
                              int seqno);
  
@@@ -122,7 -124,7 +122,7 @@@ static void ath_tx_queue_tid(struct ath
  
  static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
  {
 -      struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 +      struct ath_txq *txq = tid->ac->txq;
  
        WARN_ON(!tid->paused);
  
@@@ -138,21 -140,12 +138,21 @@@ unlock
        spin_unlock_bh(&txq->axq_lock);
  }
  
 +static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
 +{
 +      struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 +      BUILD_BUG_ON(sizeof(struct ath_frame_info) >
 +                   sizeof(tx_info->rate_driver_data));
 +      return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
 +}
 +
  static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
  {
 -      struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 +      struct ath_txq *txq = tid->ac->txq;
        struct ath_buf *bf;
        struct list_head bf_head;
        struct ath_tx_status ts;
 +      struct ath_frame_info *fi;
  
        INIT_LIST_HEAD(&bf_head);
  
                bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
                list_move_tail(&bf->list, &bf_head);
  
 -              if (bf_isretried(bf)) {
 -                      ath_tx_update_baw(sc, tid, bf->bf_seqno);
 +              spin_unlock_bh(&txq->axq_lock);
 +              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);
                } else {
 -                      ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
 +                      ath_tx_send_normal(sc, txq, tid, &bf_head);
                }
 +              spin_lock_bh(&txq->axq_lock);
        }
  
        spin_unlock_bh(&txq->axq_lock);
@@@ -194,11 -184,14 +194,11 @@@ static void ath_tx_update_baw(struct at
  }
  
  static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
 -                           struct ath_buf *bf)
 +                           u16 seqno)
  {
        int index, cindex;
  
 -      if (bf_isretried(bf))
 -              return;
 -
 -      index  = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
 +      index  = ATH_BA_INDEX(tid->seq_start, seqno);
        cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
        __set_bit(cindex, tid->tx_buf);
  
@@@ -222,7 -215,6 +222,7 @@@ static void ath_tid_drain(struct ath_so
        struct ath_buf *bf;
        struct list_head bf_head;
        struct ath_tx_status ts;
 +      struct ath_frame_info *fi;
  
        memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
                bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
                list_move_tail(&bf->list, &bf_head);
  
 -              if (bf_isretried(bf))
 -                      ath_tx_update_baw(sc, tid, bf->bf_seqno);
 +              fi = get_frame_info(bf->bf_mpdu);
 +              if (fi->retries)
 +                      ath_tx_update_baw(sc, tid, fi->seqno);
  
                spin_unlock(&txq->axq_lock);
                ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
  }
  
  static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
 -                           struct ath_buf *bf)
 +                           struct sk_buff *skb)
  {
 -      struct sk_buff *skb;
 +      struct ath_frame_info *fi = get_frame_info(skb);
        struct ieee80211_hdr *hdr;
  
 -      bf->bf_state.bf_type |= BUF_RETRY;
 -      bf->bf_retries++;
        TX_STAT_INC(txq->axq_qnum, a_retries);
 +      if (fi->retries++ > 0)
 +              return;
  
 -      skb = bf->bf_mpdu;
        hdr = (struct ieee80211_hdr *)skb->data;
        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
  }
@@@ -306,41 -298,9 +306,41 @@@ static struct ath_buf* ath_clone_txbuf(
        return tbf;
  }
  
 +static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
 +                              struct ath_tx_status *ts, int txok,
 +                              int *nframes, int *nbad)
 +{
 +      struct ath_frame_info *fi;
 +      u16 seq_st = 0;
 +      u32 ba[WME_BA_BMP_SIZE >> 5];
 +      int ba_index;
 +      int isaggr = 0;
 +
 +      *nbad = 0;
 +      *nframes = 0;
 +
 +      isaggr = bf_isaggr(bf);
 +      if (isaggr) {
 +              seq_st = ts->ts_seqnum;
 +              memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
 +      }
 +
 +      while (bf) {
 +              fi = get_frame_info(bf->bf_mpdu);
 +              ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
 +
 +              (*nframes)++;
 +              if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
 +                      (*nbad)++;
 +
 +              bf = bf->bf_next;
 +      }
 +}
 +
 +
  static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                 struct ath_buf *bf, struct list_head *bf_q,
 -                               struct ath_tx_status *ts, int txok)
 +                               struct ath_tx_status *ts, int txok, bool retry)
  {
        struct ath_node *an = NULL;
        struct sk_buff *skb;
        int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
        bool rc_update = true;
        struct ieee80211_tx_rate rates[4];
 +      struct ath_frame_info *fi;
        int nframes;
 +      u8 tidno;
  
        skb = bf->bf_mpdu;
        hdr = (struct ieee80211_hdr *)skb->data;
        hw = bf->aphy->hw;
  
        memcpy(rates, tx_info->control.rates, sizeof(rates));
 -      nframes = bf->bf_nframes;
  
        rcu_read_lock();
  
                            !bf->bf_stale || bf_next != NULL)
                                list_move_tail(&bf->list, &bf_head);
  
 -                      ath_tx_rc_status(bf, ts, 1, 0, false);
 +                      ath_tx_rc_status(bf, ts, 1, 1, 0, false);
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
                                0, 0);
  
        }
  
        an = (struct ath_node *)sta->drv_priv;
 -      tid = ATH_AN_2_TID(an, bf->bf_tidno);
 +      tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 +      tid = ATH_AN_2_TID(an, tidno);
  
        /*
         * The hardware occasionally sends a tx status for the wrong TID.
         * In this case, the BA status cannot be considered valid and all
         * subframes need to be retransmitted
         */
 -      if (bf->bf_tidno != ts->tid)
 +      if (tidno != ts->tid)
                txok = false;
  
        isaggr = bf_isaggr(bf);
        INIT_LIST_HEAD(&bf_pending);
        INIT_LIST_HEAD(&bf_head);
  
 -      nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
 +      ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
        while (bf) {
                txfail = txpending = 0;
                bf_next = bf->bf_next;
  
                skb = bf->bf_mpdu;
                tx_info = IEEE80211_SKB_CB(skb);
 +              fi = get_frame_info(skb);
  
 -              if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
 +              if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
                        /* transmit completion, subframe is
                         * acked by block ack */
                        acked_cnt++;
                        /* transmit completion */
                        acked_cnt++;
                } else {
 -                      if (!(tid->state & AGGR_CLEANUP) &&
 -                          !bf_last->bf_tx_aborted) {
 -                              if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
 -                                      ath_tx_set_retry(sc, txq, bf);
 +                      if (!(tid->state & AGGR_CLEANUP) && retry) {
 +                              if (fi->retries < ATH_MAX_SW_RETRIES) {
 +                                      ath_tx_set_retry(sc, txq, bf->bf_mpdu);
                                        txpending = 1;
                                } else {
                                        bf->bf_state.bf_type |= BUF_XRETRY;
                         * block-ack window
                         */
                        spin_lock_bh(&txq->axq_lock);
 -                      ath_tx_update_baw(sc, tid, bf->bf_seqno);
 +                      ath_tx_update_baw(sc, tid, fi->seqno);
                        spin_unlock_bh(&txq->axq_lock);
  
                        if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
                                memcpy(tx_info->control.rates, rates, sizeof(rates));
 -                              bf->bf_nframes = nframes;
 -                              ath_tx_rc_status(bf, ts, nbad, txok, true);
 +                              ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
                                rc_update = false;
                        } else {
 -                              ath_tx_rc_status(bf, ts, nbad, txok, false);
 +                              ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
                        }
  
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
                                         */
                                        if (!tbf) {
                                                spin_lock_bh(&txq->axq_lock);
 -                                              ath_tx_update_baw(sc, tid,
 -                                                              bf->bf_seqno);
 +                                              ath_tx_update_baw(sc, tid, fi->seqno);
                                                spin_unlock_bh(&txq->axq_lock);
  
                                                bf->bf_state.bf_type |=
                                                        BUF_XRETRY;
 -                                              ath_tx_rc_status(bf, ts, nbad,
 -                                                              0, false);
 +                                              ath_tx_rc_status(bf, ts, nframes,
 +                                                              nbad, 0, false);
                                                ath_tx_complete_buf(sc, bf, txq,
                                                                    &bf_head,
                                                                    ts, 0, 0);
@@@ -651,7 -611,6 +651,7 @@@ static int ath_compute_num_delims(struc
        u16 minlen;
        u8 flags, rix;
        int width, streams, half_gi, ndelim, mindelim;
 +      struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
  
        /* Select standard number of delimiters based on frame length alone */
        ndelim = ATH_AGGR_GET_NDELIM(frmlen);
         * TODO - this could be improved to be dependent on the rate.
         *      The hardware can keep up at lower rates, but not higher rates
         */
 -      if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
 +      if (fi->keyix != ATH9K_TXKEYIX_INVALID)
                ndelim += ATH_AGGR_ENCRYPTDELIM;
  
        /*
  static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                                             struct ath_txq *txq,
                                             struct ath_atx_tid *tid,
 -                                           struct list_head *bf_q)
 +                                           struct list_head *bf_q,
 +                                           int *aggr_len)
  {
  #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
        struct ath_buf *bf, *bf_first, *bf_prev = NULL;
                al_delta, h_baw = tid->baw_size / 2;
        enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
        struct ieee80211_tx_info *tx_info;
 +      struct ath_frame_info *fi;
  
        bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
  
        do {
                bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
 +              fi = get_frame_info(bf->bf_mpdu);
  
                /* do not step over block-ack window */
 -              if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
 +              if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
                        status = ATH_AGGR_BAW_CLOSED;
                        break;
                }
                }
  
                /* do not exceed aggregation limit */
 -              al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
 +              al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
  
                if (nframes &&
                    (aggr_limit < (al + bpad + al_delta + prev_al))) {
                 * Get the delimiters needed to meet the MPDU
                 * density for this node.
                 */
 -              ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
 +              ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
                bpad = PADBYTES(al_delta) + (ndelim << 2);
  
                bf->bf_next = NULL;
                ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
  
                /* link buffers of this frame to the aggregate */
 -              ath_tx_addto_baw(sc, tid, bf);
 +              if (!fi->retries)
 +                      ath_tx_addto_baw(sc, tid, fi->seqno);
                ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
                list_move_tail(&bf->list, bf_q);
                if (bf_prev) {
  
        } while (!list_empty(&tid->buf_q));
  
 -      bf_first->bf_al = al;
 -      bf_first->bf_nframes = nframes;
 +      *aggr_len = al;
  
        return status;
  #undef PADBYTES
@@@ -794,9 -750,7 +794,9 @@@ static void ath_tx_sched_aggr(struct at
  {
        struct ath_buf *bf;
        enum ATH_AGGR_STATUS status;
 +      struct ath_frame_info *fi;
        struct list_head bf_q;
 +      int aggr_len;
  
        do {
                if (list_empty(&tid->buf_q))
  
                INIT_LIST_HEAD(&bf_q);
  
 -              status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
 +              status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
  
                /*
                 * no frames picked up to be aggregated;
                bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
  
                /* if only one frame, send as non-aggregate */
 -              if (bf->bf_nframes == 1) {
 +              if (bf == bf->bf_lastbf) {
 +                      fi = get_frame_info(bf->bf_mpdu);
 +
                        bf->bf_state.bf_type &= ~BUF_AGGR;
                        ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
 -                      ath_buf_set_rate(sc, bf);
 +                      ath_buf_set_rate(sc, bf, fi->framelen);
                        ath_tx_txqaddbuf(sc, txq, &bf_q);
                        continue;
                }
  
                /* setup first desc of aggregate */
                bf->bf_state.bf_type |= BUF_AGGR;
 -              ath_buf_set_rate(sc, bf);
 -              ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
 +              ath_buf_set_rate(sc, bf, aggr_len);
 +              ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
  
                /* anchor last desc of aggregate */
                ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
@@@ -865,7 -817,7 +865,7 @@@ void ath_tx_aggr_stop(struct ath_softc 
  {
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
 -      struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
 +      struct ath_txq *txq = txtid->ac->txq;
  
        if (txtid->state & AGGR_CLEANUP)
                return;
@@@ -936,16 -888,10 +936,16 @@@ struct ath_txq *ath_txq_setup(struct at
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_tx_queue_info qi;
 +      static const int subtype_txq_to_hwq[] = {
 +              [WME_AC_BE] = ATH_TXQ_AC_BE,
 +              [WME_AC_BK] = ATH_TXQ_AC_BK,
 +              [WME_AC_VI] = ATH_TXQ_AC_VI,
 +              [WME_AC_VO] = ATH_TXQ_AC_VO,
 +      };
        int qnum, i;
  
        memset(&qi, 0, sizeof(qi));
 -      qi.tqi_subtype = subtype;
 +      qi.tqi_subtype = subtype_txq_to_hwq[subtype];
        qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
        qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
        qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
                return NULL;
        }
        if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "qnum %u out of range, max %u!\n",
 -                        qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
 +              ath_err(common, "qnum %u out of range, max %zu!\n",
 +                      qnum, ARRAY_SIZE(sc->tx.txq));
                ath9k_hw_releasetxqueue(ah, qnum);
                return NULL;
        }
        if (!ATH_TXQ_SETUP(sc, qnum)) {
                struct ath_txq *txq = &sc->tx.txq[qnum];
  
 -              txq->axq_class = subtype;
                txq->axq_qnum = qnum;
                txq->axq_link = NULL;
                INIT_LIST_HEAD(&txq->axq_q);
@@@ -1037,8 -985,8 +1037,8 @@@ int ath_txq_update(struct ath_softc *sc
        qi.tqi_readyTime = qinfo->tqi_readyTime;
  
        if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 -                        "Unable to update hardware queue %u!\n", qnum);
 +              ath_err(ath9k_hw_common(sc->sc_ah),
 +                      "Unable to update hardware queue %u!\n", qnum);
                error = -EIO;
        } else {
                ath9k_hw_resettxqueue(ah, qnum);
@@@ -1114,6 -1062,8 +1114,6 @@@ void ath_draintxq(struct ath_softc *sc
                }
  
                lastbf = bf->bf_lastbf;
 -              if (!retry_tx)
 -                      lastbf->bf_tx_aborted = true;
  
                if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
                        list_cut_position(&bf_head,
                spin_unlock_bh(&txq->axq_lock);
  
                if (bf_isampdu(bf))
 -                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
 +                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
 +                                           retry_tx);
                else
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }
  
                        if (bf_isampdu(bf))
                                ath_tx_complete_aggr(sc, txq, bf, &bf_head,
 -                                                   &ts, 0);
 +                                                   &ts, 0, retry_tx);
                        else
                                ath_tx_complete_buf(sc, bf, txq, &bf_head,
                                                    &ts, 0, 0);
        }
  }
  
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
  {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int i, npend = 0;
  
        if (sc->sc_flags & SC_OP_INVALID)
-               return;
+               return true;
  
        /* Stop beacon queue */
        ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
                }
        }
  
-       if (npend) {
-               int r;
-               ath_err(common, "Failed to stop TX DMA. Resetting hardware!\n");
-               r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
-               if (r)
-                       ath_err(common,
-                               "Unable to reset hardware; reset status %d\n",
-                               r);
-       }
+       if (npend)
 -              ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA!\n");
++              ath_err(common, "Failed to stop TX DMA!\n");
  
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
                if (ATH_TXQ_SETUP(sc, i))
                        ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
        }
+       return !npend;
  }
  
  void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
@@@ -1260,6 -1202,24 +1253,6 @@@ void ath_txq_schedule(struct ath_softc 
        }
  }
  
 -int ath_tx_setup(struct ath_softc *sc, int haltype)
 -{
 -      struct ath_txq *txq;
 -
 -      if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 -                        "HAL AC %u out of range, max %zu!\n",
 -                       haltype, ARRAY_SIZE(sc->tx.hwq_map));
 -              return 0;
 -      }
 -      txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
 -      if (txq != NULL) {
 -              sc->tx.hwq_map[haltype] = txq->axq_qnum;
 -              return 1;
 -      } else
 -              return 0;
 -}
 -
  /***********/
  /* TX, DMA */
  /***********/
@@@ -1285,8 -1245,8 +1278,8 @@@ static void ath_tx_txqaddbuf(struct ath
  
        bf = list_first_entry(head, struct ath_buf, list);
  
 -      ath_print(common, ATH_DBG_QUEUE,
 -                "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
 +      ath_dbg(common, ATH_DBG_QUEUE,
 +              "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
  
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
                if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
                        return;
                }
                if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
 -                      ath_print(common, ATH_DBG_XMIT,
 -                                "Initializing tx fifo %d which "
 -                                "is non-empty\n",
 -                                txq->txq_headidx);
 +                      ath_dbg(common, ATH_DBG_XMIT,
 +                              "Initializing tx fifo %d which is non-empty\n",
 +                              txq->txq_headidx);
                INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
                list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
                INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
                ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 -              ath_print(common, ATH_DBG_XMIT,
 -                        "TXDP[%u] = %llx (%p)\n",
 -                        txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
 +              ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
 +                      txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
        } else {
                list_splice_tail_init(head, &txq->axq_q);
  
                if (txq->axq_link == NULL) {
                        ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 -                      ath_print(common, ATH_DBG_XMIT,
 -                                      "TXDP[%u] = %llx (%p)\n",
 -                                      txq->axq_qnum, ito64(bf->bf_daddr),
 -                                      bf->bf_desc);
 +                      ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
 +                              txq->axq_qnum, ito64(bf->bf_daddr),
 +                              bf->bf_desc);
                } else {
                        *txq->axq_link = bf->bf_daddr;
 -                      ath_print(common, ATH_DBG_XMIT,
 -                                      "link[%u] (%p)=%llx (%p)\n",
 -                                      txq->axq_qnum, txq->axq_link,
 -                                      ito64(bf->bf_daddr), bf->bf_desc);
 +                      ath_dbg(common, ATH_DBG_XMIT,
 +                              "link[%u] (%p)=%llx (%p)\n",
 +                              txq->axq_qnum, txq->axq_link,
 +                              ito64(bf->bf_daddr), bf->bf_desc);
                }
                ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
                                       &txq->axq_link);
  }
  
  static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
 -                            struct list_head *bf_head,
 -                            struct ath_tx_control *txctl)
 +                            struct ath_buf *bf, struct ath_tx_control *txctl)
  {
 -      struct ath_buf *bf;
 +      struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
 +      struct list_head bf_head;
  
 -      bf = list_first_entry(bf_head, struct ath_buf, list);
        bf->bf_state.bf_type |= BUF_AMPDU;
        TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
  
         * - h/w queue depth exceeds low water mark
         */
        if (!list_empty(&tid->buf_q) || tid->paused ||
 -          !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
 +          !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
            txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
                /*
                 * Add this frame to software queue for scheduling later
                 * for aggregation.
                 */
 -              list_move_tail(&bf->list, &tid->buf_q);
 +              list_add_tail(&bf->list, &tid->buf_q);
                ath_tx_queue_tid(txctl->txq, tid);
                return;
        }
  
 +      INIT_LIST_HEAD(&bf_head);
 +      list_add(&bf->list, &bf_head);
 +
        /* Add sub-frame to BAW */
 -      ath_tx_addto_baw(sc, tid, bf);
 +      if (!fi->retries)
 +              ath_tx_addto_baw(sc, tid, fi->seqno);
  
        /* Queue to h/w without aggregation */
 -      bf->bf_nframes = 1;
        bf->bf_lastbf = bf;
 -      ath_buf_set_rate(sc, bf);
 -      ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
 +      ath_buf_set_rate(sc, bf, fi->framelen);
 +      ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
  }
  
 -static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
 -                                struct ath_atx_tid *tid,
 -                                struct list_head *bf_head)
 +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 +                             struct ath_atx_tid *tid,
 +                             struct list_head *bf_head)
  {
 +      struct ath_frame_info *fi;
        struct ath_buf *bf;
  
        bf = list_first_entry(bf_head, struct ath_buf, list);
        bf->bf_state.bf_type &= ~BUF_AMPDU;
  
        /* update starting sequence number for subsequent ADDBA request */
 -      INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 -
 -      bf->bf_nframes = 1;
 -      bf->bf_lastbf = bf;
 -      ath_buf_set_rate(sc, bf);
 -      ath_tx_txqaddbuf(sc, txq, bf_head);
 -      TX_STAT_INC(txq->axq_qnum, queued);
 -}
 -
 -static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 -                             struct list_head *bf_head)
 -{
 -      struct ath_buf *bf;
 -
 -      bf = list_first_entry(bf_head, struct ath_buf, list);
 +      if (tid)
 +              INCR(tid->seq_start, IEEE80211_SEQ_MAX);
  
        bf->bf_lastbf = bf;
 -      bf->bf_nframes = 1;
 -      ath_buf_set_rate(sc, bf);
 +      fi = get_frame_info(bf->bf_mpdu);
 +      ath_buf_set_rate(sc, bf, fi->framelen);
        ath_tx_txqaddbuf(sc, txq, bf_head);
        TX_STAT_INC(txq->axq_qnum, queued);
  }
@@@ -1410,52 -1383,40 +1403,52 @@@ static enum ath9k_pkt_type get_hw_packe
        return htype;
  }
  
 -static void assign_aggr_tid_seqno(struct sk_buff *skb,
 -                                struct ath_buf *bf)
 +static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
 +                           int framelen)
  {
 +      struct ath_wiphy *aphy = hw->priv;
 +      struct ath_softc *sc = aphy->sc;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 +      struct ieee80211_sta *sta = tx_info->control.sta;
 +      struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
        struct ieee80211_hdr *hdr;
 +      struct ath_frame_info *fi = get_frame_info(skb);
        struct ath_node *an;
        struct ath_atx_tid *tid;
 -      __le16 fc;
 -      u8 *qc;
 +      enum ath9k_key_type keytype;
 +      u16 seqno = 0;
 +      u8 tidno;
  
 -      if (!tx_info->control.sta)
 -              return;
 +      keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
  
 -      an = (struct ath_node *)tx_info->control.sta->drv_priv;
        hdr = (struct ieee80211_hdr *)skb->data;
 -      fc = hdr->frame_control;
 +      if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
 +              conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
  
 -      if (ieee80211_is_data_qos(fc)) {
 -              qc = ieee80211_get_qos_ctl(hdr);
 -              bf->bf_tidno = qc[0] & 0xf;
 +              an = (struct ath_node *) sta->drv_priv;
 +              tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 +
 +              /*
 +               * Override seqno set by upper layer with the one
 +               * in tx aggregation state.
 +               */
 +              tid = ATH_AN_2_TID(an, tidno);
 +              seqno = tid->seq_next;
 +              hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
 +              INCR(tid->seq_next, IEEE80211_SEQ_MAX);
        }
  
 -      /*
 -       * For HT capable stations, we save tidno for later use.
 -       * We also override seqno set by upper layer with the one
 -       * in tx aggregation state.
 -       */
 -      tid = ATH_AN_2_TID(an, bf->bf_tidno);
 -      hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
 -      bf->bf_seqno = tid->seq_next;
 -      INCR(tid->seq_next, IEEE80211_SEQ_MAX);
 +      memset(fi, 0, sizeof(*fi));
 +      if (hw_key)
 +              fi->keyix = hw_key->hw_key_idx;
 +      else
 +              fi->keyix = ATH9K_TXKEYIX_INVALID;
 +      fi->keytype = keytype;
 +      fi->framelen = framelen;
 +      fi->seqno = seqno;
  }
  
 -static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
 +static int setup_tx_flags(struct sk_buff *skb)
  {
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        int flags = 0;
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= ATH9K_TXDESC_NOACK;
  
 -      if (use_ldpc)
 +      if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
                flags |= ATH9K_TXDESC_LDPC;
  
        return flags;
   * width  - 0 for 20 MHz, 1 for 40 MHz
   * half_gi - to use 4us v/s 3.6 us for symbol time
   */
 -static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
                            int width, int half_gi, bool shortPreamble)
  {
        u32 nbits, nsymbits, duration, nsymbols;
 -      int streams, pktlen;
 -
 -      pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
 +      int streams;
  
        /* find number of symbols: PLCP + data */
        streams = HT_RC_2_STREAMS(rix);
        return duration;
  }
  
 -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 +u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
 +{
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath9k_channel *curchan = ah->curchan;
 +      if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
 +                      (curchan->channelFlags & CHANNEL_5GHZ) &&
 +                      (chainmask == 0x7) && (rate < 0x90))
 +              return 0x3;
 +      else
 +              return chainmask;
 +}
 +
 +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
  {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath9k_11n_rate_series series[4];
  
                rix = rates[i].idx;
                series[i].Tries = rates[i].count;
 -              series[i].ChSel = common->tx_chainmask;
  
                if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
                    (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
                if (rates[i].flags & IEEE80211_TX_RC_MCS) {
                        /* MCS rates */
                        series[i].Rate = rix | 0x80;
 -                      series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
 +                      series[i].ChSel = ath_txchainmask_reduction(sc,
 +                                      common->tx_chainmask, series[i].Rate);
 +                      series[i].PktDuration = ath_pkt_duration(sc, rix, len,
                                 is_40, is_sgi, is_sp);
                        if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
                                series[i].RateFlags |= ATH9K_RATESERIES_STBC;
                        continue;
                }
  
 -              /* legcay rates */
 +              /* legacy rates */
                if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
                    !(rate->flags & IEEE80211_RATE_ERP_G))
                        phy = WLAN_RC_PHY_CCK;
                        is_sp = false;
                }
  
 +              if (bf->bf_state.bfs_paprd)
 +                      series[i].ChSel = common->tx_chainmask;
 +              else
 +                      series[i].ChSel = ath_txchainmask_reduction(sc,
 +                                      common->tx_chainmask, series[i].Rate);
 +
                series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
 -                      phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
 +                      phy, rate->bitrate * 100, len, rix, is_sp);
        }
  
        /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
 -      if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
 +      if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
                flags &= ~ATH9K_TXDESC_RTSENA;
  
        /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
                ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
  }
  
 -static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
 -                              struct sk_buff *skb,
 -                              struct ath_tx_control *txctl)
 +static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
 +                                         struct ath_txq *txq,
 +                                         struct sk_buff *skb)
  {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
 -      struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 -      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 -      int hdrlen;
 -      __le16 fc;
 -      int padpos, padsize;
 -      bool use_ldpc = false;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 +      struct ath_frame_info *fi = get_frame_info(skb);
 +      struct ath_buf *bf;
 +      struct ath_desc *ds;
 +      int frm_type;
  
 -      tx_info->pad[0] = 0;
 -      switch (txctl->frame_type) {
 -      case ATH9K_IFT_NOT_INTERNAL:
 -              break;
 -      case ATH9K_IFT_PAUSE:
 -              tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
 -              /* fall through */
 -      case ATH9K_IFT_UNPAUSE:
 -              tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
 -              break;
 +      bf = ath_tx_get_buffer(sc);
 +      if (!bf) {
 +              ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
 +              return NULL;
        }
 -      hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 -      fc = hdr->frame_control;
  
        ATH_TXBUF_RESET(bf);
  
        bf->aphy = aphy;
 -      bf->bf_frmlen = skb->len + FCS_LEN;
 -      /* Remove the padding size from bf_frmlen, if any */
 -      padpos = ath9k_cmn_padpos(hdr->frame_control);
 -      padsize = padpos & 3;
 -      if (padsize && skb->len>padpos+padsize) {
 -              bf->bf_frmlen -= padsize;
 -      }
 -
 -      if (!txctl->paprd && conf_is_ht(&hw->conf)) {
 -              bf->bf_state.bf_type |= BUF_HT;
 -              if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
 -                      use_ldpc = true;
 -      }
 -
 -      bf->bf_state.bfs_paprd = txctl->paprd;
 -      if (txctl->paprd)
 -              bf->bf_state.bfs_paprd_timestamp = jiffies;
 -      bf->bf_flags = setup_tx_flags(skb, use_ldpc);
 -
 -      bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 -      if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
 -              bf->bf_frmlen += tx_info->control.hw_key->icv_len;
 -              bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
 -      } else {
 -              bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
 -      }
 -
 -      if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
 -          (sc->sc_flags & SC_OP_TXAGGR))
 -              assign_aggr_tid_seqno(skb, bf);
 -
 +      bf->bf_flags = setup_tx_flags(skb);
        bf->bf_mpdu = skb;
  
        bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
        if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
                bf->bf_mpdu = NULL;
                bf->bf_buf_addr = 0;
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 -                        "dma_mapping_error() on TX\n");
 -              return -ENOMEM;
 +              ath_err(ath9k_hw_common(sc->sc_ah),
 +                      "dma_mapping_error() on TX\n");
 +              ath_tx_return_buffer(sc, bf);
 +              return NULL;
        }
  
 -      bf->bf_tx_aborted = false;
 -
 -      return 0;
 -}
 -
 -/* FIXME: tx power */
 -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 -                           struct ath_tx_control *txctl)
 -{
 -      struct sk_buff *skb = bf->bf_mpdu;
 -      struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
 -      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 -      struct ath_node *an = NULL;
 -      struct list_head bf_head;
 -      struct ath_desc *ds;
 -      struct ath_atx_tid *tid;
 -      struct ath_hw *ah = sc->sc_ah;
 -      int frm_type;
 -      __le16 fc;
 -
        frm_type = get_hw_packet_type(skb);
 -      fc = hdr->frame_control;
 -
 -      INIT_LIST_HEAD(&bf_head);
 -      list_add_tail(&bf->list, &bf_head);
  
        ds = bf->bf_desc;
        ath9k_hw_set_desc_link(ah, ds, 0);
  
 -      ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
 -                             bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
 +      ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
 +                             fi->keyix, fi->keytype, bf->bf_flags);
  
        ath9k_hw_filltxdesc(ah, ds,
                            skb->len,   /* segment length */
                            true,       /* last segment */
                            ds,         /* first descriptor */
                            bf->bf_buf_addr,
 -                          txctl->txq->axq_qnum);
 +                          txq->axq_qnum);
  
 -      if (bf->bf_state.bfs_paprd)
 -              ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
  
 -      spin_lock_bh(&txctl->txq->axq_lock);
 +      return bf;
 +}
 +
 +/* FIXME: tx power */
 +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 +                           struct ath_tx_control *txctl)
 +{
 +      struct sk_buff *skb = bf->bf_mpdu;
 +      struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 +      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 +      struct list_head bf_head;
 +      struct ath_atx_tid *tid;
 +      u8 tidno;
  
 -      if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
 -          tx_info->control.sta) {
 -              an = (struct ath_node *)tx_info->control.sta->drv_priv;
 -              tid = ATH_AN_2_TID(an, bf->bf_tidno);
 +      spin_lock_bh(&txctl->txq->axq_lock);
  
 -              if (!ieee80211_is_data_qos(fc)) {
 -                      ath_tx_send_normal(sc, txctl->txq, &bf_head);
 -                      goto tx_done;
 -              }
 +      if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && txctl->an) {
 +              tidno = ieee80211_get_qos_ctl(hdr)[0] &
 +                      IEEE80211_QOS_CTL_TID_MASK;
 +              tid = ATH_AN_2_TID(txctl->an, tidno);
  
 -              if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
 -                      /*
 -                       * Try aggregation if it's a unicast data frame
 -                       * and the destination is HT capable.
 -                       */
 -                      ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
 -              } else {
 -                      /*
 -                       * Send this frame as regular when ADDBA
 -                       * exchange is neither complete nor pending.
 -                       */
 -                      ath_tx_send_ht_normal(sc, txctl->txq,
 -                                            tid, &bf_head);
 -              }
 +              WARN_ON(tid->ac->txq != txctl->txq);
 +              /*
 +               * Try aggregation if it's a unicast data frame
 +               * and the destination is HT capable.
 +               */
 +              ath_tx_send_ampdu(sc, tid, bf, txctl);
        } else {
 -              ath_tx_send_normal(sc, txctl->txq, &bf_head);
 +              INIT_LIST_HEAD(&bf_head);
 +              list_add_tail(&bf->list, &bf_head);
 +
 +              bf->bf_state.bfs_ftype = txctl->frame_type;
 +              bf->bf_state.bfs_paprd = txctl->paprd;
 +
 +              if (bf->bf_state.bfs_paprd)
 +                      ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
 +                                                 bf->bf_state.bfs_paprd);
 +
 +              ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
        }
  
 -tx_done:
        spin_unlock_bh(&txctl->txq->axq_lock);
  }
  
  int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl)
  {
 +      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 +      struct ieee80211_sta *sta = info->control.sta;
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
 -      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_txq *txq = txctl->txq;
        struct ath_buf *bf;
 -      int q, r;
 -
 -      bf = ath_tx_get_buffer(sc);
 -      if (!bf) {
 -              ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
 -              return -1;
 -      }
 -
 -      r = ath_tx_setup_buffer(hw, bf, skb, txctl);
 -      if (unlikely(r)) {
 -              ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
 -
 -              /* upon ath_tx_processq() this TX queue will be resumed, we
 -               * guarantee this will happen by knowing beforehand that
 -               * we will at least have to run TX completionon one buffer
 -               * on the queue */
 -              spin_lock_bh(&txq->axq_lock);
 -              if (!txq->stopped && txq->axq_depth > 1) {
 -                      ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
 -                      txq->stopped = 1;
 -              }
 -              spin_unlock_bh(&txq->axq_lock);
 -
 -              ath_tx_return_buffer(sc, bf);
 -
 -              return r;
 -      }
 -
 -      q = skb_get_queue_mapping(skb);
 -      if (q >= 4)
 -              q = 0;
 -
 -      spin_lock_bh(&txq->axq_lock);
 -      if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
 -              ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
 -              txq->stopped = 1;
 -      }
 -      spin_unlock_bh(&txq->axq_lock);
 -
 -      ath_tx_start_dma(sc, bf, txctl);
 -
 -      return 0;
 -}
 -
 -void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
 -{
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 -      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 -      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        int padpos, padsize;
 -      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 -      struct ath_tx_control txctl;
 +      int frmlen = skb->len + FCS_LEN;
 +      int q;
 +
 +      /* NOTE:  sta can be NULL according to net/mac80211.h */
 +      if (sta)
 +              txctl->an = (struct ath_node *)sta->drv_priv;
  
 -      memset(&txctl, 0, sizeof(struct ath_tx_control));
 +      if (info->control.hw_key)
 +              frmlen += info->control.hw_key->icv_len;
  
        /*
         * As a temporary workaround, assign seq# here; this will likely need
        /* Add the padding after the header if this is not already done */
        padpos = ath9k_cmn_padpos(hdr->frame_control);
        padsize = padpos & 3;
 -      if (padsize && skb->len>padpos) {
 -              if (skb_headroom(skb) < padsize) {
 -                      ath_print(common, ATH_DBG_XMIT,
 -                                "TX CABQ padding failed\n");
 -                      dev_kfree_skb_any(skb);
 -                      return;
 -              }
 +      if (padsize && skb->len > padpos) {
 +              if (skb_headroom(skb) < padsize)
 +                      return -ENOMEM;
 +
                skb_push(skb, padsize);
                memmove(skb->data, skb->data + padsize, padpos);
        }
  
 -      txctl.txq = sc->beacon.cabq;
 +      setup_frame_info(hw, skb, frmlen);
  
 -      ath_print(common, ATH_DBG_XMIT,
 -                "transmitting CABQ packet, skb: %p\n", skb);
 +      /*
 +       * At this point, the vif, hw_key and sta pointers in the tx control
 +       * info are no longer valid (overwritten by the ath_frame_info data.
 +       */
 +
 +      bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
 +      if (unlikely(!bf))
 +              return -ENOMEM;
  
 -      if (ath_tx_start(hw, skb, &txctl) != 0) {
 -              ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
 -              goto exit;
 +      q = skb_get_queue_mapping(skb);
 +      spin_lock_bh(&txq->axq_lock);
 +      if (txq == sc->tx.txq_map[q] &&
 +          ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
 +              ath_mac80211_stop_queue(sc, q);
 +              txq->stopped = 1;
        }
 +      spin_unlock_bh(&txq->axq_lock);
  
 -      return;
 -exit:
 -      dev_kfree_skb_any(skb);
 +      ath_tx_start_dma(sc, bf, txctl);
 +
 +      return 0;
  }
  
  /*****************/
  /*****************/
  
  static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 -                          struct ath_wiphy *aphy, int tx_flags)
 +                          struct ath_wiphy *aphy, int tx_flags, int ftype,
 +                          struct ath_txq *txq)
  {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        int q, padpos, padsize;
  
 -      ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 +      ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
  
        if (aphy)
                hw = aphy->hw;
  
        if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
 -              ath_print(common, ATH_DBG_PS,
 -                        "Going back to sleep after having "
 -                        "received TX status (0x%lx)\n",
 +              ath_dbg(common, ATH_DBG_PS,
 +                      "Going back to sleep after having received TX status (0x%lx)\n",
                        sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                        PS_WAIT_FOR_CAB |
                                        PS_WAIT_FOR_PSPOLL_DATA |
                                        PS_WAIT_FOR_TX_ACK));
        }
  
 -      if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
 -              ath9k_tx_status(hw, skb);
 +      if (unlikely(ftype))
 +              ath9k_tx_status(hw, skb, ftype);
        else {
                q = skb_get_queue_mapping(skb);
 -              if (q >= 4)
 -                      q = 0;
 -
 -              if (--sc->tx.pending_frames[q] < 0)
 -                      sc->tx.pending_frames[q] = 0;
 +              if (txq == sc->tx.txq_map[q]) {
 +                      spin_lock_bh(&txq->axq_lock);
 +                      if (WARN_ON(--txq->pending_frames < 0))
 +                              txq->pending_frames = 0;
 +                      spin_unlock_bh(&txq->axq_lock);
 +              }
  
                ieee80211_tx_status(hw, skb);
        }
@@@ -1880,14 -1912,15 +1873,14 @@@ static void ath_tx_complete_buf(struct 
        bf->bf_buf_addr = 0;
  
        if (bf->bf_state.bfs_paprd) {
 -              if (time_after(jiffies,
 -                             bf->bf_state.bfs_paprd_timestamp +
 -                             msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
 +              if (!sc->paprd_pending)
                        dev_kfree_skb_any(skb);
                else
                        complete(&sc->paprd_complete);
        } else {
 -              ath_debug_stat_tx(sc, txq, bf, ts);
 -              ath_tx_complete(sc, skb, bf->aphy, tx_flags);
 +              ath_debug_stat_tx(sc, bf, ts);
 +              ath_tx_complete(sc, skb, bf->aphy, tx_flags,
 +                              bf->bf_state.bfs_ftype, txq);
        }
        /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
         * accidentally reference it later.
        spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
  }
  
 -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
 -                            struct ath_tx_status *ts, int txok)
 -{
 -      u16 seq_st = 0;
 -      u32 ba[WME_BA_BMP_SIZE >> 5];
 -      int ba_index;
 -      int nbad = 0;
 -      int isaggr = 0;
 -
 -      if (bf->bf_lastbf->bf_tx_aborted)
 -              return 0;
 -
 -      isaggr = bf_isaggr(bf);
 -      if (isaggr) {
 -              seq_st = ts->ts_seqnum;
 -              memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
 -      }
 -
 -      while (bf) {
 -              ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
 -              if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
 -                      nbad++;
 -
 -              bf = bf->bf_next;
 -      }
 -
 -      return nbad;
 -}
 -
  static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
 -                           int nbad, int txok, bool update_rc)
 +                           int nframes, int nbad, int txok, bool update_rc)
  {
        struct sk_buff *skb = bf->bf_mpdu;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hw *hw = bf->aphy->hw;
 +      struct ath_softc *sc = bf->aphy->sc;
 +      struct ath_hw *ah = sc->sc_ah;
        u8 i, tx_rateindex;
  
        if (txok)
        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
  
 -              BUG_ON(nbad > bf->bf_nframes);
 +              BUG_ON(nbad > nframes);
  
 -              tx_info->status.ampdu_len = bf->bf_nframes;
 -              tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
 +              tx_info->status.ampdu_len = nframes;
 +              tx_info->status.ampdu_ack_len = nframes - nbad;
        }
  
        if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
            (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
 -              if (ieee80211_is_data(hdr->frame_control)) {
 -                      if (ts->ts_flags &
 -                          (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
 -                              tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
 -                      if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
 -                          (ts->ts_status & ATH9K_TXERR_FIFO))
 -                              tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
 -              }
 +              /*
 +               * If an underrun error is seen assume it as an excessive
 +               * retry only if max frame trigger level has been reached
 +               * (2 KB for single stream, and 4 KB for dual stream).
 +               * Adjust the long retry as if the frame was tried
 +               * hw->max_rate_tries times to affect how rate control updates
 +               * PER for the failed rate.
 +               * In case of congestion on the bus penalizing this type of
 +               * underruns should help hardware actually transmit new frames
 +               * successfully by eventually preferring slower rates.
 +               * This itself should also alleviate congestion on the bus.
 +               */
 +              if (ieee80211_is_data(hdr->frame_control) &&
 +                  (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
 +                                   ATH9K_TX_DELIM_UNDERRUN)) &&
 +                  ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
 +                      tx_info->status.rates[tx_rateindex].count =
 +                              hw->max_rate_tries;
        }
  
        for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
        tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
  }
  
 -static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
 +static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
  {
 -      int qnum;
 -
 -      qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
 -      if (qnum == -1)
 -              return;
 +      struct ath_txq *txq;
  
 +      txq = sc->tx.txq_map[qnum];
        spin_lock_bh(&txq->axq_lock);
 -      if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
 +      if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
                if (ath_mac80211_start_queue(sc, qnum))
                        txq->stopped = 0;
        }
@@@ -1983,11 -2036,10 +1976,11 @@@ static void ath_tx_processq(struct ath_
        struct ath_tx_status ts;
        int txok;
        int status;
 +      int qnum;
  
 -      ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
 -                txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
 -                txq->axq_link);
 +      ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
 +              txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
 +              txq->axq_link);
  
        for (;;) {
                spin_lock_bh(&txq->axq_lock);
                         */
                        if (ts.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
 -                      ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
 +                      ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
                }
  
 +              qnum = skb_get_queue_mapping(bf->bf_mpdu);
 +
                if (bf_isampdu(bf))
 -                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
 +                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
 +                                           true);
                else
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
  
 -              ath_wake_mac80211_queue(sc, txq);
 +              if (txq == sc->tx.txq_map[qnum])
 +                      ath_wake_mac80211_queue(sc, qnum);
  
                spin_lock_bh(&txq->axq_lock);
                if (sc->sc_flags & SC_OP_TXAGGR)
@@@ -2102,8 -2150,8 +2095,8 @@@ static void ath_tx_complete_poll_work(s
                }
  
        if (needreset) {
 -              ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
 -                        "tx hung, resetting the chip\n");
 +              ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
 +                      "tx hung, resetting the chip\n");
                ath9k_ps_wakeup(sc);
                ath_reset(sc, true);
                ath9k_ps_restore(sc);
@@@ -2138,15 -2186,14 +2131,15 @@@ void ath_tx_edma_tasklet(struct ath_sof
        struct list_head bf_head;
        int status;
        int txok;
 +      int qnum;
  
        for (;;) {
                status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
                if (status == -EINPROGRESS)
                        break;
                if (status == -EIO) {
 -                      ath_print(common, ATH_DBG_XMIT,
 -                                "Error processing tx status\n");
 +                      ath_dbg(common, ATH_DBG_XMIT,
 +                              "Error processing tx status\n");
                        break;
                }
  
                if (!bf_isampdu(bf)) {
                        if (txs.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
 -                      ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
 +                      ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
                }
  
 +              qnum = skb_get_queue_mapping(bf->bf_mpdu);
 +
                if (bf_isampdu(bf))
 -                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
 +                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
 +                                           txok, true);
                else
                        ath_tx_complete_buf(sc, bf, txq, &bf_head,
                                            &txs, txok, 0);
  
 -              ath_wake_mac80211_queue(sc, txq);
 +              if (txq == sc->tx.txq_map[qnum])
 +                      ath_wake_mac80211_queue(sc, qnum);
  
                spin_lock_bh(&txq->axq_lock);
                if (!list_empty(&txq->txq_fifo_pending)) {
@@@ -2257,16 -2300,16 +2250,16 @@@ int ath_tx_init(struct ath_softc *sc, i
        error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
                                  "tx", nbufs, 1, 1);
        if (error != 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Failed to allocate tx descriptors: %d\n", error);
 +              ath_err(common,
 +                      "Failed to allocate tx descriptors: %d\n", error);
                goto err;
        }
  
        error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
                                  "beacon", ATH_BCBUF, 1, 1);
        if (error != 0) {
 -              ath_print(common, ATH_DBG_FATAL,
 -                        "Failed to allocate beacon descriptors: %d\n", error);
 +              ath_err(common,
 +                      "Failed to allocate beacon descriptors: %d\n", error);
                goto err;
        }
  
@@@ -2324,7 -2367,7 +2317,7 @@@ void ath_tx_node_init(struct ath_softc 
        for (acno = 0, ac = &an->ac[acno];
             acno < WME_NUM_AC; acno++, ac++) {
                ac->sched    = false;
 -              ac->qnum = sc->tx.hwq_map[acno];
 +              ac->txq = sc->tx.txq_map[acno];
                INIT_LIST_HEAD(&ac->tid_q);
        }
  }
@@@ -2334,13 -2377,17 +2327,13 @@@ void ath_tx_node_cleanup(struct ath_sof
        struct ath_atx_ac *ac;
        struct ath_atx_tid *tid;
        struct ath_txq *txq;
 -      int i, tidno;
 +      int tidno;
  
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < WME_NUM_TID; tidno++, tid++) {
 -              i = tid->ac->qnum;
 -
 -              if (!ATH_TXQ_SETUP(sc, i))
 -                      continue;
  
 -              txq = &sc->tx.txq[i];
                ac = tid->ac;
 +              txq = ac->txq;
  
                spin_lock_bh(&txq->axq_lock);
  
index 8e65ffc4cb0a03b2d7ce91cc702c1657b3520340,e5afabee60d1834b898193479cf710c3bb3eed22..e793679e2e190c9321d863512e0756fbaa17713b
@@@ -893,14 -893,6 +893,14 @@@ static int orinoco_ioctl_set_auth(struc
                 */
                break;
  
 +      case IW_AUTH_MFP:
 +              /* Management Frame Protection not supported.
 +               * Only fail if set to required.
 +               */
 +              if (param->value == IW_AUTH_MFP_REQUIRED)
 +                      ret = -EINVAL;
 +              break;
 +
        case IW_AUTH_KEY_MGMT:
                /* wl_lkm implies value 2 == PSK for Hermes I
                 * which ties in with WEXT
                 */
                if (param->value) {
                        priv->tkip_cm_active = 1;
-                       ret = hermes_enable_port(hw, 0);
+                       ret = hermes_disable_port(hw, 0);
                } else {
                        priv->tkip_cm_active = 0;
-                       ret = hermes_disable_port(hw, 0);
+                       ret = hermes_enable_port(hw, 0);
                }
                break;
  
diff --combined net/mac80211/tx.c
index 5d6b0759d18c9d2dab0073d8a2f388ab84bae963,7a637b80a62ef7a8d00d49285d9d6995b4083d9e..0ee56bb0ea7e2c2c2b86e1d02fe899bfa143347c
@@@ -622,8 -622,7 +622,8 @@@ ieee80211_tx_h_rate_ctrl(struct ieee802
                txrc.max_rate_idx = -1;
        else
                txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
 -      txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP;
 +      txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
 +                  tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
  
        /* set up RTS protection if desired */
        if (len > tx->local->hw.wiphy->rts_threshold) {
        if (unlikely(info->control.rates[0].idx < 0))
                return TX_DROP;
  
 -      if (txrc.reported_rate.idx < 0)
 +      if (txrc.reported_rate.idx < 0) {
                txrc.reported_rate = info->control.rates[0];
 -
 -      if (tx->sta)
 +              if (tx->sta && ieee80211_is_data(hdr->frame_control))
 +                      tx->sta->last_tx_rate = txrc.reported_rate;
 +      } else if (tx->sta)
                tx->sta->last_tx_rate = txrc.reported_rate;
  
        if (unlikely(!info->control.rates[0].count))
@@@ -1035,7 -1033,6 +1035,7 @@@ static bool __ieee80211_parse_tx_radiot
        struct ieee80211_radiotap_header *rthdr =
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
 +      bool hw_frag;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
                                                   NULL);
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        tx->flags &= ~IEEE80211_TX_FRAGMENTED;
  
 +      /* packet is fragmented in HW if we have a non-NULL driver callback */
 +      hw_frag = (tx->local->ops->set_frag_threshold != NULL);
 +
        /*
         * for every radiotap entry that is present
         * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
                        }
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
                                info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
 -                      if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
 +                      if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) &&
 +                                                              !hw_frag)
                                tx->flags |= IEEE80211_TX_FRAGMENTED;
                        break;
  
@@@ -1188,10 -1181,8 +1188,10 @@@ ieee80211_tx_prepare(struct ieee80211_s
        /*
         * Set this flag (used below to indicate "automatic fragmentation"),
         * it will be cleared/left by radiotap as desired.
 +       * Only valid when fragmentation is done by the stack.
         */
 -      tx->flags |= IEEE80211_TX_FRAGMENTED;
 +      if (!local->ops->set_frag_threshold)
 +              tx->flags |= IEEE80211_TX_FRAGMENTED;
  
        /* process and remove the injection radiotap header */
        if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
@@@ -1746,15 -1737,13 +1746,13 @@@ netdev_tx_t ieee80211_subif_start_xmit(
        int nh_pos, h_pos;
        struct sta_info *sta = NULL;
        u32 sta_flags = 0;
+       struct sk_buff *tmp_skb;
  
        if (unlikely(skb->len < ETH_HLEN)) {
                ret = NETDEV_TX_OK;
                goto fail;
        }
  
-       nh_pos = skb_network_header(skb) - skb->data;
-       h_pos = skb_transport_header(skb) - skb->data;
        /* convert Ethernet header to proper 802.11 header (based on
         * operation mode) */
        ethertype = (skb->data[12] << 8) | skb->data[13];
                goto fail;
        }
  
+       /*
+        * If the skb is shared we need to obtain our own copy.
+        */
+       if (skb_shared(skb)) {
+               tmp_skb = skb;
+               skb = skb_copy(skb, GFP_ATOMIC);
+               kfree_skb(tmp_skb);
+               if (!skb) {
+                       ret = NETDEV_TX_OK;
+                       goto fail;
+               }
+       }
        hdr.frame_control = fc;
        hdr.duration_id = 0;
        hdr.seq_ctrl = 0;
                encaps_len = 0;
        }
  
+       nh_pos = skb_network_header(skb) - skb->data;
+       h_pos = skb_transport_header(skb) - skb->data;
        skb_pull(skb, skip_header_bytes);
        nh_pos -= skip_header_bytes;
        h_pos -= skip_header_bytes;
@@@ -2315,7 -2321,7 +2330,7 @@@ struct sk_buff *ieee80211_beacon_get_ti
                txrc.max_rate_idx = -1;
        else
                txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
 -      txrc.ap = true;
 +      txrc.bss = true;
        rate_control_get_rate(sdata, NULL, &txrc);
  
        info->control.vif = vif;