lantiq: w303v has its rt2860 eep on the nor flash. tell compat-wireless how to use it
[openwrt.git] / package / mac80211 / patches / 300-pending_work.patch
index 782f7d7877fd99cb1b54987879326609ac01a870..371e82bcaeae36d334304055b6daf2319756b29d 100644 (file)
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -603,7 +603,6 @@ struct ath_hw_ops {
-                                    int power_off);
-       void (*rx_enable)(struct ath_hw *ah);
-       void (*set_desc_link)(void *ds, u32 link);
--      void (*get_desc_link)(void *ds, u32 **link);
-       bool (*calibrate)(struct ath_hw *ah,
-                         struct ath9k_channel *chan,
-                         u8 rxchainmask,
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -62,8 +62,6 @@ static bool ath9k_has_pending_frames(str
-       if (txq->axq_depth || !list_empty(&txq->axq_acq))
-               pending = true;
--      else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
--              pending = !list_empty(&txq->txq_fifo_pending);
-       spin_unlock_bh(&txq->axq_lock);
-       return pending;
---- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-@@ -28,11 +28,6 @@ static void ar9002_hw_set_desc_link(void
-       ((struct ath_desc*) ds)->ds_link = ds_link;
- }
--static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
--{
--      *ds_link = &((struct ath_desc *)ds)->ds_link;
--}
--
- static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
- {
-       u32 isr = 0;
-@@ -437,7 +432,6 @@ void ar9002_hw_attach_mac_ops(struct ath
-       ops->rx_enable = ar9002_hw_rx_enable;
-       ops->set_desc_link = ar9002_hw_set_desc_link;
--      ops->get_desc_link = ar9002_hw_get_desc_link;
-       ops->get_isr = ar9002_hw_get_isr;
-       ops->fill_txdesc = ar9002_hw_fill_txdesc;
-       ops->proc_txdesc = ar9002_hw_proc_txdesc;
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -43,13 +43,6 @@ static void ar9003_hw_set_desc_link(void
-       ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
- }
--static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
--{
--      struct ar9003_txc *ads = ds;
--
--      *ds_link = &ads->link;
--}
--
- static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
- {
-       u32 isr = 0;
-@@ -498,7 +491,6 @@ void ar9003_hw_attach_mac_ops(struct ath
-       ops->rx_enable = ar9003_hw_rx_enable;
-       ops->set_desc_link = ar9003_hw_set_desc_link;
--      ops->get_desc_link = ar9003_hw_get_desc_link;
-       ops->get_isr = ar9003_hw_get_isr;
-       ops->fill_txdesc = ar9003_hw_fill_txdesc;
-       ops->proc_txdesc = ar9003_hw_proc_txdesc;
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -179,7 +179,7 @@ enum ATH_AGGR_STATUS {
- struct ath_txq {
-       int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
-       u32 axq_qnum; /* ath9k hardware queue number */
--      u32 *axq_link;
-+      void *axq_link;
-       struct list_head axq_q;
-       spinlock_t axq_lock;
-       u32 axq_depth;
-@@ -188,7 +188,6 @@ struct ath_txq {
-       bool axq_tx_inprogress;
-       struct list_head axq_acq;
-       struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
--      struct list_head txq_fifo_pending;
-       u8 txq_headidx;
-       u8 txq_tailidx;
-       int pending_frames;
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -550,6 +550,7 @@ static ssize_t read_file_xmit(struct fil
-       PR("MPDUs Queued:    ", queued);
-       PR("MPDUs Completed: ", completed);
-+      PR("MPDUs XRetried:  ", xretries);
-       PR("Aggregates:      ", a_aggr);
-       PR("AMPDUs Queued HW:", a_queued_hw);
-       PR("AMPDUs Queued SW:", a_queued_sw);
-@@ -587,7 +588,6 @@ static ssize_t read_file_xmit(struct fil
-       PRQLE("axq_q empty:       ", axq_q);
-       PRQLE("axq_acq empty:     ", axq_acq);
--      PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
-       for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
-               snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
-               PRQLE(tmp, txq_fifo[i]);
-@@ -807,7 +807,10 @@ void ath_debug_stat_tx(struct ath_softc 
-               else
-                       TX_STAT_INC(qnum, a_completed);
-       } else {
--              TX_STAT_INC(qnum, completed);
-+              if (bf_isxretried(bf))
-+                      TX_STAT_INC(qnum, xretries);
-+              else
-+                      TX_STAT_INC(qnum, completed);
-       }
-       if (ts->ts_status & ATH9K_TXERR_FIFO)
---- a/drivers/net/wireless/ath/ath9k/hw-ops.h
-+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
-@@ -39,11 +39,6 @@ static inline void ath9k_hw_set_desc_lin
-       ath9k_hw_ops(ah)->set_desc_link(ds, link);
- }
--static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
--                                        u32 **link)
--{
--      ath9k_hw_ops(ah)->get_desc_link(ds, link);
--}
- static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
-                                     struct ath9k_channel *chan,
-                                     u8 rxchainmask,
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct a
-                               struct ath_txq *txq, struct list_head *bf_q,
-                               struct ath_tx_status *ts, int txok, int sendbar);
- static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
--                           struct list_head *head);
-+                           struct list_head *head, bool internal);
- static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
- static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
-                            struct ath_tx_status *ts, int nframes, int nbad,
-@@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct 
-                       bf_next = bf->bf_next;
-                       bf->bf_state.bf_type |= BUF_XRETRY;
--                      if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
--                          !bf->bf_stale || bf_next != NULL)
-+                      if (!bf->bf_stale || bf_next != NULL)
-                               list_move_tail(&bf->list, &bf_head);
-                       ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
-@@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct 
-                       }
-               }
--              if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
--                  bf_next == NULL) {
--                      /*
--                       * Make sure the last desc is reclaimed if it
--                       * not a holding desc.
--                       */
--                      if (!bf_last->bf_stale)
--                              list_move_tail(&bf->list, &bf_head);
--                      else
--                              INIT_LIST_HEAD(&bf_head);
--              } else {
--                      BUG_ON(list_empty(bf_q));
-+              /*
-+               * Make sure the last desc is reclaimed if it
-+               * not a holding desc.
-+               */
-+              if (!bf_last->bf_stale || bf_next != NULL)
-                       list_move_tail(&bf->list, &bf_head);
--              }
-+              else
-+                      INIT_LIST_HEAD(&bf_head);
-               if (!txpending || (tid->state & AGGR_CLEANUP)) {
-                       /*
-@@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath
-                       bf->bf_state.bf_type &= ~BUF_AGGR;
-                       ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
-                       ath_buf_set_rate(sc, bf, fi->framelen);
--                      ath_tx_txqaddbuf(sc, txq, &bf_q);
-+                      ath_tx_txqaddbuf(sc, txq, &bf_q, false);
-                       continue;
-               }
-@@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath
-               /* anchor last desc of aggregate */
-               ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
--              ath_tx_txqaddbuf(sc, txq, &bf_q);
-+              ath_tx_txqaddbuf(sc, txq, &bf_q, false);
-               TX_STAT_INC(txq->axq_qnum, a_aggr);
-       } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
-@@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath
-               txq->txq_headidx = txq->txq_tailidx = 0;
-               for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
-                       INIT_LIST_HEAD(&txq->txq_fifo[i]);
--              INIT_LIST_HEAD(&txq->txq_fifo_pending);
-       }
-       return &sc->tx.txq[axq_qnum];
- }
-@@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(stru
-     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
- }
--/*
-- * Drain a given TX queue (could be Beacon or Data)
-- *
-- * This assumes output has been stopped and
-- * we do not need to block ath_tx_tasklet.
-- */
--void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
-+static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
-+                             struct list_head *list, bool retry_tx)
- {
-       struct ath_buf *bf, *lastbf;
-       struct list_head bf_head;
-@@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, 
-       memset(&ts, 0, sizeof(ts));
-       INIT_LIST_HEAD(&bf_head);
--      for (;;) {
--              spin_lock_bh(&txq->axq_lock);
-+      while (!list_empty(list)) {
-+              bf = list_first_entry(list, struct ath_buf, list);
--              if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--                      if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
--                              txq->txq_headidx = txq->txq_tailidx = 0;
--                              spin_unlock_bh(&txq->axq_lock);
--                              break;
--                      } else {
--                              bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
--                                                    struct ath_buf, list);
--                      }
--              } else {
--                      if (list_empty(&txq->axq_q)) {
--                              txq->axq_link = NULL;
--                              spin_unlock_bh(&txq->axq_lock);
--                              break;
--                      }
--                      bf = list_first_entry(&txq->axq_q, struct ath_buf,
--                                            list);
--
--                      if (bf->bf_stale) {
--                              list_del(&bf->list);
--                              spin_unlock_bh(&txq->axq_lock);
-+              if (bf->bf_stale) {
-+                      list_del(&bf->list);
--                              ath_tx_return_buffer(sc, bf);
--                              continue;
--                      }
-+                      ath_tx_return_buffer(sc, bf);
-+                      continue;
-               }
-               lastbf = bf->bf_lastbf;
--
--              if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--                      list_cut_position(&bf_head,
--                                        &txq->txq_fifo[txq->txq_tailidx],
--                                        &lastbf->list);
--                      INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
--              } else {
--                      /* remove ath_buf's of the same mpdu from txq */
--                      list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
--              }
-+              list_cut_position(&bf_head, list, &lastbf->list);
-               txq->axq_depth--;
-               if (bf_is_ampdu_not_probing(bf))
-                       txq->axq_ampdu_depth--;
--              spin_unlock_bh(&txq->axq_lock);
-+              spin_unlock_bh(&txq->axq_lock);
-               if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
-                                            retry_tx);
-               else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
-+              spin_lock_bh(&txq->axq_lock);
-       }
-+}
-+/*
-+ * Drain a given TX queue (could be Beacon or Data)
-+ *
-+ * This assumes output has been stopped and
-+ * we do not need to block ath_tx_tasklet.
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1122,6 +1122,7 @@ struct cfg80211_ibss_params {
+       u8 *ssid;
+       u8 *bssid;
+       struct ieee80211_channel *channel;
++      enum nl80211_channel_type channel_type;
+       u8 *ie;
+       u8 ssid_len, ie_len;
+       u16 beacon_interval;
+@@ -3188,6 +3189,16 @@ void cfg80211_gtk_rekey_notify(struct ne
+ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+                                    const u8 *bssid, bool preauth, gfp_t gfp);
++/**
++ * cfg80211_can_use_ext_chan - test if ht40 on extension channel can be used
++ * @wiphy: the wiphy
++ * @chan: main channel
++ * @channel_type: HT mode
 + */
-+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
-+{
-       spin_lock_bh(&txq->axq_lock);
--      txq->axq_tx_inprogress = false;
--      spin_unlock_bh(&txq->axq_lock);
--
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--              spin_lock_bh(&txq->axq_lock);
--              while (!list_empty(&txq->txq_fifo_pending)) {
--                      bf = list_first_entry(&txq->txq_fifo_pending,
--                                            struct ath_buf, list);
--                      list_cut_position(&bf_head,
--                                        &txq->txq_fifo_pending,
--                                        &bf->bf_lastbf->list);
--                      spin_unlock_bh(&txq->axq_lock);
-+              int idx = txq->txq_tailidx;
--                      if (bf_isampdu(bf))
--                              ath_tx_complete_aggr(sc, txq, bf, &bf_head,
--                                                   &ts, 0, retry_tx);
--                      else
--                              ath_tx_complete_buf(sc, bf, txq, &bf_head,
--                                                  &ts, 0, 0);
--                      spin_lock_bh(&txq->axq_lock);
-+              while (!list_empty(&txq->txq_fifo[idx])) {
-+                      ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
-+                                         retry_tx);
-+
-+                      INCR(idx, ATH_TXFIFO_DEPTH);
-               }
--              spin_unlock_bh(&txq->axq_lock);
-+              txq->txq_tailidx = idx;
-       }
-+      txq->axq_link = NULL;
-+      txq->axq_tx_inprogress = false;
-+      ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
-+
-       /* flush any pending frames if aggregation is enabled */
--      if (sc->sc_flags & SC_OP_TXAGGR) {
--              if (!retry_tx) {
--                      spin_lock_bh(&txq->axq_lock);
--                      ath_txq_drain_pending_buffers(sc, txq);
--                      spin_unlock_bh(&txq->axq_lock);
--              }
--      }
-+      if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
-+              ath_txq_drain_pending_buffers(sc, txq);
-+
-+      spin_unlock_bh(&txq->axq_lock);
- }
- bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
-@@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *
-  * assume the descriptors are already chained together by caller.
-  */
- static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
--                           struct list_head *head)
-+                           struct list_head *head, bool internal)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
--      struct ath_buf *bf;
-+      struct ath_buf *bf, *bf_last;
-+      bool puttxbuf = false;
-+      bool edma;
-       /*
-        * Insert the frame on the outbound list and
-@@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_
-       if (list_empty(head))
-               return;
-+      edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
-       bf = list_first_entry(head, struct ath_buf, list);
-+      bf_last = list_entry(head->prev, struct ath_buf, list);
-       ath_dbg(common, ATH_DBG_QUEUE,
-               "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
--      if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--              if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
--                      list_splice_tail_init(head, &txq->txq_fifo_pending);
--                      return;
--              }
--              if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
--                      ath_dbg(common, ATH_DBG_XMIT,
--                              "Initializing tx fifo %d which is non-empty\n",
--                              txq->txq_headidx);
--              INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
--              list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
-+      if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
-+              list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
-               INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
--              TX_STAT_INC(txq->axq_qnum, puttxbuf);
--              ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
--              ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
--                      txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
-+              puttxbuf = true;
-       } else {
-               list_splice_tail_init(head, &txq->axq_q);
--              if (txq->axq_link == NULL) {
--                      TX_STAT_INC(txq->axq_qnum, puttxbuf);
--                      ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
--                      ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
--                              txq->axq_qnum, ito64(bf->bf_daddr),
--                              bf->bf_desc);
--              } else {
--                      *txq->axq_link = bf->bf_daddr;
-+              if (txq->axq_link) {
-+                      ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "link[%u] (%p)=%llx (%p)\n",
-                               txq->axq_qnum, txq->axq_link,
-                               ito64(bf->bf_daddr), bf->bf_desc);
--              }
--              ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
--                                     &txq->axq_link);
-+              } else if (!edma)
-+                      puttxbuf = true;
-+
-+              txq->axq_link = bf_last->bf_desc;
-+      }
-+
-+      if (puttxbuf) {
-+              TX_STAT_INC(txq->axq_qnum, puttxbuf);
-+              ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-+              ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
-+                      txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
-+      }
-+
-+      if (!edma) {
-               TX_STAT_INC(txq->axq_qnum, txstart);
-               ath9k_hw_txstart(ah, txq->axq_qnum);
-       }
--      txq->axq_depth++;
--      if (bf_is_ampdu_not_probing(bf))
--              txq->axq_ampdu_depth++;
-+
-+      if (!internal) {
-+              txq->axq_depth++;
-+              if (bf_is_ampdu_not_probing(bf))
-+                      txq->axq_ampdu_depth++;
-+      }
- }
- static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
-@@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath
-       TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
-       bf->bf_lastbf = bf;
-       ath_buf_set_rate(sc, bf, fi->framelen);
--      ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
-+      ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
- }
- static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
-@@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct at
-       bf->bf_lastbf = bf;
-       fi = get_frame_info(bf->bf_mpdu);
-       ath_buf_set_rate(sc, bf, fi->framelen);
--      ath_tx_txqaddbuf(sc, txq, bf_head);
-+      ath_tx_txqaddbuf(sc, txq, bf_head, false);
-       TX_STAT_INC(txq->axq_qnum, queued);
- }
-@@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_
-       tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
- }
-+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
-+                                struct ath_tx_status *ts, struct ath_buf *bf,
-+                                struct list_head *bf_head)
-+{
-+      int txok;
-+
-+      txq->axq_depth--;
-+      txok = !(ts->ts_status & ATH9K_TXERR_MASK);
-+      txq->axq_tx_inprogress = false;
-+      if (bf_is_ampdu_not_probing(bf))
-+              txq->axq_ampdu_depth--;
-+
-+      spin_unlock_bh(&txq->axq_lock);
-+
-+      if (!bf_isampdu(bf)) {
-+              /*
-+               * This frame is sent out as a single frame.
-+               * Use hardware retry status for this frame.
-+               */
-+              if (ts->ts_status & ATH9K_TXERR_XRETRY)
-+                      bf->bf_state.bf_type |= BUF_XRETRY;
-+              ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
-+              ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
-+      } else
-+              ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
-+
-+      spin_lock_bh(&txq->axq_lock);
-+
-+      if (sc->sc_flags & SC_OP_TXAGGR)
-+              ath_txq_schedule(sc, txq);
-+}
-+
- static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
- {
-       struct ath_hw *ah = sc->sc_ah;
-@@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_s
-       struct list_head bf_head;
-       struct ath_desc *ds;
-       struct ath_tx_status ts;
--      int txok;
-       int status;
-       ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
-               txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
-               txq->axq_link);
-+      spin_lock_bh(&txq->axq_lock);
-       for (;;) {
--              spin_lock_bh(&txq->axq_lock);
-               if (list_empty(&txq->axq_q)) {
-                       txq->axq_link = NULL;
-                       if (sc->sc_flags & SC_OP_TXAGGR)
-                               ath_txq_schedule(sc, txq);
--                      spin_unlock_bh(&txq->axq_lock);
-                       break;
-               }
-               bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_s
-               bf_held = NULL;
-               if (bf->bf_stale) {
-                       bf_held = bf;
--                      if (list_is_last(&bf_held->list, &txq->axq_q)) {
--                              spin_unlock_bh(&txq->axq_lock);
-+                      if (list_is_last(&bf_held->list, &txq->axq_q))
-                               break;
--                      } else {
--                              bf = list_entry(bf_held->list.next,
--                                              struct ath_buf, list);
--                      }
-+
-+                      bf = list_entry(bf_held->list.next, struct ath_buf,
-+                                      list);
-               }
-               lastbf = bf->bf_lastbf;
-@@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_s
-               memset(&ts, 0, sizeof(ts));
-               status = ath9k_hw_txprocdesc(ah, ds, &ts);
--              if (status == -EINPROGRESS) {
--                      spin_unlock_bh(&txq->axq_lock);
-+              if (status == -EINPROGRESS)
-                       break;
--              }
++bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
++                                struct ieee80211_channel *chan,
++                                enum nl80211_channel_type channel_type);
 +
-               TX_STAT_INC(txq->axq_qnum, txprocdesc);
-               /*
-@@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_s
-                       list_cut_position(&bf_head,
-                               &txq->axq_q, lastbf->list.prev);
--              txq->axq_depth--;
--              txok = !(ts.ts_status & ATH9K_TXERR_MASK);
--              txq->axq_tx_inprogress = false;
--              if (bf_held)
-+              if (bf_held) {
-                       list_del(&bf_held->list);
--
--              if (bf_is_ampdu_not_probing(bf))
--                      txq->axq_ampdu_depth--;
--
--              spin_unlock_bh(&txq->axq_lock);
--
--              if (bf_held)
-                       ath_tx_return_buffer(sc, bf_held);
--
--              if (!bf_isampdu(bf)) {
--                      /*
--                       * This frame is sent out as a single frame.
--                       * Use hardware retry status for this frame.
--                       */
--                      if (ts.ts_status & ATH9K_TXERR_XRETRY)
--                              bf->bf_state.bf_type |= BUF_XRETRY;
--                      ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
-               }
--              if (bf_isampdu(bf))
--                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
--                                           true);
--              else
--                      ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
--
--              spin_lock_bh(&txq->axq_lock);
--
--              if (sc->sc_flags & SC_OP_TXAGGR)
--                      ath_txq_schedule(sc, txq);
--              spin_unlock_bh(&txq->axq_lock);
-+              ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
-       }
-+      spin_unlock_bh(&txq->axq_lock);
- }
- static void ath_tx_complete_poll_work(struct work_struct *work)
-@@ -2237,17 +2193,16 @@ void ath_tx_tasklet(struct ath_softc *sc
- void ath_tx_edma_tasklet(struct ath_softc *sc)
- {
--      struct ath_tx_status txs;
-+      struct ath_tx_status ts;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_txq *txq;
-       struct ath_buf *bf, *lastbf;
-       struct list_head bf_head;
-       int status;
--      int txok;
-       for (;;) {
--              status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
-+              status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
-               if (status == -EINPROGRESS)
-                       break;
-               if (status == -EIO) {
-@@ -2257,12 +2212,13 @@ void ath_tx_edma_tasklet(struct ath_soft
-               }
-               /* Skip beacon completions */
--              if (txs.qid == sc->beacon.beaconq)
-+              if (ts.qid == sc->beacon.beaconq)
-                       continue;
--              txq = &sc->tx.txq[txs.qid];
-+              txq = &sc->tx.txq[ts.qid];
-               spin_lock_bh(&txq->axq_lock);
-+
-               if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
-                       spin_unlock_bh(&txq->axq_lock);
-                       return;
-@@ -2275,41 +2231,21 @@ void ath_tx_edma_tasklet(struct ath_soft
-               INIT_LIST_HEAD(&bf_head);
-               list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
-                                 &lastbf->list);
--              INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
--              txq->axq_depth--;
--              txq->axq_tx_inprogress = false;
--              if (bf_is_ampdu_not_probing(bf))
--                      txq->axq_ampdu_depth--;
--              spin_unlock_bh(&txq->axq_lock);
--              txok = !(txs.ts_status & ATH9K_TXERR_MASK);
--
--              if (!bf_isampdu(bf)) {
--                      if (txs.ts_status & ATH9K_TXERR_XRETRY)
--                              bf->bf_state.bf_type |= BUF_XRETRY;
--                      ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
--              }
--
--              if (bf_isampdu(bf))
--                      ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
--                                           txok, true);
--              else
--                      ath_tx_complete_buf(sc, bf, txq, &bf_head,
--                                          &txs, txok, 0);
-+              if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
-+                      INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
--              spin_lock_bh(&txq->axq_lock);
-+                      if (!list_empty(&txq->axq_q)) {
-+                              struct list_head bf_q;
--              if (!list_empty(&txq->txq_fifo_pending)) {
--                      INIT_LIST_HEAD(&bf_head);
--                      bf = list_first_entry(&txq->txq_fifo_pending,
--                                            struct ath_buf, list);
--                      list_cut_position(&bf_head,
--                                        &txq->txq_fifo_pending,
--                                        &bf->bf_lastbf->list);
--                      ath_tx_txqaddbuf(sc, txq, &bf_head);
--              } else if (sc->sc_flags & SC_OP_TXAGGR)
--                      ath_txq_schedule(sc, txq);
-+                              INIT_LIST_HEAD(&bf_q);
-+                              txq->axq_link = NULL;
-+                              list_splice_tail_init(&txq->axq_q, &bf_q);
-+                              ath_tx_txqaddbuf(sc, txq, &bf_q, true);
-+                      }
-+              }
+ /* Logging, debugging and troubleshooting/diagnostic helpers. */
  
-+              ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
-               spin_unlock_bh(&txq->axq_lock);
-       }
- }
+ /* wiphy_printk helpers, similar to dev_printk */
 --- a/net/mac80211/agg-rx.c
 +++ b/net/mac80211/agg-rx.c
-@@ -161,6 +161,8 @@ static void ieee80211_send_addba_resp(st
+@@ -180,6 +180,10 @@ 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);
 +      else if (sdata->vif.type == NL80211_IFTYPE_WDS)
 +              memcpy(mgmt->bssid, da, ETH_ALEN);
++      else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++              memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
  
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 --- a/net/mac80211/agg-tx.c
 +++ b/net/mac80211/agg-tx.c
-@@ -79,7 +79,8 @@ static void ieee80211_send_addba_request
+@@ -77,10 +77,13 @@ static void ieee80211_send_addba_request
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
                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);
-@@ -388,7 +389,8 @@ int ieee80211_start_tx_ba_session(struct
++      else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++              memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+@@ -397,7 +400,9 @@ int ieee80211_start_tx_ba_session(struct
         */
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 -          sdata->vif.type != NL80211_IFTYPE_AP)
 +          sdata->vif.type != NL80211_IFTYPE_AP &&
++          sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 +          sdata->vif.type != NL80211_IFTYPE_WDS)
                return -EINVAL;
  
-       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+       if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
 --- a/net/mac80211/debugfs_sta.c
 +++ b/net/mac80211/debugfs_sta.c
-@@ -59,7 +59,7 @@ static ssize_t sta_flags_read(struct fil
-       char buf[100];
-       struct sta_info *sta = file->private_data;
-       u32 staflags = get_sta_flags(sta);
--      int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
-+      int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
-               staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
-               staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
-               staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
-@@ -67,7 +67,6 @@ static ssize_t sta_flags_read(struct fil
-               staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
-               staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
-               staflags & WLAN_STA_WME ? "WME\n" : "",
--              staflags & WLAN_STA_WDS ? "WDS\n" : "",
-               staflags & WLAN_STA_MFP ? "MFP\n" : "");
-       return simple_read_from_buffer(userbuf, count, ppos, buf, res);
- }
+@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
+       test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
+       int res = scnprintf(buf, sizeof(buf),
+-                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
++                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                           TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
+                           TEST(PS_DRIVER), TEST(AUTHORIZED),
+                           TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
+-                          TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
++                          TEST(WME), TEST(CLEAR_PS_FILT),
+                           TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
+                           TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
+                           TEST(TDLS_PEER_AUTH));
+--- a/net/mac80211/ht.c
++++ b/net/mac80211/ht.c
+@@ -199,6 +199,8 @@ void ieee80211_send_delba(struct ieee802
+               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);
++      else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++              memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(st
+       struct cfg80211_bss *bss;
+       u32 bss_change;
+       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
++      enum nl80211_channel_type channel_type;
+       lockdep_assert_held(&ifibss->mtx);
+@@ -104,8 +105,16 @@ static void __ieee80211_sta_join_ibss(st
+       sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+-      local->oper_channel = chan;
+-      WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
++      channel_type = ifibss->channel_type;
++      if (channel_type > NL80211_CHAN_HT20 &&
++          !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
++              channel_type = NL80211_CHAN_HT20;
++      if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
++              /* can only fail due to HT40+/- mismatch */
++              channel_type = NL80211_CHAN_HT20;
++              WARN_ON(!ieee80211_set_channel_type(local, sdata,
++                                                  NL80211_CHAN_HT20));
++      }
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       sband = local->hw.wiphy->bands[chan->band];
+@@ -171,6 +180,18 @@ static void __ieee80211_sta_join_ibss(st
+               memcpy(skb_put(skb, ifibss->ie_len),
+                      ifibss->ie, ifibss->ie_len);
++      /* add HT capability and information IEs */
++      if (channel_type && sband->ht_cap.ht_supported) {
++              pos = skb_put(skb, 4 +
++                                 sizeof(struct ieee80211_ht_cap) +
++                                 sizeof(struct ieee80211_ht_info));
++              pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
++              pos = ieee80211_ie_build_ht_info(pos,
++                                               &sband->ht_cap,
++                                               chan,
++                                               channel_type);
++      }
++
+       if (local->hw.queues >= 4) {
+               pos = skb_put(skb, 9);
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+@@ -194,6 +215,7 @@ static void __ieee80211_sta_join_ibss(st
+       bss_change |= BSS_CHANGED_BEACON;
+       bss_change |= BSS_CHANGED_BEACON_ENABLED;
+       bss_change |= BSS_CHANGED_BASIC_RATES;
++      bss_change |= BSS_CHANGED_HT;
+       bss_change |= BSS_CHANGED_IBSS;
+       sdata->vif.bss_conf.ibss_joined = true;
+       ieee80211_bss_info_change_notify(sdata, bss_change);
+@@ -266,6 +288,7 @@ static void ieee80211_rx_bss_info(struct
+       u64 beacon_timestamp, rx_timestamp;
+       u32 supp_rates = 0;
+       enum ieee80211_band band = rx_status->band;
++      struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+       if (elems->ds_params && elems->ds_params_len == 1)
+               freq = ieee80211_channel_to_frequency(elems->ds_params[0],
+@@ -275,7 +298,10 @@ static void ieee80211_rx_bss_info(struct
+       channel = ieee80211_get_channel(local->hw.wiphy, freq);
+-      if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
++      if (!channel ||
++          channel->flags & (IEEE80211_CHAN_DISABLED ||
++                            IEEE80211_CHAN_NO_IBSS ||
++                            IEEE80211_CHAN_RADAR))
+               return;
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+@@ -313,8 +339,41 @@ static void ieee80211_rx_bss_info(struct
+                                               GFP_ATOMIC);
+               }
+-              if (sta && elems->wmm_info)
+-                      set_sta_flag(sta, WLAN_STA_WME);
++              if (sta) {
++                      if (elems->wmm_info)
++                              set_sta_flag(sta, WLAN_STA_WME);
++
++                      /* we both use HT */
++                      if (elems->ht_info_elem && elems->ht_cap_elem &&
++                          sdata->u.ibss.channel_type) {
++                              enum nl80211_channel_type channel_type =
++                                      ieee80211_ht_info_to_channel_type(
++                                                         elems->ht_info_elem);
++                              struct ieee80211_sta_ht_cap sta_ht_cap_new;
++
++                              /*
++                               * fall back to HT20 if we don't use or use
++                               * the other extension channel
++                               */
++                              if (channel_type > NL80211_CHAN_HT20 &&
++                                  channel_type != sdata->u.ibss.channel_type)
++                                      channel_type = NL80211_CHAN_HT20;
++
++                              ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
++                                              elems->ht_cap_elem,
++                                              &sta_ht_cap_new);
++                              if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
++                                         sizeof(sta_ht_cap_new))) {
++                                      memcpy(&sta->sta.ht_cap,
++                                             &sta_ht_cap_new,
++                                             sizeof(sta_ht_cap_new));
++                                      rate_control_rate_update(local, sband,
++                                                      sta,
++                                                      IEEE80211_RC_HT_CHANGED,
++                                                      channel_type);
++                              }
++                      }
++              }
+               rcu_read_unlock();
+       }
+@@ -896,10 +955,15 @@ int ieee80211_ibss_join(struct ieee80211
+       struct sk_buff *skb;
+       skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
+-                          36 /* bitrates */ +
+-                          34 /* SSID */ +
+-                          3  /* DS params */ +
+-                          4  /* IBSS params */ +
++                          sizeof(struct ieee80211_hdr_3addr) +
++                          12 /* struct ieee80211_mgmt.u.beacon */ +
++                          2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
++                          2 + 8 /* max Supported Rates */ +
++                          3 /* max DS params */ +
++                          4 /* IBSS params */ +
++                          2 + (IEEE80211_MAX_SUPP_RATES - 8) +
++                          2 + sizeof(struct ieee80211_ht_cap) +
++                          2 + sizeof(struct ieee80211_ht_info) +
+                           params->ie_len);
+       if (!skb)
+               return -ENOMEM;
+@@ -920,13 +984,15 @@ int ieee80211_ibss_join(struct ieee80211
+       sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+       sdata->u.ibss.channel = params->channel;
++      sdata->u.ibss.channel_type = params->channel_type;
+       sdata->u.ibss.fixed_channel = params->channel_fixed;
+       /* fix ourselves to that channel now already */
+       if (params->channel_fixed) {
+               sdata->local->oper_channel = params->channel;
+-              WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
+-                                                  NL80211_CHAN_NO_HT));
++              if (!ieee80211_set_channel_type(sdata->local, sdata,
++                                             params->channel_type))
++                      return -EINVAL;
+       }
+       if (params->ie) {
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -465,6 +465,7 @@ struct ieee80211_if_ibss {
+       u8 ssid_len, ie_len;
+       u8 *ie;
+       struct ieee80211_channel *channel;
++      enum nl80211_channel_type channel_type;
+       unsigned long ibss_join_req;
+       /* probe response/beacon for IBSS */
+@@ -1339,6 +1340,12 @@ void ieee80211_recalc_smps(struct ieee80
+ size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+                         const u8 *ids, int n_ids, size_t offset);
+ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
++u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
++                            u16 cap);
++u8 *ieee80211_ie_build_ht_info(u8 *pos,
++                              struct ieee80211_sta_ht_cap *ht_cap,
++                              struct ieee80211_channel *channel,
++                              enum nl80211_channel_type channel_type);
+ /* internal work items */
+ void ieee80211_work_init(struct ieee80211_local *local);
+@@ -1367,6 +1374,8 @@ ieee80211_get_channel_mode(struct ieee80
+ bool ieee80211_set_channel_type(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata,
+                               enum nl80211_channel_type chantype);
++enum nl80211_channel_type
++ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
+ #ifdef CONFIG_MAC80211_NOINLINE
+ #define debug_noinline noinline
 --- a/net/mac80211/iface.c
 +++ b/net/mac80211/iface.c
 @@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
 -                      goto err_del_interface;
 -              }
 -
--              /* no locking required since STA is not live yet */
--              sta->flags |= WLAN_STA_AUTHORIZED;
+-              /* no atomic bitop required since STA is not live yet */
+-              set_sta_flag(sta, WLAN_STA_AUTHORIZED);
 -
 -              res = sta_info_insert(sta);
 -              if (res) {
   err_stop:
        if (!local->open_count)
                drv_stop(local);
-@@ -718,6 +695,70 @@ static void ieee80211_if_setup(struct ne
+@@ -716,6 +693,70 @@ static void ieee80211_if_setup(struct ne
        dev->destructor = free_netdev;
  }
  
 +                              elems.ht_cap_elem, &sta->sta.ht_cap);
 +
 +      if (elems.wmm_param)
-+              set_sta_flags(sta, WLAN_STA_WME);
++              set_sta_flag(sta, WLAN_STA_WME);
 +
 +      if (new) {
-+              sta->flags = WLAN_STA_AUTHORIZED;
++              set_sta_flag(sta, WLAN_STA_AUTHORIZED);
 +              rate_control_rate_init(sta);
 +              sta_info_insert_rcu(sta);
 +      }
  static void ieee80211_iface_work(struct work_struct *work)
  {
        struct ieee80211_sub_if_data *sdata =
-@@ -822,6 +863,9 @@ static void ieee80211_iface_work(struct 
+@@ -820,6 +861,9 @@ static void ieee80211_iface_work(struct 
                                break;
                        ieee80211_mesh_rx_queued_mgmt(sdata, skb);
                        break;
                        break;
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -2137,7 +2137,8 @@ ieee80211_rx_h_action(struct ieee80211_r
+@@ -2211,7 +2211,9 @@ ieee80211_rx_h_action(struct ieee80211_r
                 */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 -                  sdata->vif.type != NL80211_IFTYPE_AP)
 +                  sdata->vif.type != NL80211_IFTYPE_AP &&
++                  sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 +                  sdata->vif.type != NL80211_IFTYPE_WDS)
                        break;
  
                /* verify action_code is present */
-@@ -2335,13 +2336,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+@@ -2426,13 +2428,14 @@ 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_DEAUTH):
        case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-@@ -2680,10 +2682,16 @@ static int prepare_for_handlers(struct i
+@@ -2775,10 +2778,16 @@ static int prepare_for_handlers(struct i
                }
                break;
        case NL80211_IFTYPE_WDS:
                /* should never get here */
 --- a/net/mac80211/sta_info.h
 +++ b/net/mac80211/sta_info.h
-@@ -31,7 +31,6 @@
+@@ -32,7 +32,6 @@
   *    frames.
   * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
   * @WLAN_STA_WME: Station is a QoS-STA.
   * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
   *    IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
   *    frame to this station is transmitted.
-@@ -54,7 +53,6 @@ enum ieee80211_sta_info_flags {
-       WLAN_STA_SHORT_PREAMBLE = 1<<4,
-       WLAN_STA_ASSOC_AP       = 1<<5,
-       WLAN_STA_WME            = 1<<6,
--      WLAN_STA_WDS            = 1<<7,
-       WLAN_STA_CLEAR_PS_FILT  = 1<<9,
-       WLAN_STA_MFP            = 1<<10,
-       WLAN_STA_BLOCK_BA       = 1<<11,
---- a/drivers/net/wireless/ath/ath9k/debug.h
-+++ b/drivers/net/wireless/ath/ath9k/debug.h
-@@ -116,6 +116,7 @@ struct ath_tx_stats {
-       u32 tx_bytes_all;
-       u32 queued;
-       u32 completed;
-+      u32 xretries;
-       u32 a_aggr;
-       u32 a_queued_hw;
-       u32 a_queued_sw;
---- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-@@ -4645,10 +4645,16 @@ static void ar9003_hw_set_power_per_rate
-       case 1:
-               break;
-       case 2:
--              scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
-+              if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
-+                      scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
-+              else
-+                      scaledPower = 0;
-               break;
-       case 3:
--              scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
-+              if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
-+                      scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
-+              else
-+                      scaledPower = 0;
-               break;
+@@ -61,7 +60,6 @@ enum ieee80211_sta_info_flags {
+       WLAN_STA_SHORT_PREAMBLE,
+       WLAN_STA_ASSOC_AP,
+       WLAN_STA_WME,
+-      WLAN_STA_WDS,
+       WLAN_STA_CLEAR_PS_FILT,
+       WLAN_STA_MFP,
+       WLAN_STA_BLOCK_BA,
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -836,23 +836,8 @@ int ieee80211_build_preq_ies(struct ieee
+               offset = noffset;
        }
  
---- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
-+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
-@@ -524,10 +524,16 @@ static void ath9k_hw_set_ar9287_power_pe
-       case 1:
-               break;
-       case 2:
--              scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
-+              if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
-+                      scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
-+              else
-+                      scaledPower = 0;
-               break;
-       case 3:
--              scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
-+              if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
-+                      scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
-+              else
-+                      scaledPower = 0;
-               break;
+-      if (sband->ht_cap.ht_supported) {
+-              u16 cap = sband->ht_cap.cap;
+-              __le16 tmp;
+-
+-              *pos++ = WLAN_EID_HT_CAPABILITY;
+-              *pos++ = sizeof(struct ieee80211_ht_cap);
+-              memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+-              tmp = cpu_to_le16(cap);
+-              memcpy(pos, &tmp, sizeof(u16));
+-              pos += sizeof(u16);
+-              *pos++ = sband->ht_cap.ampdu_factor |
+-                       (sband->ht_cap.ampdu_density <<
+-                              IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+-              memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+-              pos += sizeof(sband->ht_cap.mcs);
+-              pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
+-      }
++      if (sband->ht_cap.ht_supported)
++              pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+       /*
+        * If adding more here, adjust code in main.c
+@@ -1443,3 +1428,100 @@ int ieee80211_add_ext_srates_ie(struct i
+       }
+       return 0;
+ }
++
++u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
++                            u16 cap)
++{
++      __le16 tmp;
++
++      *pos++ = WLAN_EID_HT_CAPABILITY;
++      *pos++ = sizeof(struct ieee80211_ht_cap);
++      memset(pos, 0, sizeof(struct ieee80211_ht_cap));
++
++      /* capability flags */
++      tmp = cpu_to_le16(cap);
++      memcpy(pos, &tmp, sizeof(u16));
++      pos += sizeof(u16);
++
++      /* AMPDU parameters */
++      *pos++ = sband->ht_cap.ampdu_factor |
++               (sband->ht_cap.ampdu_density <<
++                      IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
++
++      /* MCS set */
++      memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
++      pos += sizeof(sband->ht_cap.mcs);
++
++      /* extended capabilities */
++      pos += sizeof(__le16);
++
++      /* BF capabilities */
++      pos += sizeof(__le32);
++
++      /* antenna selection */
++      pos += sizeof(u8);
++
++      return pos;
++}
++
++u8 *ieee80211_ie_build_ht_info(u8 *pos,
++                             struct ieee80211_sta_ht_cap *ht_cap,
++                             struct ieee80211_channel *channel,
++                             enum nl80211_channel_type channel_type)
++{
++      struct ieee80211_ht_info *ht_info;
++      /* Build HT Information */
++      *pos++ = WLAN_EID_HT_INFORMATION;
++      *pos++ = sizeof(struct ieee80211_ht_info);
++      ht_info = (struct ieee80211_ht_info *)pos;
++      ht_info->control_chan =
++                      ieee80211_frequency_to_channel(channel->center_freq);
++      switch (channel_type) {
++      case NL80211_CHAN_HT40MINUS:
++              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
++              break;
++      case NL80211_CHAN_HT40PLUS:
++              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
++              break;
++      case NL80211_CHAN_HT20:
++      default:
++              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
++              break;
++      }
++      if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
++              ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
++      ht_info->operation_mode = 0x0000;
++      ht_info->stbc_param = 0x0000;
++
++      /* It seems that Basic MCS set and Supported MCS set
++         are identical for the first 10 bytes */
++      memset(&ht_info->basic_set, 0, 16);
++      memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
++
++      return pos + sizeof(struct ieee80211_ht_info);
++}
++
++enum nl80211_channel_type
++ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
++{
++      enum nl80211_channel_type channel_type;
++
++      if (!ht_info)
++              return NL80211_CHAN_NO_HT;
++
++      switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
++      case IEEE80211_HT_PARAM_CHA_SEC_NONE:
++              channel_type = NL80211_CHAN_HT20;
++              break;
++      case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
++              channel_type = NL80211_CHAN_HT40PLUS;
++              break;
++      case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
++              channel_type = NL80211_CHAN_HT40MINUS;
++              break;
++      default:
++              channel_type = NL80211_CHAN_NO_HT;
++      }
++
++      return channel_type;
++}
+--- a/net/mac80211/work.c
++++ b/net/mac80211/work.c
+@@ -118,7 +118,6 @@ static void ieee80211_add_ht_ie(struct s
+       u8 *pos;
+       u32 flags = channel->flags;
+       u16 cap = sband->ht_cap.cap;
+-      __le16 tmp;
+       if (!sband->ht_cap.ht_supported)
+               return;
+@@ -169,34 +168,8 @@ static void ieee80211_add_ht_ie(struct s
+       }
+       /* reserve and fill IE */
+-
+       pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+-      *pos++ = WLAN_EID_HT_CAPABILITY;
+-      *pos++ = sizeof(struct ieee80211_ht_cap);
+-      memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+-
+-      /* capability flags */
+-      tmp = cpu_to_le16(cap);
+-      memcpy(pos, &tmp, sizeof(u16));
+-      pos += sizeof(u16);
+-
+-      /* AMPDU parameters */
+-      *pos++ = sband->ht_cap.ampdu_factor |
+-               (sband->ht_cap.ampdu_density <<
+-                      IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+-
+-      /* MCS set */
+-      memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+-      pos += sizeof(sband->ht_cap.mcs);
+-
+-      /* extended capabilities */
+-      pos += sizeof(__le16);
+-
+-      /* BF capabilities */
+-      pos += sizeof(__le32);
+-
+-      /* antenna selection */
+-      pos += sizeof(u8);
++      ieee80211_ie_build_ht_cap(pos, sband, cap);
+ }
+ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -44,9 +44,9 @@ rdev_freq_to_chan(struct cfg80211_regist
+       return chan;
+ }
+-static bool can_beacon_sec_chan(struct wiphy *wiphy,
+-                              struct ieee80211_channel *chan,
+-                              enum nl80211_channel_type channel_type)
++bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
++                                struct ieee80211_channel *chan,
++                                enum nl80211_channel_type channel_type)
+ {
+       struct ieee80211_channel *sec_chan;
+       int diff;
+@@ -75,6 +75,7 @@ static bool can_beacon_sec_chan(struct w
+       return true;
+ }
++EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
+ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
+                     struct wireless_dev *wdev, int freq,
+@@ -109,8 +110,8 @@ int cfg80211_set_freq(struct cfg80211_re
+               switch (channel_type) {
+               case NL80211_CHAN_HT40PLUS:
+               case NL80211_CHAN_HT40MINUS:
+-                      if (!can_beacon_sec_chan(&rdev->wiphy, chan,
+-                                               channel_type)) {
++                      if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
++                                                        channel_type)) {
+                               printk(KERN_DEBUG
+                                      "cfg80211: Secondary channel not "
+                                      "allowed to initiate communication\n");
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -4574,13 +4574,34 @@ static int nl80211_join_ibss(struct sk_b
+               ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
-       scaledPower = max((u16)0, scaledPower);
+-      ibss.channel = ieee80211_get_channel(wiphy,
+-              nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
++      if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
++              enum nl80211_channel_type channel_type;
++
++              channel_type = nla_get_u32(
++                              info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
++              if (channel_type > NL80211_CHAN_HT40PLUS)
++                      return -EINVAL;
++              ibss.channel_type = channel_type;
++      } else {
++              ibss.channel_type = NL80211_CHAN_NO_HT;
++      }
++
++      ibss.channel = rdev_freq_to_chan(rdev,
++              nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
++              ibss.channel_type);
+       if (!ibss.channel ||
++          ibss.channel->flags & IEEE80211_CHAN_RADAR ||
+           ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
+           ibss.channel->flags & IEEE80211_CHAN_DISABLED)
+               return -EINVAL;
++      /* Both channels should be able to initiate communication */
++      if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
++           ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
++          !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
++                                        ibss.channel_type))
++              return -EINVAL;
++
+       ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+       ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];