mac80211: add more tx skb free fixes (hopefully final fix to #11894)
[openwrt.git] / package / mac80211 / patches / 300-pending_work.patch
index 1fec1b4..9a39b32 100644 (file)
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -360,7 +360,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
- struct ath_vif {
-       int av_bslot;
--      bool is_bslot_active, primary_sta_vif;
-+      bool primary_sta_vif;
-       __le64 tsf_adjust; /* TSF adjustment for staggered beacons */
-       struct ath_buf *av_bcbuf;
- };
-@@ -386,6 +386,7 @@ struct ath_beacon_config {
-       u16 dtim_period;
-       u16 bmiss_timeout;
-       u8 dtim_count;
-+      bool enable_beacon;
- };
- struct ath_beacon {
-@@ -397,7 +398,6 @@ struct ath_beacon {
-       u32 beaconq;
-       u32 bmisscnt;
--      u32 ast_be_xmit;
-       u32 bc_tstamp;
-       struct ieee80211_vif *bslot[ATH_BCBUF];
-       int slottime;
-@@ -411,12 +411,14 @@ struct ath_beacon {
-       bool tx_last;
- };
--void ath_beacon_tasklet(unsigned long data);
--void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
--int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
--void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
--int ath_beaconq_config(struct ath_softc *sc);
--void ath_set_beacon(struct ath_softc *sc);
-+void ath9k_beacon_tasklet(unsigned long data);
-+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
-+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
-+                       u32 changed);
-+void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
-+void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
-+void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);
-+void ath9k_set_beacon(struct ath_softc *sc);
- void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
- /*******************/
-@@ -442,9 +444,12 @@ void ath_rx_poll(unsigned long data);
- void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
- void ath_paprd_calibrate(struct work_struct *work);
- void ath_ani_calibrate(unsigned long data);
--void ath_start_ani(struct ath_common *common);
-+void ath_start_ani(struct ath_softc *sc);
-+void ath_stop_ani(struct ath_softc *sc);
-+void ath_check_ani(struct ath_softc *sc);
- int ath_update_survey_stats(struct ath_softc *sc);
- void ath_update_survey_nf(struct ath_softc *sc, int channel);
-+void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
- /**********/
- /* BTCOEX */
-@@ -613,7 +618,6 @@ enum sc_op_flags {
-       SC_OP_INVALID,
-       SC_OP_BEACONS,
-       SC_OP_RXFLUSH,
--      SC_OP_TSF_RESET,
-       SC_OP_ANI_RUN,
-       SC_OP_PRIM_STA_VIF,
-       SC_OP_HW_RESET,
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -30,7 +30,7 @@ static void ath9k_reset_beacon_status(st
-  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
-  *  settings and channel width min/max
- */
--int ath_beaconq_config(struct ath_softc *sc)
-+static void ath9k_beaconq_config(struct ath_softc *sc)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -38,6 +38,7 @@ int ath_beaconq_config(struct ath_softc 
-       struct ath_txq *txq;
-       ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
-+
-       if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               /* Always burst out beacon and CAB traffic. */
-               qi.tqi_aifs = 1;
-@@ -56,12 +57,9 @@ int ath_beaconq_config(struct ath_softc 
-       }
-       if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
--              ath_err(common,
--                      "Unable to update h/w beacon queue parameters\n");
--              return 0;
-+              ath_err(common, "Unable to update h/w beacon queue parameters\n");
-       } else {
-               ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
--              return 1;
-       }
- }
-@@ -70,7 +68,7 @@ int ath_beaconq_config(struct ath_softc 
-  *  up rate codes, and channel flags. Beacons are always sent out at the
-  *  lowest rate, and are not retried.
- */
--static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
-+static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
-                            struct ath_buf *bf, int rateidx)
- {
-       struct sk_buff *skb = bf->bf_mpdu;
-@@ -81,8 +79,6 @@ static void ath_beacon_setup(struct ath_
-       u8 chainmask = ah->txchainmask;
-       u8 rate = 0;
--      ath9k_reset_beacon_status(sc);
--
-       sband = &sc->sbands[common->hw->conf.channel->band];
-       rate = sband->bitrates[rateidx].hw_value;
-       if (vif->bss_conf.use_short_preamble)
-@@ -111,7 +107,7 @@ static void ath_beacon_setup(struct ath_
-       ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
- }
--static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
-+static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
- {
-       struct ath_softc *sc = hw->priv;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-@@ -128,28 +124,22 @@ static void ath_tx_cabq(struct ieee80211
-       }
- }
--static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
--                                         struct ieee80211_vif *vif)
-+static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
-+                                           struct ieee80211_vif *vif)
- {
-       struct ath_softc *sc = hw->priv;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_buf *bf;
--      struct ath_vif *avp;
-+      struct ath_vif *avp = (void *)vif->drv_priv;
-       struct sk_buff *skb;
--      struct ath_txq *cabq;
-+      struct ath_txq *cabq = sc->beacon.cabq;
-       struct ieee80211_tx_info *info;
-+      struct ieee80211_mgmt *mgmt_hdr;
-       int cabq_depth;
--      ath9k_reset_beacon_status(sc);
--
--      avp = (void *)vif->drv_priv;
--      cabq = sc->beacon.cabq;
--
--      if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
-+      if (avp->av_bcbuf == NULL)
-               return NULL;
--      /* Release the old beacon first */
--
-       bf = avp->av_bcbuf;
-       skb = bf->bf_mpdu;
-       if (skb) {
-@@ -159,14 +149,14 @@ static struct ath_buf *ath_beacon_genera
-               bf->bf_buf_addr = 0;
-       }
--      /* Get a new beacon from mac80211 */
--
-       skb = ieee80211_beacon_get(hw, vif);
--      bf->bf_mpdu = skb;
-       if (skb == NULL)
-               return NULL;
--      ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
--              avp->tsf_adjust;
-+
-+      bf->bf_mpdu = skb;
-+
-+      mgmt_hdr = (struct ieee80211_mgmt *)skb->data;
-+      mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
-       info = IEEE80211_SKB_CB(skb);
-       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-@@ -212,61 +202,52 @@ static struct ath_buf *ath_beacon_genera
-               }
-       }
--      ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
-+      ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
-       while (skb) {
--              ath_tx_cabq(hw, skb);
-+              ath9k_tx_cabq(hw, skb);
-               skb = ieee80211_get_buffered_bc(hw, vif);
-       }
-       return bf;
- }
--int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
-+void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
- {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
--      struct ath_vif *avp;
--      struct ath_buf *bf;
--      struct sk_buff *skb;
--      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
--      __le64 tstamp;
-+      struct ath_vif *avp = (void *)vif->drv_priv;
-+      int slot;
--      avp = (void *)vif->drv_priv;
-+      avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
-+      list_del(&avp->av_bcbuf->list);
--      /* Allocate a beacon descriptor if we haven't done so. */
--      if (!avp->av_bcbuf) {
--              /* Allocate beacon state for hostap/ibss.  We know
--               * a buffer is available. */
--              avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
--                                               struct ath_buf, list);
--              list_del(&avp->av_bcbuf->list);
--
--              if (ath9k_uses_beacons(vif->type)) {
--                      int slot;
--                      /*
--                       * Assign the vif to a beacon xmit slot. As
--                       * above, this cannot fail to find one.
--                       */
--                      avp->av_bslot = 0;
--                      for (slot = 0; slot < ATH_BCBUF; slot++)
--                              if (sc->beacon.bslot[slot] == NULL) {
--                                      avp->av_bslot = slot;
--                                      avp->is_bslot_active = false;
--
--                                      /* NB: keep looking for a double slot */
--                                      if (slot == 0 || !sc->beacon.bslot[slot-1])
--                                              break;
--                              }
--                      BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
--                      sc->beacon.bslot[avp->av_bslot] = vif;
--                      sc->nbcnvifs++;
-+      for (slot = 0; slot < ATH_BCBUF; slot++) {
-+              if (sc->beacon.bslot[slot] == NULL) {
-+                      avp->av_bslot = slot;
-+                      break;
-               }
-       }
--      /* release the previous beacon frame, if it already exists. */
--      bf = avp->av_bcbuf;
--      if (bf->bf_mpdu != NULL) {
--              skb = bf->bf_mpdu;
-+      sc->beacon.bslot[avp->av_bslot] = vif;
-+      sc->nbcnvifs++;
-+
-+      ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
-+              avp->av_bslot);
-+}
-+
-+void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
-+{
-+      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-+      struct ath_vif *avp = (void *)vif->drv_priv;
-+      struct ath_buf *bf = avp->av_bcbuf;
-+
-+      ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
-+              avp->av_bslot);
-+
-+      tasklet_disable(&sc->bcon_tasklet);
-+
-+      if (bf && bf->bf_mpdu) {
-+              struct sk_buff *skb = bf->bf_mpdu;
-               dma_unmap_single(sc->dev, bf->bf_buf_addr,
-                                skb->len, DMA_TO_DEVICE);
-               dev_kfree_skb_any(skb);
-@@ -274,99 +255,74 @@ int ath_beacon_alloc(struct ath_softc *s
-               bf->bf_buf_addr = 0;
-       }
--      /* NB: the beacon data buffer must be 32-bit aligned. */
--      skb = ieee80211_beacon_get(sc->hw, vif);
--      if (skb == NULL)
--              return -ENOMEM;
--
--      tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
--      sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
--      /* Calculate a TSF adjustment factor required for staggered beacons. */
--      if (avp->av_bslot > 0) {
--              u64 tsfadjust;
--              int intval;
-+      avp->av_bcbuf = NULL;
-+      sc->beacon.bslot[avp->av_bslot] = NULL;
-+      sc->nbcnvifs--;
-+      list_add_tail(&bf->list, &sc->beacon.bbuf);
--              intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
-+      tasklet_enable(&sc->bcon_tasklet);
-+}
--              /*
--               * Calculate the TSF offset for this beacon slot, i.e., the
--               * number of usecs that need to be added to the timestamp field
--               * in Beacon and Probe Response frames. Beacon slot 0 is
--               * processed at the correct offset, so it does not require TSF
--               * adjustment. Other slots are adjusted to get the timestamp
--               * close to the TBTT for the BSS.
--               */
--              tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
--              avp->tsf_adjust = cpu_to_le64(tsfadjust);
-+static int ath9k_beacon_choose_slot(struct ath_softc *sc)
-+{
-+      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-+      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-+      u16 intval;
-+      u32 tsftu;
-+      u64 tsf;
-+      int slot;
--              ath_dbg(common, BEACON,
--                      "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
--                      avp->av_bslot, intval, (unsigned long long)tsfadjust);
-+      if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) {
-+              ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
-+                      ath9k_hw_gettsf64(sc->sc_ah));
-+              return 0;
-+      }
--              ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
--                      avp->tsf_adjust;
--      } else
--              avp->tsf_adjust = cpu_to_le64(0);
-+      intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
-+      tsf = ath9k_hw_gettsf64(sc->sc_ah);
-+      tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
-+      tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
-+      slot = (tsftu % (intval * ATH_BCBUF)) / intval;
--      bf->bf_mpdu = skb;
--      bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
--                                       skb->len, DMA_TO_DEVICE);
--      if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
--              dev_kfree_skb_any(skb);
--              bf->bf_mpdu = NULL;
--              bf->bf_buf_addr = 0;
--              ath_err(common, "dma_mapping_error on beacon alloc\n");
--              return -ENOMEM;
--      }
--      avp->is_bslot_active = true;
-+      ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
-+              slot, tsf, tsftu / ATH_BCBUF);
--      return 0;
-+      return slot;
- }
--void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
-+void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
- {
--      if (avp->av_bcbuf != NULL) {
--              struct ath_buf *bf;
-+      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-+      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-+      struct ath_vif *avp = (void *)vif->drv_priv;
-+      u64 tsfadjust;
--              avp->is_bslot_active = false;
--              if (avp->av_bslot != -1) {
--                      sc->beacon.bslot[avp->av_bslot] = NULL;
--                      sc->nbcnvifs--;
--                      avp->av_bslot = -1;
--              }
-+      if (avp->av_bslot == 0)
-+              return;
--              bf = avp->av_bcbuf;
--              if (bf->bf_mpdu != NULL) {
--                      struct sk_buff *skb = bf->bf_mpdu;
--                      dma_unmap_single(sc->dev, bf->bf_buf_addr,
--                                       skb->len, DMA_TO_DEVICE);
--                      dev_kfree_skb_any(skb);
--                      bf->bf_mpdu = NULL;
--                      bf->bf_buf_addr = 0;
--              }
--              list_add_tail(&bf->list, &sc->beacon.bbuf);
-+      tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF;
-+      avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
--              avp->av_bcbuf = NULL;
--      }
-+      ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
-+              (unsigned long long)tsfadjust, avp->av_bslot);
- }
--void ath_beacon_tasklet(unsigned long data)
-+void ath9k_beacon_tasklet(unsigned long data)
- {
-       struct ath_softc *sc = (struct ath_softc *)data;
--      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_buf *bf = NULL;
-       struct ieee80211_vif *vif;
-       bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
-       int slot;
--      u32 bfaddr, bc = 0;
--      if (work_pending(&sc->hw_reset_work)) {
-+      if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
-               ath_dbg(common, RESET,
-                       "reset work is pending, skip beaconing now\n");
-               return;
-       }
-+
-       /*
-        * Check if the previous beacon has gone out.  If
-        * not don't try to post another, skip this period
-@@ -390,55 +346,25 @@ void ath_beacon_tasklet(unsigned long da
-               } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
-                       ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
-                       sc->beacon.bmisscnt = 0;
--                      set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
--                      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+                      ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK);
-               }
-               return;
-       }
--      /*
--       * Generate beacon frames. we are sending frames
--       * staggered so calculate the slot for this frame based
--       * on the tsf to safeguard against missing an swba.
--       */
--
--
--      if (ah->opmode == NL80211_IFTYPE_AP) {
--              u16 intval;
--              u32 tsftu;
--              u64 tsf;
--
--              intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
--              tsf = ath9k_hw_gettsf64(ah);
--              tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
--              tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
--              slot = (tsftu % (intval * ATH_BCBUF)) / intval;
--              vif = sc->beacon.bslot[slot];
--
--              ath_dbg(common, BEACON,
--                      "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
--                      slot, tsf, tsftu / ATH_BCBUF, intval, vif);
--      } else {
--              slot = 0;
--              vif = sc->beacon.bslot[slot];
--      }
-+      slot = ath9k_beacon_choose_slot(sc);
-+      vif = sc->beacon.bslot[slot];
-+      if (!vif || !vif->bss_conf.enable_beacon)
-+              return;
--      bfaddr = 0;
--      if (vif) {
--              bf = ath_beacon_generate(sc->hw, vif);
--              if (bf != NULL) {
--                      bfaddr = bf->bf_daddr;
--                      bc = 1;
--              }
-+      bf = ath9k_beacon_generate(sc->hw, vif);
-+      WARN_ON(!bf);
--              if (sc->beacon.bmisscnt != 0) {
--                      ath_dbg(common, BSTUCK,
--                              "resume beacon xmit after %u misses\n",
--                              sc->beacon.bmisscnt);
--                      sc->beacon.bmisscnt = 0;
--              }
-+      if (sc->beacon.bmisscnt != 0) {
-+              ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
-+                      sc->beacon.bmisscnt);
-+              sc->beacon.bmisscnt = 0;
-       }
-       /*
-@@ -458,39 +384,37 @@ void ath_beacon_tasklet(unsigned long da
-        *     set to ATH_BCBUF so this check is a noop.
-        */
-       if (sc->beacon.updateslot == UPDATE) {
--              sc->beacon.updateslot = COMMIT; /* commit next beacon */
-+              sc->beacon.updateslot = COMMIT;
-               sc->beacon.slotupdate = slot;
--      } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
-+      } else if (sc->beacon.updateslot == COMMIT &&
-+                 sc->beacon.slotupdate == slot) {
-               ah->slottime = sc->beacon.slottime;
-               ath9k_hw_init_global_settings(ah);
-               sc->beacon.updateslot = OK;
-       }
--      if (bfaddr != 0) {
-+
-+      if (bf) {
-+              ath9k_reset_beacon_status(sc);
-+
-               /* NB: cabq traffic should already be queued and primed */
--              ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
-+              ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
-               if (!edma)
-                       ath9k_hw_txstart(ah, sc->beacon.beaconq);
--
--              sc->beacon.ast_be_xmit += bc;     /* XXX per-vif? */
-       }
- }
--static void ath9k_beacon_init(struct ath_softc *sc,
--                            u32 next_beacon,
--                            u32 beacon_period)
-+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
- {
--      if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
--              ath9k_ps_wakeup(sc);
--              ath9k_hw_reset_tsf(sc->sc_ah);
--      }
--
--      ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
-+      struct ath_hw *ah = sc->sc_ah;
--      if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
--              ath9k_ps_restore(sc);
--              clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
--      }
-+      ath9k_hw_disable_interrupts(ah);
-+      ath9k_hw_reset_tsf(ah);
-+      ath9k_beaconq_config(sc);
-+      ath9k_hw_beaconinit(ah, nexttbtt, intval);
-+      sc->beacon.bmisscnt = 0;
-+      ath9k_hw_set_interrupts(ah);
-+      ath9k_hw_enable_interrupts(ah);
- }
- /*
-@@ -498,32 +422,27 @@ static void ath9k_beacon_init(struct ath
-  * burst together.  For the former arrange for the SWBA to be delivered for each
-  * slot. Slots that are not occupied will generate nothing.
-  */
--static void ath_beacon_config_ap(struct ath_softc *sc,
--                               struct ath_beacon_config *conf)
-+static void ath9k_beacon_config_ap(struct ath_softc *sc,
-+                                 struct ath_beacon_config *conf)
- {
-       struct ath_hw *ah = sc->sc_ah;
-+      struct ath_common *common = ath9k_hw_common(ah);
-       u32 nexttbtt, intval;
-       /* NB: the beacon interval is kept internally in TU's */
-       intval = TU_TO_USEC(conf->beacon_interval);
--      intval /= ATH_BCBUF;    /* for staggered beacons */
-+      intval /= ATH_BCBUF;
-       nexttbtt = intval;
--      /*
--       * In AP mode we enable the beacon timers and SWBA interrupts to
--       * prepare beacon frames.
--       */
--      ah->imask |= ATH9K_INT_SWBA;
--      ath_beaconq_config(sc);
-+      if (conf->enable_beacon)
-+              ah->imask |= ATH9K_INT_SWBA;
-+      else
-+              ah->imask &= ~ATH9K_INT_SWBA;
--      /* Set the computed AP beacon timers */
-+      ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
-+              nexttbtt, intval, conf->beacon_interval);
--      ath9k_hw_disable_interrupts(ah);
--      set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
-       ath9k_beacon_init(sc, nexttbtt, intval);
--      sc->beacon.bmisscnt = 0;
--      ath9k_hw_set_interrupts(ah);
--      ath9k_hw_enable_interrupts(ah);
- }
- /*
-@@ -534,8 +453,8 @@ static void ath_beacon_config_ap(struct 
-  * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
-  * we've associated with.
-  */
--static void ath_beacon_config_sta(struct ath_softc *sc,
--                                struct ath_beacon_config *conf)
-+static void ath9k_beacon_config_sta(struct ath_softc *sc,
-+                                  struct ath_beacon_config *conf)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -654,8 +573,8 @@ static void ath_beacon_config_sta(struct
-       ath9k_hw_enable_interrupts(ah);
- }
--static void ath_beacon_config_adhoc(struct ath_softc *sc,
--                                  struct ath_beacon_config *conf)
-+static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
-+                                    struct ath_beacon_config *conf)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -669,82 +588,53 @@ static void ath_beacon_config_adhoc(stru
-       tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
-       nexttbtt = tsf + intval;
--      ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n",
--              nexttbtt, intval, conf->beacon_interval);
--
--      /*
--       * In IBSS mode enable the beacon timers but only enable SWBA interrupts
--       * if we need to manually prepare beacon frames.  Otherwise we use a
--       * self-linked tx descriptor and let the hardware deal with things.
--       */
--      ah->imask |= ATH9K_INT_SWBA;
--
--      ath_beaconq_config(sc);
-+      if (conf->enable_beacon)
-+              ah->imask |= ATH9K_INT_SWBA;
-+      else
-+              ah->imask &= ~ATH9K_INT_SWBA;
--      /* Set the computed ADHOC beacon timers */
-+      ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
-+              nexttbtt, intval, conf->beacon_interval);
--      ath9k_hw_disable_interrupts(ah);
-       ath9k_beacon_init(sc, nexttbtt, intval);
--      sc->beacon.bmisscnt = 0;
--
--      ath9k_hw_set_interrupts(ah);
--      ath9k_hw_enable_interrupts(ah);
- }
--static bool ath9k_allow_beacon_config(struct ath_softc *sc,
--                                    struct ieee80211_vif *vif)
-+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
- {
--      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
--      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-       struct ath_vif *avp = (void *)vif->drv_priv;
--      /*
--       * Can not have different beacon interval on multiple
--       * AP interface case
--       */
--      if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
--          (sc->nbcnvifs > 1) &&
--          (vif->type == NL80211_IFTYPE_AP) &&
--          (cur_conf->beacon_interval != bss_conf->beacon_int)) {
--              ath_dbg(common, CONFIG,
--                      "Changing beacon interval of multiple AP interfaces !\n");
--              return false;
--      }
--      /*
--       * Can not configure station vif's beacon config
--       * while on AP opmode
--       */
--      if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
--          (vif->type != NL80211_IFTYPE_AP)) {
--              ath_dbg(common, CONFIG,
--                      "STA vif's beacon not allowed on AP mode\n");
--              return false;
-+      if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-+              if ((vif->type != NL80211_IFTYPE_AP) ||
-+                  (sc->nbcnvifs > 1)) {
-+                      ath_dbg(common, CONFIG,
-+                              "An AP interface is already present !\n");
-+                      return false;
-+              }
-       }
--      /*
--       * Do not allow beacon config if HW was already configured
--       * with another STA vif
--       */
--      if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
--          (vif->type == NL80211_IFTYPE_STATION) &&
--          test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
--          !avp->primary_sta_vif) {
--              ath_dbg(common, CONFIG,
--                      "Beacon already configured for a station interface\n");
--              return false;
-+
-+      if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
-+              if ((vif->type == NL80211_IFTYPE_STATION) &&
-+                  test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
-+                  !avp->primary_sta_vif) {
-+                      ath_dbg(common, CONFIG,
-+                              "Beacon already configured for a station interface\n");
-+                      return false;
-+              }
-       }
-+
-       return true;
- }
--void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
-+static void ath9k_cache_beacon_config(struct ath_softc *sc,
-+                                    struct ieee80211_bss_conf *bss_conf)
- {
-+      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
--      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
--      if (!ath9k_allow_beacon_config(sc, vif))
--              return;
-+      ath_dbg(common, BEACON,
-+              "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
--      /* Setup the beacon configuration parameters */
-       cur_conf->beacon_interval = bss_conf->beacon_int;
-       cur_conf->dtim_period = bss_conf->dtim_period;
-       cur_conf->listen_interval = 1;
-@@ -769,73 +659,59 @@ void ath_beacon_config(struct ath_softc 
-       if (cur_conf->dtim_period == 0)
-               cur_conf->dtim_period = 1;
--      ath_set_beacon(sc);
- }
--static bool ath_has_valid_bslot(struct ath_softc *sc)
-+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
-+                       u32 changed)
- {
--      struct ath_vif *avp;
--      int slot;
--      bool found = false;
-+      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-+      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
--      for (slot = 0; slot < ATH_BCBUF; slot++) {
--              if (sc->beacon.bslot[slot]) {
--                      avp = (void *)sc->beacon.bslot[slot]->drv_priv;
--                      if (avp->is_bslot_active) {
--                              found = true;
--                              break;
--                      }
-+      ath9k_cache_beacon_config(sc, bss_conf);
-+
-+      if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
-+              ath9k_set_beacon(sc);
-+              set_bit(SC_OP_BEACONS, &sc->sc_flags);
-+      } else {
-+              /*
-+               * Take care of multiple interfaces when
-+               * enabling/disabling SWBA.
-+               */
-+              if (changed & BSS_CHANGED_BEACON_ENABLED) {
-+                      if (!bss_conf->enable_beacon &&
-+                          (sc->nbcnvifs <= 1))
-+                              cur_conf->enable_beacon = false;
-+                      else if (bss_conf->enable_beacon)
-+                              cur_conf->enable_beacon = true;
-               }
-+
-+              ath9k_set_beacon(sc);
-+
-+              if (cur_conf->enable_beacon)
-+                      set_bit(SC_OP_BEACONS, &sc->sc_flags);
-+              else
-+                      clear_bit(SC_OP_BEACONS, &sc->sc_flags);
-       }
--      return found;
- }
--
--void ath_set_beacon(struct ath_softc *sc)
-+void ath9k_set_beacon(struct ath_softc *sc)
- {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-       switch (sc->sc_ah->opmode) {
-       case NL80211_IFTYPE_AP:
--              if (ath_has_valid_bslot(sc))
--                      ath_beacon_config_ap(sc, cur_conf);
-+              ath9k_beacon_config_ap(sc, cur_conf);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_MESH_POINT:
--              ath_beacon_config_adhoc(sc, cur_conf);
-+              ath9k_beacon_config_adhoc(sc, cur_conf);
-               break;
-       case NL80211_IFTYPE_STATION:
--              ath_beacon_config_sta(sc, cur_conf);
-+              ath9k_beacon_config_sta(sc, cur_conf);
-               break;
-       default:
-               ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
-               return;
-       }
--
--      set_bit(SC_OP_BEACONS, &sc->sc_flags);
--}
--
--void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
--{
--      struct ath_hw *ah = sc->sc_ah;
--
--      if (!ath_has_valid_bslot(sc)) {
--              clear_bit(SC_OP_BEACONS, &sc->sc_flags);
--              return;
--      }
--
--      ath9k_ps_wakeup(sc);
--      if (status) {
--              /* Re-enable beaconing */
--              ah->imask |= ATH9K_INT_SWBA;
--              ath9k_hw_set_interrupts(ah);
--      } else {
--              /* Disable SWBA interrupt */
--              ah->imask &= ~ATH9K_INT_SWBA;
--              ath9k_hw_set_interrupts(ah);
--              tasklet_kill(&sc->bcon_tasklet);
--              ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
--      }
--      ath9k_ps_restore(sc);
- }
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -206,10 +206,9 @@ static ssize_t write_file_disable_ani(st
-       if (disable_ani) {
-               clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--              del_timer_sync(&common->ani.timer);
-+              ath_stop_ani(sc);
-       } else {
--              set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--              ath_start_ani(common);
-+              ath_check_ani(sc);
-       }
-       return count;
---- a/drivers/net/wireless/ath/ath9k/debug.h
-+++ b/drivers/net/wireless/ath/ath9k/debug.h
-@@ -32,6 +32,19 @@ struct ath_buf;
- #define RESET_STAT_INC(sc, type) do { } while (0)
- #endif
-+enum ath_reset_type {
-+      RESET_TYPE_BB_HANG,
-+      RESET_TYPE_BB_WATCHDOG,
-+      RESET_TYPE_FATAL_INT,
-+      RESET_TYPE_TX_ERROR,
-+      RESET_TYPE_TX_HANG,
-+      RESET_TYPE_PLL_HANG,
-+      RESET_TYPE_MAC_HANG,
-+      RESET_TYPE_BEACON_STUCK,
-+      RESET_TYPE_MCI,
-+      __RESET_TYPE_MAX
-+};
-+
- #ifdef CONFIG_ATH9K_DEBUGFS
- /**
-@@ -209,17 +222,6 @@ struct ath_rx_stats {
-       u32 rx_frags;
- };
--enum ath_reset_type {
--      RESET_TYPE_BB_HANG,
--      RESET_TYPE_BB_WATCHDOG,
--      RESET_TYPE_FATAL_INT,
--      RESET_TYPE_TX_ERROR,
--      RESET_TYPE_TX_HANG,
--      RESET_TYPE_PLL_HANG,
--      RESET_TYPE_MAC_HANG,
--      __RESET_TYPE_MAX
--};
--
- struct ath_stats {
-       struct ath_interrupt_stats istats;
-       struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
---- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
-+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
-@@ -1111,7 +1111,7 @@ static int ath9k_htc_add_interface(struc
-       if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
-           !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
--              ath9k_hw_set_tsfadjust(priv->ah, 1);
-+              ath9k_hw_set_tsfadjust(priv->ah, true);
-               ath9k_htc_start_ani(priv);
-       }
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2908,9 +2908,9 @@ void ath9k_hw_reset_tsf(struct ath_hw *a
- }
- EXPORT_SYMBOL(ath9k_hw_reset_tsf);
--void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
-+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set)
- {
--      if (setting)
-+      if (set)
-               ah->misc_mode |= AR_PCU_TX_ADD_TSF;
-       else
-               ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -943,7 +943,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah)
- u64 ath9k_hw_gettsf64(struct ath_hw *ah);
- void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
- void ath9k_hw_reset_tsf(struct ath_hw *ah);
--void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
-+void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);
- void ath9k_hw_init_global_settings(struct ath_hw *ah);
- u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
- void ath9k_hw_set11nmac2040(struct ath_hw *ah);
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -560,7 +560,7 @@ static int ath9k_init_softc(u16 devid, s
-       spin_lock_init(&sc->debug.samp_lock);
- #endif
-       tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
--      tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
-+      tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
-                    (unsigned long)sc);
-       INIT_WORK(&sc->hw_reset_work, ath_reset_work);
---- a/drivers/net/wireless/ath/ath9k/link.c
-+++ b/drivers/net/wireless/ath/ath9k/link.c
-@@ -50,8 +50,7 @@ void ath_tx_complete_poll_work(struct wo
-       if (needreset) {
-               ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-                       "tx hung, resetting the chip\n");
--              RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
--              ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+              ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
-               return;
-       }
-@@ -69,6 +68,7 @@ void ath_hw_check(struct work_struct *wo
-       unsigned long flags;
-       int busy;
-       u8 is_alive, nbeacon = 1;
-+      enum ath_reset_type type;
-       ath9k_ps_wakeup(sc);
-       is_alive = ath9k_hw_check_alive(sc->sc_ah);
-@@ -78,7 +78,7 @@ void ath_hw_check(struct work_struct *wo
-       else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
-               ath_dbg(common, RESET,
-                       "DCU stuck is detected. Schedule chip reset\n");
--              RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
-+              type = RESET_TYPE_MAC_HANG;
-               goto sched_reset;
-       }
-@@ -90,7 +90,7 @@ void ath_hw_check(struct work_struct *wo
-               busy, sc->hw_busy_count + 1);
-       if (busy >= 99) {
-               if (++sc->hw_busy_count >= 3) {
--                      RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
-+                      type = RESET_TYPE_BB_HANG;
-                       goto sched_reset;
-               }
-       } else if (busy >= 0) {
-@@ -102,7 +102,7 @@ void ath_hw_check(struct work_struct *wo
-       goto out;
- sched_reset:
--      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+      ath9k_queue_reset(sc, type);
- out:
-       ath9k_ps_restore(sc);
- }
-@@ -119,8 +119,7 @@ static bool ath_hw_pll_rx_hang_check(str
-               count++;
-               if (count == 3) {
-                       ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
--                      RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
--                      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+                      ath9k_queue_reset(sc, RESET_TYPE_PLL_HANG);
-                       count = 0;
-                       return true;
-               }
-@@ -432,26 +431,69 @@ set_timer:
-       }
- }
--void ath_start_ani(struct ath_common *common)
-+void ath_start_ani(struct ath_softc *sc)
- {
--      struct ath_hw *ah = common->ah;
-+      struct ath_hw *ah = sc->sc_ah;
-+      struct ath_common *common = ath9k_hw_common(ah);
-       unsigned long timestamp = jiffies_to_msecs(jiffies);
--      struct ath_softc *sc = (struct ath_softc *) common->priv;
--      if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
--              return;
--
--      if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
-+      if (common->disable_ani ||
-+          !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) ||
-+          (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
-               return;
-       common->ani.longcal_timer = timestamp;
-       common->ani.shortcal_timer = timestamp;
-       common->ani.checkani_timer = timestamp;
-+      ath_dbg(common, ANI, "Starting ANI\n");
-       mod_timer(&common->ani.timer,
-                 jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
- }
-+void ath_stop_ani(struct ath_softc *sc)
-+{
-+      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-+
-+      ath_dbg(common, ANI, "Stopping ANI\n");
-+      del_timer_sync(&common->ani.timer);
-+}
-+
-+void ath_check_ani(struct ath_softc *sc)
-+{
-+      struct ath_hw *ah = sc->sc_ah;
-+      struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-+
-+      /*
-+       * Check for the various conditions in which ANI has to
-+       * be stopped.
-+       */
-+      if (ah->opmode == NL80211_IFTYPE_ADHOC) {
-+              if (!cur_conf->enable_beacon)
-+                      goto stop_ani;
-+      } else if (ah->opmode == NL80211_IFTYPE_AP) {
-+              if (!cur_conf->enable_beacon) {
-+                      /*
-+                       * Disable ANI only when there are no
-+                       * associated stations.
-+                       */
-+                      if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
-+                              goto stop_ani;
-+              }
-+      } else if (ah->opmode == NL80211_IFTYPE_STATION) {
-+              if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
-+                      goto stop_ani;
-+      }
-+
-+      set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-+      ath_start_ani(sc);
-+      return;
-+
-+stop_ani:
-+      clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
-+      ath_stop_ani(sc);
-+}
-+
- void ath_update_survey_nf(struct ath_softc *sc, int channel)
- {
-       struct ath_hw *ah = sc->sc_ah;
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -167,8 +167,6 @@ static void ath_cancel_work(struct ath_s
- static void ath_restart_work(struct ath_softc *sc)
- {
--      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
--
-       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
-       if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
-@@ -177,21 +175,18 @@ static void ath_restart_work(struct ath_
-                                    msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
-       ath_start_rx_poll(sc, 3);
--
--      if (!common->disable_ani)
--              ath_start_ani(common);
-+      ath_start_ani(sc);
- }
- static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
- {
-       struct ath_hw *ah = sc->sc_ah;
--      struct ath_common *common = ath9k_hw_common(ah);
-       bool ret = true;
-       ieee80211_stop_queues(sc->hw);
-       sc->hw_busy_count = 0;
--      del_timer_sync(&common->ani.timer);
-+      ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
-       ath9k_debug_samp_bb_mac(sc);
-@@ -236,7 +231,7 @@ static bool ath_complete_reset(struct at
-               if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
-                       goto work;
--              ath_set_beacon(sc);
-+              ath9k_set_beacon(sc);
-               if (ah->opmode == NL80211_IFTYPE_STATION &&
-                   test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
-@@ -365,6 +360,7 @@ void ath9k_tasklet(unsigned long data)
-       struct ath_softc *sc = (struct ath_softc *)data;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-+      enum ath_reset_type type;
-       unsigned long flags;
-       u32 status = sc->intrstatus;
-       u32 rxmask;
-@@ -374,18 +370,13 @@ void ath9k_tasklet(unsigned long data)
-       if ((status & ATH9K_INT_FATAL) ||
-           (status & ATH9K_INT_BB_WATCHDOG)) {
--#ifdef CONFIG_ATH9K_DEBUGFS
--              enum ath_reset_type type;
-               if (status & ATH9K_INT_FATAL)
-                       type = RESET_TYPE_FATAL_INT;
-               else
-                       type = RESET_TYPE_BB_WATCHDOG;
--              RESET_STAT_INC(sc, type);
--#endif
--              set_bit(SC_OP_HW_RESET, &sc->sc_flags);
--              ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+              ath9k_queue_reset(sc, type);
-               goto out;
-       }
-@@ -575,6 +566,15 @@ static int ath_reset(struct ath_softc *s
-       return r;
- }
-+void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
-+{
-+#ifdef CONFIG_ATH9K_DEBUGFS
-+      RESET_STAT_INC(sc, type);
-+#endif
-+      set_bit(SC_OP_HW_RESET, &sc->sc_flags);
-+      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+}
-+
- void ath_reset_work(struct work_struct *work)
- {
-       struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
-@@ -841,16 +841,6 @@ bool ath9k_uses_beacons(int type)
-       }
- }
--static void ath9k_reclaim_beacon(struct ath_softc *sc,
--                               struct ieee80211_vif *vif)
--{
--      struct ath_vif *avp = (void *)vif->drv_priv;
--
--      ath9k_set_beaconing_status(sc, false);
--      ath_beacon_return(sc, avp);
--      ath9k_set_beaconing_status(sc, true);
--}
--
- static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
- {
-       struct ath9k_vif_iter_data *iter_data = data;
-@@ -918,18 +908,14 @@ static void ath9k_calculate_summary_stat
-       ath9k_calculate_iter_data(hw, vif, &iter_data);
--      /* Set BSSID mask. */
-       memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
-       ath_hw_setbssidmask(common);
--      /* Set op-mode & TSF */
-       if (iter_data.naps > 0) {
--              ath9k_hw_set_tsfadjust(ah, 1);
--              set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
-+              ath9k_hw_set_tsfadjust(ah, true);
-               ah->opmode = NL80211_IFTYPE_AP;
-       } else {
--              ath9k_hw_set_tsfadjust(ah, 0);
--              clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
-+              ath9k_hw_set_tsfadjust(ah, false);
-               if (iter_data.nmeshes)
-                       ah->opmode = NL80211_IFTYPE_MESH_POINT;
-@@ -941,45 +927,14 @@ static void ath9k_calculate_summary_stat
-                       ah->opmode = NL80211_IFTYPE_STATION;
-       }
--      /*
--       * Enable MIB interrupts when there are hardware phy counters.
--       */
-+      ath9k_hw_setopmode(ah);
-+
-       if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
-               ah->imask |= ATH9K_INT_TSFOOR;
-       else
-               ah->imask &= ~ATH9K_INT_TSFOOR;
-       ath9k_hw_set_interrupts(ah);
--
--      /* Set up ANI */
--      if (iter_data.naps > 0) {
--              sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
--
--              if (!common->disable_ani) {
--                      set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--                      ath_start_ani(common);
--              }
--
--      } else {
--              clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--              del_timer_sync(&common->ani.timer);
--      }
--}
--
--/* Called with sc->mutex held, vif counts set up properly. */
--static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
--                                 struct ieee80211_vif *vif)
--{
--      struct ath_softc *sc = hw->priv;
--
--      ath9k_calculate_summary_state(hw, vif);
--
--      if (ath9k_uses_beacons(vif->type)) {
--              /* Reserve a beacon slot for the vif */
--              ath9k_set_beaconing_status(sc, false);
--              ath_beacon_alloc(sc, vif);
--              ath9k_set_beaconing_status(sc, true);
--      }
- }
- static int ath9k_add_interface(struct ieee80211_hw *hw,
-@@ -1021,7 +976,10 @@ static int ath9k_add_interface(struct ie
-       sc->nvifs++;
--      ath9k_do_vif_add_setup(hw, vif);
-+      ath9k_calculate_summary_state(hw, vif);
-+      if (ath9k_uses_beacons(vif->type))
-+              ath9k_beacon_assign_slot(sc, vif);
-+
- out:
-       mutex_unlock(&sc->mutex);
-       ath9k_ps_restore(sc);
-@@ -1038,6 +996,7 @@ static int ath9k_change_interface(struct
-       int ret = 0;
-       ath_dbg(common, CONFIG, "Change Interface\n");
-+
-       mutex_lock(&sc->mutex);
-       ath9k_ps_wakeup(sc);
-@@ -1050,15 +1009,16 @@ static int ath9k_change_interface(struct
-               }
-       }
--      /* Clean up old vif stuff */
-       if (ath9k_uses_beacons(vif->type))
--              ath9k_reclaim_beacon(sc, vif);
-+              ath9k_beacon_remove_slot(sc, vif);
--      /* Add new settings */
-       vif->type = new_type;
-       vif->p2p = p2p;
--      ath9k_do_vif_add_setup(hw, vif);
-+      ath9k_calculate_summary_state(hw, vif);
-+      if (ath9k_uses_beacons(vif->type))
-+              ath9k_beacon_assign_slot(sc, vif);
-+
- out:
-       ath9k_ps_restore(sc);
-       mutex_unlock(&sc->mutex);
-@@ -1078,9 +1038,8 @@ static void ath9k_remove_interface(struc
-       sc->nvifs--;
--      /* Reclaim beacon resources */
-       if (ath9k_uses_beacons(vif->type))
--              ath9k_reclaim_beacon(sc, vif);
-+              ath9k_beacon_remove_slot(sc, vif);
-       ath9k_calculate_summary_state(hw, NULL);
-@@ -1388,10 +1347,6 @@ static int ath9k_conf_tx(struct ieee8021
-       if (ret)
-               ath_err(common, "TXQ Update failed\n");
--      if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
--              if (queue == WME_AC_BE && !ret)
--                      ath_beaconq_config(sc);
--
-       mutex_unlock(&sc->mutex);
-       ath9k_ps_restore(sc);
-@@ -1460,85 +1415,36 @@ static int ath9k_set_key(struct ieee8021
-       return ret;
- }
--static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
-+
-+static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
- {
-       struct ath_softc *sc = data;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
--      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-       struct ath_vif *avp = (void *)vif->drv_priv;
-+      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-       unsigned long flags;
--      /*
--       * Skip iteration if primary station vif's bss info
--       * was not changed
--       */
-+
-       if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
-               return;
-       if (bss_conf->assoc) {
-               set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
-               avp->primary_sta_vif = true;
-+
-               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-               common->curaid = bss_conf->aid;
-               ath9k_hw_write_associd(sc->sc_ah);
--              ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
--                      bss_conf->aid, common->curbssid);
--              ath_beacon_config(sc, vif);
--              /*
--               * Request a re-configuration of Beacon related timers
--               * on the receipt of the first Beacon frame (i.e.,
--               * after time sync with the AP).
--               */
--              spin_lock_irqsave(&sc->sc_pm_lock, flags);
--              sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
--              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
--              /* Reset rssi stats */
-               sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-               sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
--              ath_start_rx_poll(sc, 3);
--
--              if (!common->disable_ani) {
--                      set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--                      ath_start_ani(common);
--              }
--
--      }
--}
--
--static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
--{
--      struct ath_common *common = ath9k_hw_common(sc->sc_ah);
--      struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
--      struct ath_vif *avp = (void *)vif->drv_priv;
--
--      if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
--              return;
--
--      /* Reconfigure bss info */
--      if (avp->primary_sta_vif && !bss_conf->assoc) {
--              ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
--                      common->curaid, common->curbssid);
--              clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
--              clear_bit(SC_OP_BEACONS, &sc->sc_flags);
--              avp->primary_sta_vif = false;
--              memset(common->curbssid, 0, ETH_ALEN);
--              common->curaid = 0;
--      }
--
--      ieee80211_iterate_active_interfaces_atomic(
--                      sc->hw, ath9k_bss_iter, sc);
-+              spin_lock_irqsave(&sc->sc_pm_lock, flags);
-+              sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
-+              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
--      /*
--       * None of station vifs are associated.
--       * Clear bssid & aid
--       */
--      if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
--              ath9k_hw_write_associd(sc->sc_ah);
--              clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--              del_timer_sync(&common->ani.timer);
--              del_timer_sync(&sc->rx_poll_timer);
--              memset(&sc->caldata, 0, sizeof(sc->caldata));
-+              ath_dbg(common, CONFIG,
-+                      "Primary Station interface: %pM, BSSID: %pM\n",
-+                      vif->addr, common->curbssid);
-       }
- }
-@@ -1547,6 +1453,11 @@ static void ath9k_bss_info_changed(struc
-                                  struct ieee80211_bss_conf *bss_conf,
-                                  u32 changed)
- {
-+#define CHECK_ANI                             \
-+      (BSS_CHANGED_ASSOC |                    \
-+       BSS_CHANGED_IBSS |                     \
-+       BSS_CHANGED_BEACON_ENABLED)
-+
-       struct ath_softc *sc = hw->priv;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -1557,53 +1468,43 @@ static void ath9k_bss_info_changed(struc
-       mutex_lock(&sc->mutex);
-       if (changed & BSS_CHANGED_ASSOC) {
--              ath9k_config_bss(sc, vif);
-+              ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
-+                      bss_conf->bssid, bss_conf->assoc);
--              ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n",
--                      common->curbssid, common->curaid);
-+              /*
-+               * Do not do anything when the opmode is not STATION.
-+               */
-+              if (ah->opmode == NL80211_IFTYPE_STATION) {
-+                      if (avp->primary_sta_vif && !bss_conf->assoc) {
-+                              clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
-+                              clear_bit(SC_OP_BEACONS, &sc->sc_flags);
-+                              avp->primary_sta_vif = false;
-+                      }
-+
-+                      ieee80211_iterate_active_interfaces_atomic(sc->hw,
-+                                                 ath9k_bss_assoc_iter, sc);
-+
-+                      if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
-+                              memset(common->curbssid, 0, ETH_ALEN);
-+                              common->curaid = 0;
-+                              ath9k_hw_write_associd(sc->sc_ah);
-+                      }
-+              }
-       }
-       if (changed & BSS_CHANGED_IBSS) {
--              /* There can be only one vif available */
-               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-               common->curaid = bss_conf->aid;
-               ath9k_hw_write_associd(sc->sc_ah);
--
--              if (bss_conf->ibss_joined) {
--                      sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
--
--                      if (!common->disable_ani) {
--                              set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--                              ath_start_ani(common);
--                      }
--
--              } else {
--                      clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
--                      del_timer_sync(&common->ani.timer);
--                      del_timer_sync(&sc->rx_poll_timer);
--              }
-       }
--      /*
--       * In case of AP mode, the HW TSF has to be reset
--       * when the beacon interval changes.
--       */
--      if ((changed & BSS_CHANGED_BEACON_INT) &&
--          (vif->type == NL80211_IFTYPE_AP))
--              set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
--
--      /* Configure beaconing (AP, IBSS, MESH) */
--      if (ath9k_uses_beacons(vif->type) &&
--          ((changed & BSS_CHANGED_BEACON) ||
--           (changed & BSS_CHANGED_BEACON_ENABLED) ||
--           (changed & BSS_CHANGED_BEACON_INT))) {
--              ath9k_set_beaconing_status(sc, false);
--              if (bss_conf->enable_beacon)
--                      ath_beacon_alloc(sc, vif);
--              else
--                      avp->is_bslot_active = false;
--              ath_beacon_config(sc, vif);
--              ath9k_set_beaconing_status(sc, true);
-+      if ((changed & BSS_CHANGED_BEACON) ||
-+          (changed & BSS_CHANGED_BEACON_ENABLED) ||
-+          (changed & BSS_CHANGED_BEACON_INT)) {
-+              if (ah->opmode == NL80211_IFTYPE_AP)
-+                      ath9k_set_tsfadjust(sc, vif);
-+              if (ath9k_allow_beacon_config(sc, vif))
-+                      ath9k_beacon_config(sc, vif, changed);
-       }
-       if (changed & BSS_CHANGED_ERP_SLOT) {
-@@ -1625,8 +1526,13 @@ static void ath9k_bss_info_changed(struc
-               }
-       }
-+      if (changed & CHECK_ANI)
-+              ath_check_ani(sc);
-+
-       mutex_unlock(&sc->mutex);
-       ath9k_ps_restore(sc);
-+
-+#undef CHECK_ANI
- }
- static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-@@ -1855,10 +1761,11 @@ static int ath9k_tx_last_beacon(struct i
-       if (!vif)
-               return 0;
--      avp = (void *)vif->drv_priv;
--      if (!avp->is_bslot_active)
-+      if (!vif->bss_conf.enable_beacon)
-               return 0;
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -325,6 +325,8 @@ ath5k_setup_channels(struct ath5k_hw *ah
+               if (!ath5k_is_standard_channel(ch, band))
+                       continue;
  
-+      avp = (void *)vif->drv_priv;
++              channels[count].max_power = AR5K_TUNE_MAX_TXPOWER/2;
 +
-       if (!sc->beacon.tx_processed && !edma) {
-               tasklet_disable(&sc->bcon_tasklet);
---- a/drivers/net/wireless/ath/ath9k/mci.c
-+++ b/drivers/net/wireless/ath/ath9k/mci.c
-@@ -202,7 +202,7 @@ static void ath_mci_cal_msg(struct ath_s
-       case MCI_GPM_BT_CAL_REQ:
-               if (mci_hw->bt_state == MCI_BT_AWAKE) {
-                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
--                      ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-+                      ath9k_queue_reset(sc, RESET_TYPE_MCI);
-               }
-               ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
-               break;
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_
-               sc->ps_flags &= ~PS_BEACON_SYNC;
-               ath_dbg(common, PS,
-                       "Reconfigure Beacon timers based on timestamp from the AP\n");
--              ath_set_beacon(sc);
-+              ath9k_set_beacon(sc);
+               count++;
        }
  
-       if (ath_beacon_dtim_pending_cab(skb)) {
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -614,10 +614,8 @@ static void ath_tx_complete_aggr(struct 
-       rcu_read_unlock();
--      if (needreset) {
--              RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR);
--              ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
--      }
-+      if (needreset)
-+              ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
- }
- static bool ath_lookup_legacy(struct ath_buf *bf)
-@@ -1586,7 +1584,8 @@ void ath_txq_schedule(struct ath_softc *
-       struct ath_atx_ac *ac, *ac_tmp, *last_ac;
-       struct ath_atx_tid *tid, *last_tid;
--      if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) ||
-+      if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) ||
-+          list_empty(&txq->axq_acq) ||
-           txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
-               return;
-@@ -2191,7 +2190,7 @@ static void ath_tx_processq(struct ath_s
-       ath_txq_lock(sc, txq);
-       for (;;) {
--              if (work_pending(&sc->hw_reset_work))
-+              if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
-                       break;
-               if (list_empty(&txq->axq_q)) {
-@@ -2274,7 +2273,7 @@ void ath_tx_edma_tasklet(struct ath_soft
-       int status;
-       for (;;) {
--              if (work_pending(&sc->hw_reset_work))
-+              if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
-                       break;
-               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -3596,22 +3596,6 @@ void ieee80211_request_smps(struct ieee8
-                           enum ieee80211_smps_mode smps_mode);
- /**
-- * ieee80211_key_removed - disable hw acceleration for key
-- * @key_conf: The key hw acceleration should be disabled for
-- *
-- * This allows drivers to indicate that the given key has been
-- * removed from hardware acceleration, due to a new key that
-- * was added. Don't use this if the key can continue to be used
-- * for TX, if the key restriction is on RX only it is permitted
-- * to keep the key for TX only and not call this function.
-- *
-- * Due to locking constraints, it may only be called during
-- * @set_key. This function must be allowed to sleep, and the
-- * key it tries to disable may still be used until it returns.
-- */
--void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
--
--/**
-  * ieee80211_ready_on_channel - notification of remain-on-channel start
-  * @hw: pointer as obtained from ieee80211_alloc_hw()
-  */
 --- a/net/mac80211/agg-rx.c
 +++ b/net/mac80211/agg-rx.c
 @@ -203,6 +203,8 @@ static void ieee80211_send_addba_resp(st
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-@@ -459,6 +460,7 @@ int ieee80211_start_tx_ba_session(struct
+@@ -460,6 +461,7 @@ int ieee80211_start_tx_ba_session(struct
            sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sdata->vif.type != NL80211_IFTYPE_AP &&
            sdata->vif.type != NL80211_IFTYPE_ADHOC)
                return -EINVAL;
  
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1741,6 +1741,8 @@ static int ieee80211_set_txq_params(stru
-               return -EINVAL;
-       }
+@@ -869,7 +871,7 @@ void ieee80211_process_addba_resp(struct
  
-+      ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
-+
-       return 0;
- }
+       } else {
+               ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
+-                                              true);
++                                              false);
+       }
  
+  out:
 --- a/net/mac80211/debugfs_sta.c
 +++ b/net/mac80211/debugfs_sta.c
 @@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
                            TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
 --- a/net/mac80211/iface.c
 +++ b/net/mac80211/iface.c
-@@ -400,7 +400,6 @@ static int ieee80211_do_open(struct net_
- {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+@@ -420,7 +420,6 @@ int ieee80211_do_open(struct wireless_de
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       struct net_device *dev = wdev->netdev;
        struct ieee80211_local *local = sdata->local;
 -      struct sta_info *sta;
        u32 changed = 0;
        int res;
        u32 hw_reconf_flags = 0;
-@@ -538,28 +537,6 @@ static int ieee80211_do_open(struct net_
+@@ -575,30 +574,8 @@ int ieee80211_do_open(struct wireless_de
  
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
  
 -              }
 -
 -              rate_control_rate_init(sta);
+-              netif_carrier_on(dev);
+-      } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
++      if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+               rcu_assign_pointer(local->p2p_sdata, sdata);
 -      }
--
        /*
         * set_multicast_list will be invoked by the networking core
-        * which will check whether any increments here were done in
-@@ -949,6 +926,72 @@ static void ieee80211_if_setup(struct ne
+@@ -849,7 +826,7 @@ static void ieee80211_do_stop(struct iee
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                       if (info->control.vif == &sdata->vif) {
+                               __skb_unlink(skb, &local->pending[i]);
+-                              dev_kfree_skb_irq(skb);
++                              ieee80211_free_txskb(&local->hw, skb);
+                       }
+               }
+       }
+@@ -997,6 +974,72 @@ static void ieee80211_if_setup(struct ne
        dev->destructor = free_netdev;
  }
  
  static void ieee80211_iface_work(struct work_struct *work)
  {
        struct ieee80211_sub_if_data *sdata =
-@@ -1053,6 +1096,9 @@ static void ieee80211_iface_work(struct 
+@@ -1101,6 +1144,9 @@ static void ieee80211_iface_work(struct 
                                break;
                        ieee80211_mesh_rx_queued_mgmt(sdata, skb);
                        break;
                default:
                        WARN(1, "frame for unexpected interface type");
                        break;
---- a/net/mac80211/key.c
-+++ b/net/mac80211/key.c
-@@ -197,26 +197,6 @@ static void ieee80211_key_disable_hw_acc
-       key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- }
--void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
--{
--      struct ieee80211_key *key;
--
--      key = container_of(key_conf, struct ieee80211_key, conf);
--
--      might_sleep();
--      assert_key_lock(key->local);
--
--      key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
--
--      /*
--       * Flush TX path to avoid attempts to use this key
--       * after this function returns. Until then, drivers
--       * must be prepared to handle the key.
--       */
--      synchronize_rcu();
--}
--EXPORT_SYMBOL_GPL(ieee80211_key_removed);
--
- static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
-                                       int idx, bool uni, bool multi)
- {
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -1108,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned
- }
- /* MLME */
--static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
-+static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
-                                    struct ieee80211_sub_if_data *sdata,
-                                    u8 *wmm_param, size_t wmm_param_len)
- {
-@@ -1119,23 +1119,23 @@ static void ieee80211_sta_wmm_params(str
-       u8 *pos, uapsd_queues = 0;
-       if (!local->ops->conf_tx)
--              return;
-+              return false;
-       if (local->hw.queues < IEEE80211_NUM_ACS)
--              return;
-+              return false;
-       if (!wmm_param)
--              return;
-+              return false;
-       if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
--              return;
-+              return false;
-       if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
-               uapsd_queues = ifmgd->uapsd_queues;
-       count = wmm_param[6] & 0x0f;
-       if (count == ifmgd->wmm_last_param_set)
--              return;
-+              return false;
-       ifmgd->wmm_last_param_set = count;
-       pos = wmm_param + 8;
-@@ -1202,6 +1202,7 @@ static void ieee80211_sta_wmm_params(str
-       /* enable WMM or activate new settings */
-       sdata->vif.bss_conf.qos = true;
-+      return true;
- }
- static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
-@@ -2435,14 +2436,6 @@ static void ieee80211_rx_mgmt_beacon(str
-               directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
-                                                  ifmgd->aid);
--      if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
--              ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
--                                    true);
--
--              ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
--                                       elems.wmm_param_len);
--      }
--
-       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
-               if (directed_tim) {
-                       if (local->hw.conf.dynamic_ps_timeout > 0) {
-@@ -2473,6 +2466,13 @@ static void ieee80211_rx_mgmt_beacon(str
-       ifmgd->beacon_crc = ncrc;
-       ifmgd->beacon_crc_valid = true;
-+      ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
-+                            true);
-+
-+      if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
-+                                   elems.wmm_param_len))
-+              changed |= BSS_CHANGED_QOS;
-+
-       if (elems.erp_info && elems.erp_info_len >= 1) {
-               erp_valid = true;
-               erp_value = elems.erp_info[0];
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct 
- #ifdef CONFIG_MAC80211_DEBUGFS
-       /* use fixed index if set */
--      if (mp->fixed_rate_idx != -1)
--              sample_idx = mp->fixed_rate_idx;
-+      if (mp->fixed_rate_idx != -1) {
-+              mi->max_tp_rate = mp->fixed_rate_idx;
-+              mi->max_tp_rate2 = mp->fixed_rate_idx;
-+              mi->max_prob_rate = mp->fixed_rate_idx;
-+              sample_idx = -1;
-+      }
- #endif
-       if (sample_idx >= 0) {
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -2262,6 +2262,7 @@ ieee80211_rx_h_action(struct ieee80211_r
+@@ -2279,6 +2279,7 @@ ieee80211_rx_h_action(struct ieee80211_r
                    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP &&
                    sdata->vif.type != NL80211_IFTYPE_ADHOC)
                        break;
  
-@@ -2479,14 +2480,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+@@ -2496,14 +2497,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
  
        if (!ieee80211_vif_is_mesh(&sdata->vif) &&
            sdata->vif.type != NL80211_IFTYPE_ADHOC &&
                break;
        case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
        case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
-@@ -2817,10 +2819,16 @@ static int prepare_for_handlers(struct i
+@@ -2827,10 +2829,16 @@ static int prepare_for_handlers(struct i
                }
                break;
        case NL80211_IFTYPE_WDS:
 +                      return 0;
 +
                break;
-       default:
-               /* should never get here */
+       case NL80211_IFTYPE_P2P_DEVICE:
+               if (!ieee80211_is_public_action(hdr, skb->len) &&
 --- a/net/mac80211/sta_info.h
 +++ b/net/mac80211/sta_info.h
 @@ -32,7 +32,6 @@
        WLAN_STA_CLEAR_PS_FILT,
        WLAN_STA_MFP,
        WLAN_STA_BLOCK_BA,
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2716,7 +2716,7 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc)
- void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
-                         struct sk_buff *skb, int tid)
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct 
+               skb_queue_len(&local->skb_queue_unreliable);
+       while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
+              (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+-              dev_kfree_skb_irq(skb);
++              ieee80211_free_txskb(hw, skb);
+               tmp--;
+               I802_DEBUG_INC(local->tx_status_drop);
+       }
+@@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_fr
+                          "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
+                          skb_queue_len(&sta->tx_filtered[ac]),
+                          !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
+-      dev_kfree_skb(skb);
++      ieee80211_free_txskb(&local->hw, skb);
+ }
+ static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
+@@ -324,6 +324,75 @@ static void ieee80211_add_tx_radiotap_he
+ }
++static void ieee80211_report_used_skb(struct ieee80211_local *local,
++                                    struct sk_buff *skb, bool dropped)
++{
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++      struct ieee80211_hdr *hdr = (void *)skb->data;
++      bool acked = info->flags & IEEE80211_TX_STAT_ACK;
++
++      if (dropped)
++              acked = false;
++
++      if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
++              struct ieee80211_sub_if_data *sdata = NULL;
++              struct ieee80211_sub_if_data *iter_sdata;
++              u64 cookie = (unsigned long)skb;
++
++              rcu_read_lock();
++
++              if (skb->dev) {
++                      list_for_each_entry_rcu(iter_sdata, &local->interfaces,
++                                              list) {
++                              if (!iter_sdata->dev)
++                                      continue;
++
++                              if (skb->dev == iter_sdata->dev) {
++                                      sdata = iter_sdata;
++                                      break;
++                              }
++                      }
++              } else {
++                      sdata = rcu_dereference(local->p2p_sdata);
++              }
++
++              if (!sdata)
++                      skb->dev = NULL;
++              else if (ieee80211_is_nullfunc(hdr->frame_control) ||
++                       ieee80211_is_qos_nullfunc(hdr->frame_control)) {
++                      cfg80211_probe_status(sdata->dev, hdr->addr1,
++                                            cookie, acked, GFP_ATOMIC);
++              } else {
++                      cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
++                                              skb->len, acked, GFP_ATOMIC);
++              }
++
++              rcu_read_unlock();
++      }
++
++      if (unlikely(info->ack_frame_id)) {
++              struct sk_buff *ack_skb;
++              unsigned long flags;
++
++              spin_lock_irqsave(&local->ack_status_lock, flags);
++              ack_skb = idr_find(&local->ack_status_frames,
++                                 info->ack_frame_id);
++              if (ack_skb)
++                      idr_remove(&local->ack_status_frames,
++                                 info->ack_frame_id);
++              spin_unlock_irqrestore(&local->ack_status_lock, flags);
++
++              if (ack_skb) {
++                      if (!dropped) {
++                              /* consumes ack_skb */
++                              skb_complete_wifi_ack(ack_skb, acked);
++                      } else {
++                              dev_kfree_skb_any(ack_skb);
++                      }
++              }
++      }
++}
++
+ /*
+  * Use a static threshold for now, best value to be determined
+  * by testing ...
+@@ -515,50 +584,7 @@ void ieee80211_tx_status(struct ieee8021
+                                       msecs_to_jiffies(10));
+       }
+-      if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+-              u64 cookie = (unsigned long)skb;
+-              acked = info->flags & IEEE80211_TX_STAT_ACK;
+-
+-              if (ieee80211_is_nullfunc(hdr->frame_control) ||
+-                  ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+-                      cfg80211_probe_status(skb->dev, hdr->addr1,
+-                                            cookie, acked, GFP_ATOMIC);
+-              } else if (skb->dev) {
+-                      cfg80211_mgmt_tx_status(
+-                              skb->dev->ieee80211_ptr, cookie, skb->data,
+-                              skb->len, acked, GFP_ATOMIC);
+-              } else {
+-                      struct ieee80211_sub_if_data *p2p_sdata;
+-
+-                      rcu_read_lock();
+-
+-                      p2p_sdata = rcu_dereference(local->p2p_sdata);
+-                      if (p2p_sdata) {
+-                              cfg80211_mgmt_tx_status(
+-                                      &p2p_sdata->wdev, cookie, skb->data,
+-                                      skb->len, acked, GFP_ATOMIC);
+-                      }
+-                      rcu_read_unlock();
+-              }
+-      }
+-
+-      if (unlikely(info->ack_frame_id)) {
+-              struct sk_buff *ack_skb;
+-              unsigned long flags;
+-
+-              spin_lock_irqsave(&local->ack_status_lock, flags);
+-              ack_skb = idr_find(&local->ack_status_frames,
+-                                 info->ack_frame_id);
+-              if (ack_skb)
+-                      idr_remove(&local->ack_status_frames,
+-                                 info->ack_frame_id);
+-              spin_unlock_irqrestore(&local->ack_status_lock, flags);
+-
+-              /* consumes ack_skb */
+-              if (ack_skb)
+-                      skb_complete_wifi_ack(ack_skb,
+-                              info->flags & IEEE80211_TX_STAT_ACK);
+-      }
++      ieee80211_report_used_skb(local, skb, false);
+       /* this was a transmitted frame, but now we want to reuse it */
+       skb_orphan(skb);
+@@ -634,25 +660,17 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
+ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
  {
--      int ac = ieee802_1d_to_ac[tid];
-+      int ac = ieee802_1d_to_ac[tid & 7];
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -136,9 +136,16 @@ cfg80211_get_chan_state(struct cfg80211_
-               break;
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_P2P_GO:
-+              if (wdev->beacon_interval) {
-+                      *chan = wdev->channel;
-+                      *chanmode = CHAN_MODE_SHARED;
+       struct ieee80211_local *local = hw_to_local(hw);
+-      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-
+-      if (unlikely(info->ack_frame_id)) {
+-              struct sk_buff *ack_skb;
+-              unsigned long flags;
+-
+-              spin_lock_irqsave(&local->ack_status_lock, flags);
+-              ack_skb = idr_find(&local->ack_status_frames,
+-                                 info->ack_frame_id);
+-              if (ack_skb)
+-                      idr_remove(&local->ack_status_frames,
+-                                 info->ack_frame_id);
+-              spin_unlock_irqrestore(&local->ack_status_lock, flags);
+-
+-              /* consumes ack_skb */
+-              if (ack_skb)
+-                      dev_kfree_skb_any(ack_skb);
+-      }
++      ieee80211_report_used_skb(local, skb, true);
+       dev_kfree_skb_any(skb);
+ }
+ EXPORT_SYMBOL(ieee80211_free_txskb);
++
++void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
++                            struct sk_buff_head *skbs)
++{
++      struct sk_buff *skb;
++
++      while ((skb = __skb_dequeue(skbs)))
++              ieee80211_free_txskb(hw, skb);
++}
+--- a/drivers/net/wireless/p54/main.c
++++ b/drivers/net/wireless/p54/main.c
+@@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru
+ static int p54_beacon_update(struct p54_common *priv,
+                       struct ieee80211_vif *vif)
+ {
++      struct ieee80211_tx_control control = { };
+       struct sk_buff *beacon;
+       int ret;
+@@ -158,7 +159,7 @@ static int p54_beacon_update(struct p54_
+        * to cancel the old beacon template by hand, instead the firmware
+        * will release the previous one through the feedback mechanism.
+        */
+-      p54_tx_80211(priv->hw, NULL, beacon);
++      p54_tx_80211(priv->hw, &control, beacon);
+       priv->tsf_high32 = 0;
+       priv->tsf_low32 = 0;
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -352,6 +352,9 @@ static void reg_regdb_search(struct work
+       struct reg_regdb_search_request *request;
+       const struct ieee80211_regdomain *curdom, *regdom;
+       int i, r;
++      bool set_reg = false;
++
++      mutex_lock(&cfg80211_mutex);
+       mutex_lock(&reg_regdb_search_mutex);
+       while (!list_empty(&reg_regdb_search_list)) {
+@@ -367,9 +370,7 @@ static void reg_regdb_search(struct work
+                               r = reg_copy_regd(&regdom, curdom);
+                               if (r)
+                                       break;
+-                              mutex_lock(&cfg80211_mutex);
+-                              set_regdom(regdom);
+-                              mutex_unlock(&cfg80211_mutex);
++                              set_reg = true;
+                               break;
+                       }
+               }
+@@ -377,6 +378,11 @@ static void reg_regdb_search(struct work
+               kfree(request);
+       }
+       mutex_unlock(&reg_regdb_search_mutex);
++
++      if (set_reg)
++              set_regdom(regdom);
++
++      mutex_unlock(&cfg80211_mutex);
+ }
+ static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -424,8 +424,8 @@ u32 ath_calcrxfilter(struct ath_softc *s
+               rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+       if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
+-              /* The following may also be needed for other older chips */
+-              if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
++              /* This is needed for older chips */
++              if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
+                       rfilt |= ATH9K_RX_FILTER_PROM;
+               rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+       }
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -818,23 +818,71 @@ void ieee80211_sta_process_chanswitch(st
+ }
+ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+-                                      u16 capab_info, u8 *pwr_constr_elem,
+-                                      u8 pwr_constr_elem_len)
++                                      struct ieee80211_channel *channel,
++                                      const u8 *country_ie, u8 country_ie_len,
++                                      const u8 *pwr_constr_elem)
+ {
+-      struct ieee80211_conf *conf = &sdata->local->hw.conf;
++      struct ieee80211_country_ie_triplet *triplet;
++      int chan = ieee80211_frequency_to_channel(channel->center_freq);
++      int i, chan_pwr, chan_increment, new_ap_level;
++      bool have_chan_pwr = false;
+-      if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
++      /* Invalid IE */
++      if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
+               return;
+-      /* Power constraint IE length should be 1 octet */
+-      if (pwr_constr_elem_len != 1)
+-              return;
++      triplet = (void *)(country_ie + 3);
++      country_ie_len -= 3;
+-      if ((*pwr_constr_elem <= conf->channel->max_reg_power) &&
+-          (*pwr_constr_elem != sdata->local->power_constr_level)) {
+-              sdata->local->power_constr_level = *pwr_constr_elem;
+-              ieee80211_hw_config(sdata->local, 0);
++      switch (channel->band) {
++      default:
++              WARN_ON_ONCE(1);
++              /* fall through */
++      case IEEE80211_BAND_2GHZ:
++      case IEEE80211_BAND_60GHZ:
++              chan_increment = 1;
++              break;
++      case IEEE80211_BAND_5GHZ:
++              chan_increment = 4;
++              break;
+       }
++
++      /* find channel */
++      while (country_ie_len >= 3) {
++              u8 first_channel = triplet->chans.first_channel;
++
++              if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
++                      goto next;
++
++              for (i = 0; i < triplet->chans.num_channels; i++) {
++                      if (first_channel + i * chan_increment == chan) {
++                              have_chan_pwr = true;
++                              chan_pwr = triplet->chans.max_power;
++                              break;
++                      }
 +              }
++              if (have_chan_pwr)
++                      break;
++
++ next:
++              triplet++;
++              country_ie_len -= 3;
++      }
++
++      if (!have_chan_pwr)
 +              return;
-       case NL80211_IFTYPE_MESH_POINT:
--              *chan = wdev->channel;
--              *chanmode = CHAN_MODE_SHARED;
-+              if (wdev->mesh_id_len) {
-+                      *chan = wdev->channel;
-+                      *chanmode = CHAN_MODE_SHARED;
-+              }
++
++      new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
++
++      if (sdata->local->ap_power_level == new_ap_level)
++              return;
++
++      sdata_info(sdata,
++                 "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
++                 new_ap_level, chan_pwr, *pwr_constr_elem,
++                 sdata->u.mgd.bssid);
++      sdata->local->ap_power_level = new_ap_level;
++      ieee80211_hw_config(sdata->local, 0);
+ }
+ void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+@@ -1390,7 +1438,7 @@ static void ieee80211_set_disassoc(struc
+       sta = sta_info_get(sdata, ifmgd->bssid);
+       if (sta) {
+               set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+-              ieee80211_sta_tear_down_BA_sessions(sta, tx);
++              ieee80211_sta_tear_down_BA_sessions(sta, false);
+       }
+       mutex_unlock(&local->sta_mtx);
+@@ -1438,7 +1486,7 @@ static void ieee80211_set_disassoc(struc
+       memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
+       memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
+-      local->power_constr_level = 0;
++      local->ap_power_level = 0;
+       del_timer_sync(&local->dynamic_ps_timer);
+       cancel_work_sync(&local->dynamic_ps_enable_work);
+@@ -2530,15 +2578,13 @@ static void ieee80211_rx_mgmt_beacon(str
+                                                 bssid, true);
+       }
+-      /* Note: country IE parsing is done for us by cfg80211 */
+-      if (elems.country_elem) {
+-              /* TODO: IBSS also needs this */
+-              if (elems.pwr_constr_elem)
+-                      ieee80211_handle_pwr_constr(sdata,
+-                              le16_to_cpu(mgmt->u.probe_resp.capab_info),
+-                              elems.pwr_constr_elem,
+-                              elems.pwr_constr_elem_len);
+-      }
++      if (elems.country_elem && elems.pwr_constr_elem &&
++          mgmt->u.probe_resp.capab_info &
++                              cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
++              ieee80211_handle_pwr_constr(sdata, local->oper_channel,
++                                          elems.country_elem,
++                                          elems.country_elem_len,
++                                          elems.pwr_constr_elem);
+       ieee80211_bss_info_change_notify(sdata, changed);
+ }
+@@ -3526,6 +3572,7 @@ int ieee80211_mgd_deauth(struct ieee8021
+ {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 frame_buf[DEAUTH_DISASSOC_LEN];
++      bool tx = !req->local_state_change;
+       mutex_lock(&ifmgd->mtx);
+@@ -3542,12 +3589,12 @@ int ieee80211_mgd_deauth(struct ieee8021
+       if (ifmgd->associated &&
+           ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
+               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+-                                     req->reason_code, true, frame_buf);
++                                     req->reason_code, tx, frame_buf);
+       } else {
+               drv_mgd_prepare_tx(sdata->local, sdata);
+               ieee80211_send_deauth_disassoc(sdata, req->bssid,
+                                              IEEE80211_STYPE_DEAUTH,
+-                                             req->reason_code, true,
++                                             req->reason_code, tx,
+                                              frame_buf);
+       }
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -585,7 +585,7 @@ static bool sta_info_cleanup_expire_buff
+                */
+               if (!skb)
+                       break;
+-              dev_kfree_skb(skb);
++              ieee80211_free_txskb(&local->hw, skb);
+       }
+       /*
+@@ -614,7 +614,7 @@ static bool sta_info_cleanup_expire_buff
+               local->total_ps_buffered--;
+               ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
+                      sta->sta.addr);
+-              dev_kfree_skb(skb);
++              ieee80211_free_txskb(&local->hw, skb);
+       }
+       /*
+@@ -674,7 +674,7 @@ int __must_check __sta_info_destroy(stru
+        * will be sufficient.
+        */
+       set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+-      ieee80211_sta_tear_down_BA_sessions(sta, true);
++      ieee80211_sta_tear_down_BA_sessions(sta, false);
+       ret = sta_info_hash_del(local, sta);
+       if (ret)
+@@ -730,8 +730,8 @@ int __must_check __sta_info_destroy(stru
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
+-              __skb_queue_purge(&sta->ps_tx_buf[ac]);
+-              __skb_queue_purge(&sta->tx_filtered[ac]);
++              ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
++              ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
+       }
+ #ifdef CONFIG_MAC80211_MESH
+@@ -765,7 +765,7 @@ int __must_check __sta_info_destroy(stru
+               tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
+               if (!tid_tx)
+                       continue;
+-              __skb_queue_purge(&tid_tx->pending);
++              ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
+               kfree(tid_tx);
+       }
+--- a/drivers/net/wireless/ath/ath5k/phy.c
++++ b/drivers/net/wireless/ath/ath5k/phy.c
+@@ -1977,11 +1977,13 @@ ath5k_hw_set_spur_mitigation_filter(stru
+                       spur_delta_phase = (spur_offset << 18) / 25;
+                       spur_freq_sigma_delta = (spur_delta_phase >> 10);
+                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
++                      break;
+               case AR5K_BWMODE_5MHZ:
+                       /* Both sample_freq and chip_freq are 10MHz (?) */
+                       spur_delta_phase = (spur_offset << 19) / 25;
+                       spur_freq_sigma_delta = (spur_delta_phase >> 10);
+                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
++                      break;
+               default:
+                       if (channel->band == IEEE80211_BAND_5GHZ) {
+                               /* Both sample_freq and chip_freq are 40MHz */
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1062,7 +1062,7 @@ struct ieee80211_local {
+       bool disable_dynamic_ps;
+       int user_power_level; /* in dBm */
+-      int power_constr_level; /* in dBm */
++      int ap_power_level; /* in dBm */
+       enum ieee80211_smps_mode smps_mode;
+@@ -1170,7 +1170,6 @@ struct ieee802_11_elems {
+       u8 prep_len;
+       u8 perr_len;
+       u8 country_elem_len;
+-      u8 pwr_constr_elem_len;
+       u8 quiet_elem_len;
+       u8 num_of_quiet_elem;   /* can be more the one */
+       u8 timeout_int_len;
+@@ -1318,6 +1317,8 @@ netdev_tx_t ieee80211_monitor_start_xmit
+                                        struct net_device *dev);
+ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
+                                      struct net_device *dev);
++void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
++                            struct sk_buff_head *skbs);
+ /* HT */
+ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ie
+       int queue = info->hw_queue;
+       if (WARN_ON(!info->control.vif)) {
+-              kfree_skb(skb);
++              ieee80211_free_txskb(&local->hw, skb);
+               return;
+       }
+@@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struc
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+               if (WARN_ON(!info->control.vif)) {
+-                      kfree_skb(skb);
++                      ieee80211_free_txskb(&local->hw, skb);
+                       continue;
+               }
+@@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start
+                       elems->country_elem_len = elen;
+                       break;
+               case WLAN_EID_PWR_CONSTRAINT:
++                      if (elen != 1) {
++                              elem_parse_failed = true;
++                              break;
++                      }
+                       elems->pwr_constr_elem = pos;
+-                      elems->pwr_constr_elem_len = elen;
+                       break;
+               case WLAN_EID_TIMEOUT_INTERVAL:
+                       elems->timeout_int = pos;
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -154,13 +154,11 @@ int ieee80211_hw_config(struct ieee80211
+       if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+           test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
+-          test_bit(SCAN_HW_SCANNING, &local->scanning))
++          test_bit(SCAN_HW_SCANNING, &local->scanning) ||
++          !local->ap_power_level)
+               power = chan->max_power;
+       else
+-              power = local->power_constr_level ?
+-                      min(chan->max_power,
+-                              (chan->max_reg_power  - local->power_constr_level)) :
+-                      chan->max_power;
++              power = min(chan->max_power, local->ap_power_level);
+       if (local->user_power_level >= 0)
+               power = min(power, local->user_power_level);
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request {
+       const u8 *ie;
+       size_t ie_len;
+       u16 reason_code;
++      bool local_state_change;
+ };
+ /**
+--- a/net/wireless/mlme.c
++++ b/net/wireless/mlme.c
+@@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg802
+               .reason_code = reason,
+               .ie = ie,
+               .ie_len = ie_len,
++              .local_state_change = local_state_change,
+       };
+       ASSERT_WDEV_LOCK(wdev);
+-      if (local_state_change) {
+-              if (wdev->current_bss &&
+-                  ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
+-                      cfg80211_unhold_bss(wdev->current_bss);
+-                      cfg80211_put_bss(&wdev->current_bss->pub);
+-                      wdev->current_bss = NULL;
+-              }
+-
++      if (local_state_change && (!wdev->current_bss ||
++          !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
+               return 0;
+-      }
+       return rdev->ops->deauth(&rdev->wiphy, dev, &req);
+ }
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -386,7 +386,7 @@ static void ath_tx_complete_aggr(struct 
+       u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first;
+       u32 ba[WME_BA_BMP_SIZE >> 5];
+       int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
+-      bool rc_update = true;
++      bool rc_update = true, isba;
+       struct ieee80211_tx_rate rates[4];
+       struct ath_frame_info *fi;
+       int nframes;
+@@ -430,13 +430,17 @@ static void ath_tx_complete_aggr(struct 
+       tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+       tid = ATH_AN_2_TID(an, tidno);
+       seq_first = tid->seq_start;
++      isba = ts->ts_flags & ATH9K_TX_BA;
+       /*
+        * 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
++       *
++       * Only BlockAcks have a TID and therefore normal Acks cannot be
++       * checked
+        */
+-      if (tidno != ts->tid)
++      if (isba && tidno != ts->tid)
+               txok = false;
+       isaggr = bf_isaggr(bf);
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2563,6 +2563,9 @@ static void ieee80211_mgmt_frame_registe
+               else
+                       local->probe_req_reg--;
++              if (!local->open_count)
++                      break;
++
+               ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+               break;
+       default:
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct 
+                       total += skb_queue_len(&sta->ps_tx_buf[ac]);
+                       if (skb) {
+                               purged++;
+-                              dev_kfree_skb(skb);
++                              ieee80211_free_txskb(&local->hw, skb);
+                               break;
+                       }
+               }
+@@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+                       ps_dbg(tx->sdata,
+                              "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
+                              sta->sta.addr, ac);
+-                      dev_kfree_skb(old);
++                      ieee80211_free_txskb(&local->hw, old);
+               } else
+                       tx->local->total_ps_buffered++;
+@@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct
+               spin_unlock(&tx->sta->lock);
+               if (purge_skb)
+-                      dev_kfree_skb(purge_skb);
++                      ieee80211_free_txskb(&tx->local->hw, purge_skb);
+       }
+       /* reset session timer */
+@@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ie
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+               if (WARN_ON_ONCE(q >= local->hw.queues)) {
+                       __skb_unlink(skb, skbs);
+-                      dev_kfree_skb(skb);
++                      ieee80211_free_txskb(&local->hw, skb);
+                       continue;
+               }
+ #endif
+@@ -1356,9 +1356,9 @@ static int invoke_tx_handlers(struct iee
+       if (unlikely(res == TX_DROP)) {
+               I802_DEBUG_INC(tx->local->tx_handlers_drop);
+               if (tx->skb)
+-                      dev_kfree_skb(tx->skb);
++                      ieee80211_free_txskb(&tx->local->hw, tx->skb);
+               else
+-                      __skb_queue_purge(&tx->skbs);
++                      ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
+               return -1;
+       } else if (unlikely(res == TX_QUEUED)) {
+               I802_DEBUG_INC(tx->local->tx_handlers_queued);
+@@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee8021
+       res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
+       if (unlikely(res_prepare == TX_DROP)) {
+-              dev_kfree_skb(skb);
++              ieee80211_free_txskb(&local->hw, skb);
+               goto out;
+       } else if (unlikely(res_prepare == TX_QUEUED)) {
+               goto out;
+@@ -1465,7 +1465,7 @@ void ieee80211_xmit(struct ieee80211_sub
+       headroom = max_t(int, 0, headroom);
+       if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
+-              dev_kfree_skb(skb);
++              ieee80211_free_txskb(&local->hw, skb);
+               rcu_read_unlock();
                return;
-       case NL80211_IFTYPE_MONITOR:
-       case NL80211_IFTYPE_AP_VLAN:
+       }
+@@ -2056,8 +2056,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
+               head_need += IEEE80211_ENCRYPT_HEADROOM;
+               head_need += local->tx_headroom;
+               head_need = max_t(int, 0, head_need);
+-              if (ieee80211_skb_resize(sdata, skb, head_need, true))
+-                      goto fail;
++              if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
++                      ieee80211_free_txskb(&local->hw, skb);
++                      return NETDEV_TX_OK;
++              }
+       }
+       if (encaps_data) {
+@@ -2124,10 +2126,13 @@ netdev_tx_t ieee80211_subif_start_xmit(s
+  */
+ void ieee80211_clear_tx_pending(struct ieee80211_local *local)
+ {
++      struct sk_buff *skb;
+       int i;
+-      for (i = 0; i < local->hw.queues; i++)
+-              skb_queue_purge(&local->pending[i]);
++      for (i = 0; i < local->hw.queues; i++) {
++              while ((skb = skb_dequeue(&local->pending[i])) != NULL)
++                      ieee80211_free_txskb(&local->hw, skb);
++      }
+ }
+ /*
+@@ -2190,7 +2195,7 @@ void ieee80211_tx_pending(unsigned long 
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                       if (WARN_ON(!info->control.vif)) {
+-                              kfree_skb(skb);
++                              ieee80211_free_txskb(&local->hw, skb);
+                               continue;
+                       }