]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 11 May 2010 18:24:55 +0000 (14:24 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 11 May 2010 18:24:55 +0000 (14:24 -0400)
Conflicts:
drivers/net/wireless/ath/ar9170/main.c

30 files changed:
1  2 
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/wl12xx/wl1271_boot.c
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_main.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mlme.c
net/wireless/ibss.c
net/wireless/nl80211.c
net/wireless/sme.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c

index 2e9b330f64137c702a913e7ae8ca54a5f53c611c,b0654c873300578f39b0fd63feac9892e5c816f0..2abc8757899418ab6875576dc556b703324624be
@@@ -38,7 -38,6 +38,7 @@@
   */
  
  #include <linux/init.h>
 +#include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/etherdevice.h>
  #include <net/mac80211.h>
@@@ -50,10 -49,6 +50,6 @@@ static int modparam_nohwcrypt
  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
  
- static int modparam_ht;
- module_param_named(ht, modparam_ht, bool, S_IRUGO);
- MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
  #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {   \
        .bitrate        = (_bitrate),                   \
        .flags          = (_flags),                     \
@@@ -182,7 -177,6 +178,6 @@@ static struct ieee80211_supported_band 
  };
  
  static void ar9170_tx(struct ar9170 *ar);
- static bool ar9170_tx_ampdu(struct ar9170 *ar);
  
  static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
  {
@@@ -195,21 -189,7 +190,7 @@@ static inline u16 ar9170_get_seq(struc
        return ar9170_get_seq_h((void *) txc->frame_data);
  }
  
- static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
- {
-       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
- }
- static inline u16 ar9170_get_tid(struct sk_buff *skb)
- {
-       struct ar9170_tx_control *txc = (void *) skb->data;
-       return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
- }
- #define GET_NEXT_SEQ(seq)     ((seq + 1) & 0x0fff)
- #define GET_NEXT_SEQ_FROM_SKB(skb)    (GET_NEXT_SEQ(ar9170_get_seq(skb)))
- #if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
+ #ifdef AR9170_QUEUE_DEBUG
  static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
  {
        struct ar9170_tx_control *txc = (void *) skb->data;
@@@ -244,7 -224,7 +225,7 @@@ static void __ar9170_dump_txqueue(struc
                       "mismatch %d != %d\n", skb_queue_len(queue), i);
        printk(KERN_DEBUG "---[ end ]---\n");
  }
- #endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+ #endif /* AR9170_QUEUE_DEBUG */
  
  #ifdef AR9170_QUEUE_DEBUG
  static void ar9170_dump_txqueue(struct ar9170 *ar,
@@@ -275,20 -255,6 +256,6 @@@ static void __ar9170_dump_txstats(struc
  }
  #endif /* AR9170_QUEUE_STOP_DEBUG */
  
- #ifdef AR9170_TXAGG_DEBUG
- static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
- {
-       unsigned long flags;
-       spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
-       printk(KERN_DEBUG "%s: A-MPDU tx_status queue =>\n",
-              wiphy_name(ar->hw->wiphy));
-       __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
-       spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
- }
- #endif /* AR9170_TXAGG_DEBUG */
  /* caller must guarantee exclusive access for _bin_ queue. */
  static void ar9170_recycle_expired(struct ar9170 *ar,
                                   struct sk_buff_head *queue,
@@@ -360,70 -326,6 +327,6 @@@ static void ar9170_tx_status(struct ar9
        ieee80211_tx_status_irqsafe(ar->hw, skb);
  }
  
- static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
- {
-       struct sk_buff_head success;
-       struct sk_buff *skb;
-       unsigned int i;
-       unsigned long queue_bitmap = 0;
-       skb_queue_head_init(&success);
-       while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
-               __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
-       ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
- #ifdef AR9170_TXAGG_DEBUG
-       printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
-              wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
-       __ar9170_dump_txqueue(ar, &success);
- #endif /* AR9170_TXAGG_DEBUG */
-       while ((skb = __skb_dequeue(&success))) {
-               struct ieee80211_tx_info *txinfo;
-               queue_bitmap |= BIT(skb_get_queue_mapping(skb));
-               txinfo = IEEE80211_SKB_CB(skb);
-               ieee80211_tx_info_clear_status(txinfo);
-               txinfo->flags |= IEEE80211_TX_STAT_ACK;
-               txinfo->status.rates[0].count = 1;
-               skb_pull(skb, sizeof(struct ar9170_tx_control));
-               ieee80211_tx_status_irqsafe(ar->hw, skb);
-       }
-       for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) {
- #ifdef AR9170_QUEUE_STOP_DEBUG
-               printk(KERN_DEBUG "%s: wake queue %d\n",
-                      wiphy_name(ar->hw->wiphy), i);
-               __ar9170_dump_txstats(ar);
- #endif /* AR9170_QUEUE_STOP_DEBUG */
-               ieee80211_wake_queue(ar->hw, i);
-       }
-       if (queue_bitmap)
-               ar9170_tx(ar);
- }
- static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
- {
-       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-       struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
-       arinfo->timeout = jiffies +
-                         msecs_to_jiffies(AR9170_BA_TIMEOUT);
-       skb_queue_tail(&ar->tx_status_ampdu, skb);
-       ar9170_tx_fake_ampdu_status(ar);
-       if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
-           !list_empty(&ar->tx_ampdu_list))
-               ar9170_tx_ampdu(ar);
- }
  void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
  {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
                ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
        } else {
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       ar9170_tx_ampdu_callback(ar, skb);
-               } else {
-                       arinfo->timeout = jiffies +
-                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
+               arinfo->timeout = jiffies +
+                         msecs_to_jiffies(AR9170_TX_TIMEOUT);
  
-                       skb_queue_tail(&ar->tx_status[queue], skb);
-               }
+               skb_queue_tail(&ar->tx_status[queue], skb);
        }
  
        if (!ar->tx_stats[queue].len &&
@@@ -524,38 -422,6 +423,6 @@@ static struct sk_buff *ar9170_get_queue
        return NULL;
  }
  
- static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
- {
-       struct sk_buff *skb;
-       struct ieee80211_tx_info *txinfo;
-       while (count) {
-               skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
-               if (!skb)
-                       break;
-               txinfo = IEEE80211_SKB_CB(skb);
-               ieee80211_tx_info_clear_status(txinfo);
-               /* FIXME: maybe more ? */
-               txinfo->status.rates[0].count = 1;
-               skb_pull(skb, sizeof(struct ar9170_tx_control));
-               ieee80211_tx_status_irqsafe(ar->hw, skb);
-               count--;
-       }
- #ifdef AR9170_TXAGG_DEBUG
-       if (count) {
-               printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
-                      "suitable frames left in tx_status queue.\n",
-                      wiphy_name(ar->hw->wiphy), count);
-               ar9170_dump_tx_status_ampdu(ar);
-       }
- #endif /* AR9170_TXAGG_DEBUG */
- }
  /*
   * This worker tries to keeps an maintain tx_status queues.
   * So we can guarantee that incoming tx_status reports are
@@@ -592,8 -458,6 +459,6 @@@ static void ar9170_tx_janitor(struct wo
                        resched = true;
        }
  
-       ar9170_tx_fake_ampdu_status(ar);
        if (!resched)
                return;
  
@@@ -673,10 -537,6 +538,6 @@@ void ar9170_handle_command_response(str
  
        case 0xc5:
                /* BlockACK events */
-               ar9170_handle_block_ack(ar,
-                                       le16_to_cpu(cmd->ba_fail_cnt.failed),
-                                       le16_to_cpu(cmd->ba_fail_cnt.rate));
-               ar9170_tx_fake_ampdu_status(ar);
                break;
  
        case 0xc6:
@@@ -1247,7 -1107,6 +1108,6 @@@ static int ar9170_op_start(struct ieee8
        ar->global_ampdu_density = 6;
        ar->global_ampdu_factor = 3;
  
-       atomic_set(&ar->tx_ampdu_pending, 0);
        ar->bad_hw_nagger = jiffies;
  
        err = ar->open(ar);
@@@ -1310,40 -1169,10 +1170,10 @@@ static void ar9170_op_stop(struct ieee8
                skb_queue_purge(&ar->tx_pending[i]);
                skb_queue_purge(&ar->tx_status[i]);
        }
-       skb_queue_purge(&ar->tx_status_ampdu);
  
        mutex_unlock(&ar->mutex);
  }
  
- static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
- {
-       struct ar9170_tx_control *txc = (void *) skb->data;
-       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
- }
- static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
-                              struct sk_buff *src)
- {
-       struct ar9170_tx_control *dst_txc, *src_txc;
-       struct ieee80211_tx_info *dst_info, *src_info;
-       struct ar9170_tx_info *dst_arinfo, *src_arinfo;
-       src_txc = (void *) src->data;
-       src_info = IEEE80211_SKB_CB(src);
-       src_arinfo = (void *) src_info->rate_driver_data;
-       dst_txc = (void *) dst->data;
-       dst_info = IEEE80211_SKB_CB(dst);
-       dst_arinfo = (void *) dst_info->rate_driver_data;
-       dst_txc->phy_control = src_txc->phy_control;
-       /* same MCS for the whole aggregate */
-       memcpy(dst_info->driver_rates, src_info->driver_rates,
-              sizeof(dst_info->driver_rates));
- }
  static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
  {
        struct ieee80211_hdr *hdr;
                txc->phy_control |=
                        cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
  
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       if (unlikely(!info->control.sta))
-                               goto err_out;
-                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-               } else {
-                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
-               }
+               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
        }
  
        return 0;
@@@ -1537,158 -1359,6 +1360,6 @@@ static void ar9170_tx_prepare_phy(struc
        txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
  }
  
- static bool ar9170_tx_ampdu(struct ar9170 *ar)
- {
-       struct sk_buff_head agg;
-       struct ar9170_sta_tid *tid_info = NULL, *tmp;
-       struct sk_buff *skb, *first = NULL;
-       unsigned long flags, f2;
-       unsigned int i = 0;
-       u16 seq, queue, tmpssn;
-       bool run = false;
-       skb_queue_head_init(&agg);
-       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-       if (list_empty(&ar->tx_ampdu_list)) {
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: aggregation list is empty.\n",
-                      wiphy_name(ar->hw->wiphy));
- #endif /* AR9170_TXAGG_DEBUG */
-               goto out_unlock;
-       }
-       list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
-               if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
-                              wiphy_name(ar->hw->wiphy));
- #endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-               if (++i > 64) {
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: enough frames aggregated.\n",
-                              wiphy_name(ar->hw->wiphy));
- #endif /* AR9170_TXAGG_DEBUG */
-                       break;
-               }
-               queue = TID_TO_WME_AC(tid_info->tid);
-               if (skb_queue_len(&ar->tx_pending[queue]) >=
-                   AR9170_NUM_TX_AGG_MAX) {
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: queue %d full.\n",
-                              wiphy_name(ar->hw->wiphy), queue);
- #endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-               list_del_init(&tid_info->list);
-               spin_lock_irqsave(&tid_info->queue.lock, f2);
-               tmpssn = seq = tid_info->ssn;
-               first = skb_peek(&tid_info->queue);
-               if (likely(first))
-                       tmpssn = ar9170_get_seq(first);
-               if (unlikely(tmpssn != seq)) {
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
-                              wiphy_name(ar->hw->wiphy), seq, tmpssn);
- #endif /* AR9170_TXAGG_DEBUG */
-                       tid_info->ssn = tmpssn;
-               }
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
-                      "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
-                      tid_info->tid, tid_info->ssn,
-                      skb_queue_len(&tid_info->queue));
-               __ar9170_dump_txqueue(ar, &tid_info->queue);
- #endif /* AR9170_TXAGG_DEBUG */
-               while ((skb = skb_peek(&tid_info->queue))) {
-                       if (unlikely(ar9170_get_seq(skb) != seq))
-                               break;
-                       __skb_unlink(skb, &tid_info->queue);
-                       tid_info->ssn = seq = GET_NEXT_SEQ(seq);
-                       if (unlikely(skb_get_queue_mapping(skb) != queue)) {
- #ifdef AR9170_TXAGG_DEBUG
-                               printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
-                                      "!match.\n", wiphy_name(ar->hw->wiphy),
-                                      tid_info->tid,
-                                      TID_TO_WME_AC(tid_info->tid),
-                                      skb_get_queue_mapping(skb));
- #endif /* AR9170_TXAGG_DEBUG */
-                                       dev_kfree_skb_any(skb);
-                                       continue;
-                       }
-                       if (unlikely(first == skb)) {
-                               ar9170_tx_prepare_phy(ar, skb);
-                               __skb_queue_tail(&agg, skb);
-                               first = skb;
-                       } else {
-                               ar9170_tx_copy_phy(ar, skb, first);
-                               __skb_queue_tail(&agg, skb);
-                       }
-                       if (unlikely(skb_queue_len(&agg) ==
-                           AR9170_NUM_TX_AGG_MAX))
-                               break;
-               }
-               if (skb_queue_empty(&tid_info->queue))
-                       tid_info->active = false;
-               else
-                       list_add_tail(&tid_info->list,
-                                     &ar->tx_ampdu_list);
-               spin_unlock_irqrestore(&tid_info->queue.lock, f2);
-               if (unlikely(skb_queue_empty(&agg))) {
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: queued empty list!\n",
-                              wiphy_name(ar->hw->wiphy));
- #endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-               /*
-                * tell the FW/HW that this is the last frame,
-                * that way it will wait for the immediate block ack.
-                */
-               ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
-                      wiphy_name(ar->hw->wiphy));
-               __ar9170_dump_txqueue(ar, &agg);
- #endif /* AR9170_TXAGG_DEBUG */
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
-               skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
-               spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
-               run = true;
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-       }
- out_unlock:
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       __skb_queue_purge(&agg);
-       return run;
- }
  static void ar9170_tx(struct ar9170 *ar)
  {
        struct sk_buff *skb;
                        arinfo->timeout = jiffies +
                                          msecs_to_jiffies(AR9170_TX_TIMEOUT);
  
-                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                               atomic_inc(&ar->tx_ampdu_pending);
  #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: send frame q:%d =>\n",
                               wiphy_name(ar->hw->wiphy), i);
  
                        err = ar->tx(ar, skb);
                        if (unlikely(err)) {
-                               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                                       atomic_dec(&ar->tx_ampdu_pending);
                                frames_failed++;
                                dev_kfree_skb_any(skb);
                        } else {
                                     msecs_to_jiffies(AR9170_JANITOR_DELAY));
  }
  
- static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
- {
-       struct ieee80211_tx_info *txinfo;
-       struct ar9170_sta_info *sta_info;
-       struct ar9170_sta_tid *agg;
-       struct sk_buff *iter;
-       unsigned long flags, f2;
-       unsigned int max;
-       u16 tid, seq, qseq;
-       bool run = false, queue = false;
-       tid = ar9170_get_tid(skb);
-       seq = ar9170_get_seq(skb);
-       txinfo = IEEE80211_SKB_CB(skb);
-       sta_info = (void *) txinfo->control.sta->drv_priv;
-       agg = &sta_info->agg[tid];
-       max = sta_info->ampdu_max_len;
-       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-       if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
-                      "for ESS:%pM tid:%d state:%d.\n",
-                      wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
-                      agg->state);
- #endif /* AR9170_TXAGG_DEBUG */
-               goto err_unlock;
-       }
-       if (!agg->active) {
-               agg->active = true;
-               agg->ssn = seq;
-               queue = true;
-       }
-       /* check if seq is within the BA window */
-       if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
-                      "fit into BA window (%d - %d)\n",
-                      wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
-                      (agg->ssn + max) & 0xfff);
- #endif /* AR9170_TXAGG_DEBUG */
-               goto err_unlock;
-       }
-       spin_lock_irqsave(&agg->queue.lock, f2);
-       skb_queue_reverse_walk(&agg->queue, iter) {
-               qseq = ar9170_get_seq(iter);
-               if (GET_NEXT_SEQ(qseq) == seq) {
-                       __skb_queue_after(&agg->queue, iter, skb);
-                       goto queued;
-               }
-       }
-       __skb_queue_head(&agg->queue, skb);
- queued:
-       spin_unlock_irqrestore(&agg->queue.lock, f2);
- #ifdef AR9170_TXAGG_DEBUG
-       printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
-              wiphy_name(ar->hw->wiphy), skb);
-       __ar9170_dump_txqueue(ar, &agg->queue);
- #endif /* AR9170_TXAGG_DEBUG */
-       if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
-               run = true;
-       if (queue)
-               list_add_tail(&agg->list, &ar->tx_ampdu_list);
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       return run;
- err_unlock:
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       dev_kfree_skb_irq(skb);
-       return false;
- }
  int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
  {
        struct ar9170 *ar = hw->priv;
        struct ieee80211_tx_info *info;
+       unsigned int queue;
  
        if (unlikely(!IS_STARTED(ar)))
                goto err_free;
        if (unlikely(ar9170_tx_prepare(ar, skb)))
                goto err_free;
  
+       queue = skb_get_queue_mapping(skb);
        info = IEEE80211_SKB_CB(skb);
-       if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-               bool run = ar9170_tx_ampdu_queue(ar, skb);
-               if (run || !atomic_read(&ar->tx_ampdu_pending))
-                       ar9170_tx_ampdu(ar);
-       } else {
-               unsigned int queue = skb_get_queue_mapping(skb);
-               ar9170_tx_prepare_phy(ar, skb);
-               skb_queue_tail(&ar->tx_pending[queue], skb);
-       }
+       ar9170_tx_prepare_phy(ar, skb);
+       skb_queue_tail(&ar->tx_pending[queue], skb);
  
        ar9170_tx(ar);
        return NETDEV_TX_OK;
        return err;
  }
  
 -static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
 -                                     struct dev_addr_list *mclist)
 +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw,
 +                                     struct netdev_hw_addr_list *mc_list)
  {
        u64 mchash;
 -      int i;
 +      struct netdev_hw_addr *ha;
  
        /* always get broadcast frames */
        mchash = 1ULL << (0xff >> 2);
  
 -      for (i = 0; i < mc_count; i++) {
 -              if (WARN_ON(!mclist))
 -                      break;
 -              mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
 -              mclist = mclist->next;
 -      }
 +      netdev_hw_addr_list_for_each(ha, mc_list)
 +              mchash |= 1ULL << (ha->addr[5] >> 2);
  
        return mchash;
  }
@@@ -2326,57 -1903,6 +1900,6 @@@ out
        return err;
  }
  
- static int ar9170_sta_add(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif,
-                         struct ieee80211_sta *sta)
- {
-       struct ar9170 *ar = hw->priv;
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       unsigned int i;
-       memset(sta_info, 0, sizeof(*sta_info));
-       if (!sta->ht_cap.ht_supported)
-               return 0;
-       if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
-               ar->global_ampdu_density = sta->ht_cap.ampdu_density;
-       if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
-               ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
-       for (i = 0; i < AR9170_NUM_TID; i++) {
-               sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
-               sta_info->agg[i].active = false;
-               sta_info->agg[i].ssn = 0;
-               sta_info->agg[i].tid = i;
-               INIT_LIST_HEAD(&sta_info->agg[i].list);
-               skb_queue_head_init(&sta_info->agg[i].queue);
-       }
-       sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
-       return 0;
- }
- static int ar9170_sta_remove(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_sta *sta)
- {
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       unsigned int i;
-       if (!sta->ht_cap.ht_supported)
-               return 0;
-       for (i = 0; i < AR9170_NUM_TID; i++) {
-               sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
-               skb_queue_purge(&sta_info->agg[i].queue);
-       }
-       return 0;
- }
  static int ar9170_get_stats(struct ieee80211_hw *hw,
                            struct ieee80211_low_level_stats *stats)
  {
@@@ -2419,55 -1945,7 +1942,7 @@@ static int ar9170_ampdu_action(struct i
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
  {
-       struct ar9170 *ar = hw->priv;
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
-       unsigned long flags;
-       if (!modparam_ht)
-               return -EOPNOTSUPP;
        switch (action) {
-       case IEEE80211_AMPDU_TX_START:
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
-                   !list_empty(&tid_info->list)) {
-                       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- #ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
-                              "is in a very bad state!\n",
-                              wiphy_name(hw->wiphy), sta->addr, tid);
- #endif /* AR9170_TXAGG_DEBUG */
-                       return -EBUSY;
-               }
-               *ssn = tid_info->ssn;
-               tid_info->state = AR9170_TID_STATE_PROGRESS;
-               tid_info->active = false;
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               break;
-       case IEEE80211_AMPDU_TX_STOP:
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               tid_info->state = AR9170_TID_STATE_SHUTDOWN;
-               list_del_init(&tid_info->list);
-               tid_info->active = false;
-               skb_queue_purge(&tid_info->queue);
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               break;
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
- #ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
-                      wiphy_name(hw->wiphy), sta->addr, tid);
- #endif /* AR9170_TXAGG_DEBUG */
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               break;
        case IEEE80211_AMPDU_RX_START:
        case IEEE80211_AMPDU_RX_STOP:
                /* Handled by firmware */
@@@ -2493,8 -1971,6 +1968,6 @@@ static const struct ieee80211_ops ar917
        .bss_info_changed       = ar9170_op_bss_info_changed,
        .get_tsf                = ar9170_op_get_tsf,
        .set_key                = ar9170_set_key,
-       .sta_add                = ar9170_sta_add,
-       .sta_remove             = ar9170_sta_remove,
        .get_stats              = ar9170_get_stats,
        .ampdu_action           = ar9170_ampdu_action,
  };
@@@ -2509,7 -1985,7 +1982,7 @@@ void *ar9170_alloc(size_t priv_size
        /*
         * this buffer is used for rx stream reconstruction.
         * Under heavy load this device (or the transport layer?)
 -       * tends to split the streams into seperate rx descriptors.
 +       * tends to split the streams into separate rx descriptors.
         */
  
        skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
        mutex_init(&ar->mutex);
        spin_lock_init(&ar->cmdlock);
        spin_lock_init(&ar->tx_stats_lock);
-       spin_lock_init(&ar->tx_ampdu_list_lock);
-       skb_queue_head_init(&ar->tx_status_ampdu);
        for (i = 0; i < __AR9170_NUM_TXQ; i++) {
                skb_queue_head_init(&ar->tx_status[i]);
                skb_queue_head_init(&ar->tx_pending[i]);
        ar9170_rx_reset_rx_mpdu(ar);
        INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
        INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
-       INIT_LIST_HEAD(&ar->tx_ampdu_list);
  
        /* all hw supports 2.4 GHz, so set channel to 1 by default */
        ar->channel = &ar9170_2ghz_chantable[0];
                         IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                         IEEE80211_HW_SIGNAL_DBM;
  
-       if (modparam_ht) {
-               ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
-       } else {
-               ar9170_band_2GHz.ht_cap.ht_supported = false;
-               ar9170_band_5GHz.ht_cap.ht_supported = false;
-       }
        ar->hw->queues = __AR9170_NUM_TXQ;
        ar->hw->extra_tx_headroom = 8;
-       ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
  
        ar->hw->max_rates = 1;
        ar->hw->max_rate_tries = 3;
index 559019262d30202efd274a806f777a88132e703f,f2d0389a66c0b80f5b7ae848f4c8a0d685a2efd4..c33f17dbe6f17e978191e76ac43bffbbc0978ffe
@@@ -15,7 -15,6 +15,7 @@@
   */
  
  #include <linux/io.h>
 +#include <linux/slab.h>
  #include <asm/unaligned.h>
  
  #include "hw.h"
@@@ -574,6 -573,26 +574,26 @@@ static int __ath9k_hw_init(struct ath_h
  
        ath9k_hw_init_mode_regs(ah);
  
+       /*
+        * Configire PCIE after Ini init. SERDES values now come from ini file
+        * This enables PCIe low power mode.
+        */
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               u32 regval;
+               unsigned int i;
+               /* Set Bits 16 and 17 in the AR_WA register. */
+               regval = REG_READ(ah, AR_WA);
+               regval |= 0x00030000;
+               REG_WRITE(ah, AR_WA, regval);
+               for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {
+                       REG_WRITE(ah,
+                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 0),
+                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 1));
+               }
+       }
        if (ah->is_pciexpress)
                ath9k_hw_configpcipowersave(ah, 0, 0);
        else
index 17197a78d894949407b2c76ef1b9897c76756aef,3faa78ceaed113b576d8c9e1eb3a7cd12b9f1ca6..99b876a2feb9b46616cba70dece8ce258b773daa
@@@ -27,7 -27,6 +27,7 @@@
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
 +#include <linux/slab.h>
  #include <linux/pci.h>
  #include <linux/dma-mapping.h>
  #include <linux/delay.h>
@@@ -2483,7 -2482,6 +2483,6 @@@ int iwl3945_hw_set_hw_params(struct iwl
                                   &priv->_3945.shared_phys, GFP_KERNEL);
        if (!priv->_3945.shared_virt) {
                IWL_ERR(priv, "failed to allocate pci memory\n");
-               mutex_unlock(&priv->mutex);
                return -ENOMEM;
        }
  
index ce7bec402a33bbc885647b733d0e00dff50c6022,ea9d0b2ea0d77c4c279b2e95b9a21efe8d7dd311..9d5d3ccf08c854376e9a22d3364019b37512baf5
@@@ -6,7 -6,6 +6,7 @@@
   *
   */
  
 +#include <linux/slab.h>
  #include <net/cfg80211.h>
  
  #include "cfg.h"
@@@ -79,6 -78,7 +79,7 @@@ static const u32 cipher_suites[] = 
  
  
  static int lbs_cfg_set_channel(struct wiphy *wiphy,
+       struct net_device *netdev,
        struct ieee80211_channel *chan,
        enum nl80211_channel_type channel_type)
  {
index 9fd2beadb6f566214053b8912b9d0788e4562937,bdce71a4ba20d3894dc5a5ea7d3ee0bc5cce7f3b..6f8cb3ee6fed57610ed56756982daf4a4497b493
@@@ -14,7 -14,6 +14,7 @@@
   */
  
  #include <linux/list.h>
 +#include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <net/dst.h>
  #include <net/xfrm.h>
@@@ -652,17 -651,17 +652,17 @@@ static void mac80211_hwsim_beacon(unsig
        add_timer(&data->beacon_timer);
  }
  
+ static const char *hwsim_chantypes[] = {
+       [NL80211_CHAN_NO_HT] = "noht",
+       [NL80211_CHAN_HT20] = "ht20",
+       [NL80211_CHAN_HT40MINUS] = "ht40-",
+       [NL80211_CHAN_HT40PLUS] = "ht40+",
+ };
  
  static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
  {
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
-       static const char *chantypes[4] = {
-               [NL80211_CHAN_NO_HT] = "noht",
-               [NL80211_CHAN_HT20] = "ht20",
-               [NL80211_CHAN_HT40MINUS] = "ht40-",
-               [NL80211_CHAN_HT40PLUS] = "ht40+",
-       };
        static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
                [IEEE80211_SMPS_AUTOMATIC] = "auto",
                [IEEE80211_SMPS_OFF] = "off",
        printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
               wiphy_name(hw->wiphy), __func__,
               conf->channel->center_freq,
-              chantypes[conf->channel_type],
+              hwsim_chantypes[conf->channel_type],
               !!(conf->flags & IEEE80211_CONF_IDLE),
               !!(conf->flags & IEEE80211_CONF_PS),
               smps_modes[conf->smps_mode]);
@@@ -761,9 -760,10 +761,10 @@@ static void mac80211_hwsim_bss_info_cha
        }
  
        if (changed & BSS_CHANGED_HT) {
-               printk(KERN_DEBUG "  %s: HT: op_mode=0x%x\n",
+               printk(KERN_DEBUG "  %s: HT: op_mode=0x%x, chantype=%s\n",
                       wiphy_name(hw->wiphy),
-                      info->ht_operation_mode);
+                      info->ht_operation_mode,
+                      hwsim_chantypes[info->channel_type]);
        }
  
        if (changed & BSS_CHANGED_BASIC_RATES) {
index 884a7779fc5f823b96a65e1cbc63fb9cd72a85bd,86f268cd89e7448a09bb19ab4a03e9a868f33823..97e954ee17f834f7b2d06f82efa3705069974916
@@@ -78,7 -78,6 +78,7 @@@
  
  #include <linux/module.h>
  #include <linux/kernel.h>
 +#include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/device.h>
@@@ -340,18 -339,109 +340,109 @@@ EXPORT_SYMBOL(orinoco_change_mtu)
  /* Tx path                                                          */
  /********************************************************************/
  
+ /* Add encapsulation and MIC to the existing SKB.
+  * The main xmit routine will then send the whole lot to the card.
+  * Need 8 bytes headroom
+  * Need 8 bytes tailroom
+  *
+  *                          With encapsulated ethernet II frame
+  *                          --------
+  *                          803.3 header (14 bytes)
+  *                           dst[6]
+  * --------                  src[6]
+  * 803.3 header (14 bytes)   len[2]
+  *  dst[6]                  803.2 header (8 bytes)
+  *  src[6]                   encaps[6]
+  *  len[2] <- leave alone -> len[2]
+  * --------                 -------- <-- 0
+  * Payload                  Payload
+  * ...                      ...
+  *
+  * --------                 --------
+  *                          MIC (8 bytes)
+  *                          --------
+  *
+  * returns 0 on success, -ENOMEM on error.
+  */
+ int orinoco_process_xmit_skb(struct sk_buff *skb,
+                            struct net_device *dev,
+                            struct orinoco_private *priv,
+                            int *tx_control,
+                            u8 *mic_buf)
+ {
+       struct orinoco_tkip_key *key;
+       struct ethhdr *eh;
+       int do_mic;
+       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
+       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
+                 (key != NULL));
+       if (do_mic)
+               *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+                       HERMES_TXCTRL_MIC;
+       eh = (struct ethhdr *)skb->data;
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
+               struct header_struct {
+                       struct ethhdr eth;      /* 802.3 header */
+                       u8 encap[6];            /* 802.2 header */
+               } __attribute__ ((packed)) hdr;
+               int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
+               if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR
+                                      "%s: Not enough headroom for 802.2 headers %d\n",
+                                      dev->name, skb_headroom(skb));
+                       return -ENOMEM;
+               }
+               /* Fill in new header */
+               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+               hdr.eth.h_proto = htons(len);
+               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+               /* Make room for the new header, and copy it in */
+               eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD);
+               memcpy(eh, &hdr, sizeof(hdr));
+       }
+       /* Calculate Michael MIC */
+       if (do_mic) {
+               size_t len = skb->len - ETH_HLEN;
+               u8 *mic = &mic_buf[0];
+               /* Have to write to an even address, so copy the spare
+                * byte across */
+               if (skb->len % 2) {
+                       *mic = skb->data[skb->len - 1];
+                       mic++;
+               }
+               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
+                           eh->h_dest, eh->h_source, 0 /* priority */,
+                           skb->data + ETH_HLEN,
+                           len, mic);
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL(orinoco_process_xmit_skb);
  static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
  {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
-       struct orinoco_tkip_key *key;
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 txfid = priv->txfid;
-       struct ethhdr *eh;
        int tx_control;
        unsigned long flags;
-       int do_mic;
+       u8 mic_buf[MICHAEL_MIC_LEN+1];
  
        if (!netif_running(dev)) {
                printk(KERN_ERR "%s: Tx on stopped device!\n",
        if (skb->len < ETH_HLEN)
                goto drop;
  
-       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
-       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
-                 (key != NULL));
        tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
  
-       if (do_mic)
-               tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
-                       HERMES_TXCTRL_MIC;
+       err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
+                                      &mic_buf[0]);
+       if (err)
+               goto drop;
  
        if (priv->has_alt_txcntl) {
                /* WPA enabled firmwares have tx_cntl at the end of
                                   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
        }
  
-       eh = (struct ethhdr *)skb->data;
-       /* Encapsulate Ethernet-II frames */
-       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-               struct header_struct {
-                       struct ethhdr eth;      /* 802.3 header */
-                       u8 encap[6];            /* 802.2 header */
-               } __attribute__ ((packed)) hdr;
-               /* Strip destination and source from the data */
-               skb_pull(skb, 2 * ETH_ALEN);
-               /* And move them to a separate header */
-               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-               /* Insert the SNAP header */
-               if (skb_headroom(skb) < sizeof(hdr)) {
-                       printk(KERN_ERR
-                              "%s: Not enough headroom for 802.2 headers %d\n",
-                              dev->name, skb_headroom(skb));
-                       goto drop;
-               }
-               eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
-               memcpy(eh, &hdr, sizeof(hdr));
-       }
        err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
                                  txfid, HERMES_802_3_OFFSET);
        if (err) {
                goto busy;
        }
  
-       /* Calculate Michael MIC */
-       if (do_mic) {
-               u8 mic_buf[MICHAEL_MIC_LEN + 1];
-               u8 *mic;
-               size_t offset;
-               size_t len;
+       if (tx_control & HERMES_TXCTRL_MIC) {
+               size_t offset = HERMES_802_3_OFFSET + skb->len;
+               size_t len = MICHAEL_MIC_LEN;
  
-               if (skb->len % 2) {
-                       /* MIC start is on an odd boundary */
-                       mic_buf[0] = skb->data[skb->len - 1];
-                       mic = &mic_buf[1];
-                       offset = skb->len - 1;
-                       len = MICHAEL_MIC_LEN + 1;
-               } else {
-                       mic = &mic_buf[0];
-                       offset = skb->len;
-                       len = MICHAEL_MIC_LEN;
+               if (offset % 2) {
+                       offset--;
+                       len++;
                }
-               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
-                           eh->h_dest, eh->h_source, 0 /* priority */,
-                           skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
-               /* Write the MIC */
                err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-                                         txfid, HERMES_802_3_OFFSET + offset);
+                                         txfid, offset);
                if (err) {
                        printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
                               dev->name, err);
                goto busy;
        }
  
 -      dev->trans_start = jiffies;
        stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
        goto ok;
  
@@@ -2234,7 -2277,7 +2277,7 @@@ int orinoco_if_add(struct orinoco_priva
        /* we use the default eth_mac_addr for setting the MAC addr */
  
        /* Reserve space in skb for the SNAP header */
-       dev->hard_header_len += ENCAPS_OVERHEAD;
+       dev->needed_headroom = ENCAPS_OVERHEAD;
  
        netif_carrier_off(dev);
  
index babdcdf6d71dad7511b444b1f90551d8dbf0ffe0,99d4f0de77ca1888c789fe7b498a57607edb8b2f..2d2890878deae2162abf5dea253821f09f55e461
@@@ -41,7 -41,6 +41,7 @@@
  #include <linux/if_arp.h>
  #include <linux/ctype.h>
  #include <linux/spinlock.h>
 +#include <linux/slab.h>
  #include <net/iw_handler.h>
  #include <net/cfg80211.h>
  #include <linux/usb/usbnet.h>
@@@ -535,7 -534,7 +535,7 @@@ static int rndis_join_ibss(struct wiph
  
  static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
  
- static int rndis_set_channel(struct wiphy *wiphy,
+ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
  
  static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
@@@ -1546,7 -1545,7 +1546,7 @@@ static int remove_key(struct usbnet *us
  static void set_multicast_list(struct usbnet *usbdev)
  {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 -      struct dev_mc_list *mclist;
 +      struct netdev_hw_addr *ha;
        __le32 filter, basefilter;
        int ret;
        char *mc_addrs = NULL;
                        return;
                }
  
 -              netdev_for_each_mc_addr(mclist, usbdev->net)
 +              netdev_for_each_mc_addr(ha, usbdev->net)
                        memcpy(mc_addrs + i++ * ETH_ALEN,
 -                             mclist->dmi_addr, ETH_ALEN);
 +                             ha->addr, ETH_ALEN);
        }
        netif_addr_unlock_bh(usbdev->net);
  
@@@ -2291,7 -2290,7 +2291,7 @@@ static int rndis_leave_ibss(struct wiph
        return deauthenticate(usbdev);
  }
  
- static int rndis_set_channel(struct wiphy *wiphy,
+ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
        struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
  {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
index 06b92f8b7a55b957c58b1d04ffe61d21d3b4e022,4b3845152e1f35d8b12c273ecfe745bac1a5b445..6126c0ab5880855367bb5e7cae1925f02c547f91
@@@ -31,7 -31,6 +31,7 @@@
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/eeprom_93cx6.h>
 +#include <linux/slab.h>
  
  #include "rt2x00.h"
  #include "rt2x00pci.h"
@@@ -1060,7 -1059,8 +1060,8 @@@ static void rt2400pci_write_tx_desc(str
  /*
   * TX data initialization
   */
- static void rt2400pci_write_beacon(struct queue_entry *entry)
+ static void rt2400pci_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        rt2x00_desc_read(entry_priv->desc, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
  }
  
  static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
  {
        u32 reg;
  
-       if (queue == QID_BEACON) {
-               rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-               if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-                       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-                       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-               }
-               return;
-       }
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
        rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
index ae8e205df26996a366caacc38ead707fce9d61d2,d876c6d87591d5ff03426937905467c5dc324e30..2e4f461406aec8882a159c0f9bcf3e6f337893b3
@@@ -31,7 -31,6 +31,7 @@@
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/eeprom_93cx6.h>
 +#include <linux/slab.h>
  
  #include "rt2x00.h"
  #include "rt2x00pci.h"
@@@ -1217,7 -1216,8 +1217,8 @@@ static void rt2500pci_write_tx_desc(str
  /*
   * TX data initialization
   */
- static void rt2500pci_write_beacon(struct queue_entry *entry)
+ static void rt2500pci_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        rt2x00_desc_read(entry_priv->desc, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
  }
  
  static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
  {
        u32 reg;
  
-       if (queue == QID_BEACON) {
-               rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-               if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-                       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-                       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-               }
-               return;
-       }
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
        rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
index 41d9996c80e6004ad6cfadcbd1cbf9737be39a52,30c0544e8036cf139502185fa2d65195940cd3ac..e88d7033fbc99d598c3e149f5253c15fcc4b6713
@@@ -29,7 -29,6 +29,7 @@@
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
 +#include <linux/slab.h>
  #include <linux/usb.h>
  
  #include "rt2x00.h"
@@@ -369,7 -368,7 +369,7 @@@ static int rt2500usb_config_key(struct 
  
                /*
                 * The encryption key doesn't fit within the CSR cache,
 -               * this means we should allocate it seperately and use
 +               * this means we should allocate it separately and use
                 * rt2x00usb_vendor_request() to send the key to the hardware.
                 */
                reg = KEY_ENTRY(key->hw_key_idx);
                /*
                 * The driver does not support the IV/EIV generation
                 * in hardware. However it demands the data to be provided
 -               * both seperately as well as inside the frame.
 +               * both separately as well as inside the frame.
                 * We already provided the CONFIG_CRYPTO_COPY_IV to rt2x00lib
                 * to ensure rt2x00lib will not strip the data from the
                 * frame after the copy, now we must tell mac80211
@@@ -1083,7 -1082,8 +1083,8 @@@ static void rt2500usb_write_tx_desc(str
   */
  static void rt2500usb_beacondone(struct urb *urb);
  
- static void rt2500usb_write_beacon(struct queue_entry *entry)
+ static void rt2500usb_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
        int length;
-       u16 reg;
+       u16 reg, reg0;
  
        /*
         * Add the descriptor in front of the skb.
         * Send out the guardian byte.
         */
        usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+       rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+       reg0 = reg;
+       rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+       /*
+        * Beacon generation will fail initially.
+        * To prevent this we need to change the TXRX_CSR19
+        * register several times (reg0 is the same as reg
+        * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
+        * and 1 in reg).
+        */
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
  }
  
  static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
        return length;
  }
  
- static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
- {
-       u16 reg, reg0;
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-       rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
-       if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
-               rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
-               rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
-               reg0 = reg;
-               rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
-               /*
-                * Beacon generation will fail initially.
-                * To prevent this we need to change the TXRX_CSR19
-                * register several times (reg0 is the same as reg
-                * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
-                * and 1 in reg).
-                */
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-       }
- }
  /*
   * RX control handlers
   */
@@@ -1214,11 -1203,9 +1204,9 @@@ static void rt2500usb_fill_rxdone(struc
        if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
  
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
-               if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-                       rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
+       if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+               rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
  
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
@@@ -1780,7 -1767,7 +1768,7 @@@ static const struct rt2x00lib_ops rt250
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt2500usb_write_beacon,
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
-       .kick_tx_queue          = rt2500usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt2500usb_fill_rxdone,
        .config_shared_key      = rt2500usb_config_key,
index e37bbeab923399cffc891f530959dc6bf3c3c5f3,7410ac1acaffd13ec030b6f4d9b4f5f05a90a211..db4250d1c8b35cc68abfe078a10753d5ad97e198
@@@ -35,7 -35,6 +35,7 @@@
  
  #include <linux/kernel.h>
  #include <linux/module.h>
 +#include <linux/slab.h>
  
  #include "rt2x00.h"
  #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
@@@ -282,6 -281,104 +282,104 @@@ int rt2800_wait_wpdma_ready(struct rt2x
  }
  EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
  
+ void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+ {
+       __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
+       u32 word;
+       /*
+        * Initialize TX Info descriptor
+        */
+       rt2x00_desc_read(txwi, 0, &word);
+       rt2x00_set_field32(&word, TXWI_W0_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+       rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
+       rt2x00_set_field32(&word, TXWI_W0_TS,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_AMPDU,
+                          test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
+       rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->txop);
+       rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
+       rt2x00_set_field32(&word, TXWI_W0_BW,
+                          test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
+                          test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
+       rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
+       rt2x00_desc_write(txwi, 0, word);
+       rt2x00_desc_read(txwi, 1, &word);
+       rt2x00_set_field32(&word, TXWI_W1_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W1_NSEQ,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
+       rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
+                          test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
+                          txdesc->key_idx : 0xff);
+       rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
+                          txdesc->length);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1);
+       rt2x00_desc_write(txwi, 1, word);
+       /*
+        * Always write 0 to IV/EIV fields, hardware will insert the IV
+        * from the IVEIV register when TXD_W3_WIV is set to 0.
+        * When TXD_W3_WIV is set to 1 it will use the IV data
+        * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
+        * crypto entry in the registers should be used to encrypt the frame.
+        */
+       _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
+       _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
+ }
+ EXPORT_SYMBOL_GPL(rt2800_write_txwi);
+ void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
+ {
+       __le32 *rxwi = (__le32 *) skb->data;
+       u32 word;
+       rt2x00_desc_read(rxwi, 0, &word);
+       rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF);
+       rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+       rt2x00_desc_read(rxwi, 1, &word);
+       if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI))
+               rxdesc->flags |= RX_FLAG_SHORT_GI;
+       if (rt2x00_get_field32(word, RXWI_W1_BW))
+               rxdesc->flags |= RX_FLAG_40MHZ;
+       /*
+        * Detect RX rate, always use MCS as signal type.
+        */
+       rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
+       rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS);
+       rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE);
+       /*
+        * Mask of 0x8 bit to remove the short preamble flag.
+        */
+       if (rxdesc->rate_mode == RATE_MODE_CCK)
+               rxdesc->signal &= ~0x8;
+       rt2x00_desc_read(rxwi, 2, &word);
+       rxdesc->rssi =
+           (rt2x00_get_field32(word, RXWI_W2_RSSI0) +
+            rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
+       /*
+        * Remove RXWI descriptor from start of buffer.
+        */
+       skb_pull(skb, RXWI_DESC_SIZE);
+ }
+ EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
  #ifdef CONFIG_RT2X00_LIB_DEBUGFS
  const struct rt2x00debug rt2800_rt2x00debug = {
        .owner  = THIS_MODULE,
@@@ -640,8 -737,6 +738,6 @@@ void rt2800_config_erp(struct rt2x00_de
        rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
  
        rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
        rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
  
@@@ -1415,9 -1510,16 +1511,16 @@@ int rt2800_init_registers(struct rt2x00
  
        rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
  
+       /*
+        * Usually the CCK SIFS time should be set to 10 and the OFDM SIFS
+        * time should be set to 16. However, the original Ralink driver uses
+        * 16 for both and indeed using a value of 10 for CCK SIFS results in
+        * connection problems with 11g + CTS protection. Hence, use the same
+        * defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS.
+        */
        rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 32);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 32);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, 314);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
@@@ -2219,7 -2321,7 +2322,7 @@@ int rt2800_init_eeprom(struct rt2x00_de
  EXPORT_SYMBOL_GPL(rt2800_init_eeprom);
  
  /*
-  * RF value list for rt28x0
+  * RF value list for rt28xx
   * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
   */
  static const struct rf_channel rf_vals[] = {
  };
  
  /*
-  * RF value list for rt3070
-  * Supports: 2.4 GHz
+  * RF value list for rt3xxx
+  * Supports: 2.4 GHz (all) & 5.2 GHz (RF3052)
   */
- static const struct rf_channel rf_vals_302x[] = {
+ static const struct rf_channel rf_vals_3x[] = {
        {1,  241, 2, 2 },
        {2,  241, 2, 7 },
        {3,  242, 2, 2 },
        {12, 246, 2, 7 },
        {13, 247, 2, 2 },
        {14, 248, 2, 4 },
+       /* 802.11 UNI / HyperLan 2 */
+       {36, 0x56, 0, 4},
+       {38, 0x56, 0, 6},
+       {40, 0x56, 0, 8},
+       {44, 0x57, 0, 0},
+       {46, 0x57, 0, 2},
+       {48, 0x57, 0, 4},
+       {52, 0x57, 0, 8},
+       {54, 0x57, 0, 10},
+       {56, 0x58, 0, 0},
+       {60, 0x58, 0, 4},
+       {62, 0x58, 0, 6},
+       {64, 0x58, 0, 8},
+       /* 802.11 HyperLan 2 */
+       {100, 0x5b, 0, 8},
+       {102, 0x5b, 0, 10},
+       {104, 0x5c, 0, 0},
+       {108, 0x5c, 0, 4},
+       {110, 0x5c, 0, 6},
+       {112, 0x5c, 0, 8},
+       {116, 0x5d, 0, 0},
+       {118, 0x5d, 0, 2},
+       {120, 0x5d, 0, 4},
+       {124, 0x5d, 0, 8},
+       {126, 0x5d, 0, 10},
+       {128, 0x5e, 0, 0},
+       {132, 0x5e, 0, 4},
+       {134, 0x5e, 0, 6},
+       {136, 0x5e, 0, 8},
+       {140, 0x5f, 0, 0},
+       /* 802.11 UNII */
+       {149, 0x5f, 0, 9},
+       {151, 0x5f, 0, 11},
+       {153, 0x60, 0, 1},
+       {157, 0x60, 0, 5},
+       {159, 0x60, 0, 7},
+       {161, 0x60, 0, 9},
+       {165, 0x61, 0, 1},
+       {167, 0x61, 0, 3},
+       {169, 0x61, 0, 5},
+       {171, 0x61, 0, 7},
+       {173, 0x61, 0, 9},
  };
  
  int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
  
        if (rt2x00_rf(rt2x00dev, RF2820) ||
-           rt2x00_rf(rt2x00dev, RF2720) ||
-           rt2x00_rf(rt2x00dev, RF3052)) {
+           rt2x00_rf(rt2x00dev, RF2720)) {
                spec->num_channels = 14;
                spec->channels = rf_vals;
-       } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2850) ||
+                  rt2x00_rf(rt2x00dev, RF2750)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals);
                spec->channels = rf_vals;
                   rt2x00_rf(rt2x00dev, RF2020) ||
                   rt2x00_rf(rt2x00dev, RF3021) ||
                   rt2x00_rf(rt2x00dev, RF3022)) {
-               spec->num_channels = ARRAY_SIZE(rf_vals_302x);
-               spec->channels = rf_vals_302x;
+               spec->num_channels = 14;
+               spec->channels = rf_vals_3x;
+       } else if (rt2x00_rf(rt2x00dev, RF3052)) {
+               spec->supported_bands |= SUPPORT_BAND_5GHZ;
+               spec->num_channels = ARRAY_SIZE(rf_vals_3x);
+               spec->channels = rf_vals_3x;
        }
  
        /*
index e3f3a97db80773118c0228b6ced8e99822f4e5e7,d48d705d1808548d7a5b0704810ce72cae8f5bf3..8ad0669a1b99cd56ec19e413641b190419b8612b
@@@ -99,7 -99,7 +99,7 @@@ static int rt2800usb_check_firmware(str
         * There are 2 variations of the rt2870 firmware.
         * a) size: 4kb
         * b) size: 8kb
 -       * Note that (b) contains 2 seperate firmware blobs of 4k
 +       * Note that (b) contains 2 separate firmware blobs of 4k
         * within the file. The first blob is the same firmware as (a),
         * but the second blob is for the additional chipsets.
         */
  
        /*
         * 8kb firmware files must be checked as if it were
 -       * 2 seperate firmware files.
 +       * 2 separate firmware files.
         */
        while (offset < len) {
                if (!rt2800usb_check_crc(data + offset, 4096))
@@@ -401,59 -401,15 +401,15 @@@ static void rt2800usb_write_tx_desc(str
  {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        __le32 *txi = skbdesc->desc;
-       __le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)];
        u32 word;
  
        /*
-        * Initialize TX Info descriptor
-        */
-       rt2x00_desc_read(txwi, 0, &word);
-       rt2x00_set_field32(&word, TXWI_W0_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
-       rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
-       rt2x00_set_field32(&word, TXWI_W0_TS,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_AMPDU,
-                          test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
-       rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
-       rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
-       rt2x00_set_field32(&word, TXWI_W0_BW,
-                          test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
-                          test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
-       rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
-       rt2x00_desc_write(txwi, 0, word);
-       rt2x00_desc_read(txwi, 1, &word);
-       rt2x00_set_field32(&word, TXWI_W1_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_NSEQ,
-                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
-       rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-                          test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-                          txdesc->key_idx : 0xff);
-       rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-                          txdesc->length);
-       rt2x00_set_field32(&word, TXWI_W1_PACKETID,
-                          skbdesc->entry->queue->qid + 1);
-       rt2x00_desc_write(txwi, 1, word);
-       /*
-        * Always write 0 to IV/EIV fields, hardware will insert the IV
-        * from the IVEIV register when TXINFO_W0_WIV is set to 0.
-        * When TXINFO_W0_WIV is set to 1 it will use the IV data
-        * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
-        * crypto entry in the registers should be used to encrypt the frame.
-        */
-       _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
-       _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
-       /*
-        * Initialize TX descriptor
+        * Initialize TXWI descriptor
+        */
+       rt2800_write_txwi(skb, txdesc);
+       /*
+        * Initialize TXINFO descriptor
         */
        rt2x00_desc_read(txi, 0, &word);
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
  /*
   * TX data initialization
   */
- static void rt2800usb_write_beacon(struct queue_entry *entry)
+ static void rt2800usb_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
  
-       /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
        rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
  
+       /*
+        * Add the TXWI for the beacon to the skb.
+        */
+       rt2800_write_txwi(entry->skb, txdesc);
+       skb_push(entry->skb, TXWI_DESC_SIZE);
        /*
         * Write entire beacon with descriptor to register.
         */
                                            entry->skb->data, entry->skb->len,
                                            REGISTER_TIMEOUT32(entry->skb->len));
  
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
        /*
         * Clean up the beacon skb.
         */
@@@ -524,84 -487,53 +487,53 @@@ static int rt2800usb_get_tx_data_len(st
        return length;
  }
  
- static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
- {
-       u32 reg;
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-       rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-       if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-               rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-       }
- }
  /*
   * RX control handlers
   */
  static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
  {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        __le32 *rxi = (__le32 *)entry->skb->data;
-       __le32 *rxwi;
        __le32 *rxd;
-       u32 rxi0;
-       u32 rxwi0;
-       u32 rxwi1;
-       u32 rxwi2;
-       u32 rxwi3;
-       u32 rxd0;
+       u32 word;
        int rx_pkt_len;
  
+       /*
+        * Copy descriptor to the skbdesc->desc buffer, making it safe from
+        * moving of frame data in rt2x00usb.
+        */
+       memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
        /*
         * RX frame format is :
         * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
         *          |<------------ rx_pkt_len -------------->|
         */
-       rt2x00_desc_read(rxi, 0, &rxi0);
-       rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
-       rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
+       rt2x00_desc_read(rxi, 0, &word);
+       rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN);
  
        /*
-        * FIXME : we need to check for rx_pkt_len validity
+        * Remove the RXINFO structure from the sbk.
         */
-       rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
+       skb_pull(entry->skb, RXINFO_DESC_SIZE);
  
        /*
-        * Copy descriptor to the skbdesc->desc buffer, making it safe from
-        * moving of frame data in rt2x00usb.
+        * FIXME: we need to check for rx_pkt_len validity
         */
-       memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
+       rxd = (__le32 *)(entry->skb->data + rx_pkt_len);
  
        /*
         * It is now safe to read the descriptor on all architectures.
         */
-       rt2x00_desc_read(rxwi, 0, &rxwi0);
-       rt2x00_desc_read(rxwi, 1, &rxwi1);
-       rt2x00_desc_read(rxwi, 2, &rxwi2);
-       rt2x00_desc_read(rxwi, 3, &rxwi3);
-       rt2x00_desc_read(rxd, 0, &rxd0);
+       rt2x00_desc_read(rxd, 0, &word);
  
-       if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
+       if (rt2x00_get_field32(word, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
  
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W0_CIPHER_ERROR);
  
-       if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
+       if (rt2x00_get_field32(word, RXD_W0_DECRYPTED)) {
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
                 * decryption. Unfortunately the descriptor doesn't contain
                        rxdesc->flags |= RX_FLAG_MMIC_ERROR;
        }
  
-       if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
+       if (rt2x00_get_field32(word, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
  
-       if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
+       if (rt2x00_get_field32(word, RXD_W0_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
  
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
-               rxdesc->flags |= RX_FLAG_SHORT_GI;
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
-               rxdesc->flags |= RX_FLAG_40MHZ;
        /*
-        * Detect RX rate, always use MCS as signal type.
+        * Remove RXD descriptor from end of buffer.
         */
-       rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
-       rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
-       rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
-       /*
-        * Mask of 0x8 bit to remove the short preamble flag.
-        */
-       if (rxdesc->rate_mode == RATE_MODE_CCK)
-               rxdesc->signal &= ~0x8;
-       rxdesc->rssi =
-           (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
-            rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
-       rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+       skb_trim(entry->skb, rx_pkt_len);
  
        /*
-        * Remove RXWI descriptor from start of buffer.
+        * Process the RXWI structure.
         */
-       skb_pull(entry->skb, skbdesc->desc_len);
+       rt2800_process_rxwi(entry->skb, rxdesc);
  }
  
  /*
@@@ -743,7 -655,7 +655,7 @@@ static const struct rt2x00lib_ops rt280
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt2800usb_write_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
-       .kick_tx_queue          = rt2800usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt2800usb_fill_rxdone,
        .config_shared_key      = rt2800_config_shared_key,
@@@ -841,7 -753,7 +753,7 @@@ static struct usb_device_id rt2800usb_d
        { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
-       { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
        { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
index e22029fcf411580571fe696246ffb64659729e42,97b2c76506560cb5b5f13bd50d8d33854405f22c..089a12c7b90f1cd584a1f84ac6f001d97d944438
@@@ -24,7 -24,6 +24,7 @@@
        Abstract: rt2x00 queue specific routines.
   */
  
 +#include <linux/slab.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/dma-mapping.h>
@@@ -429,20 -428,23 +429,23 @@@ static void rt2x00queue_write_tx_descri
         * it is now ready to be dumped to userspace through debugfs.
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+ }
+ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
+                                     struct txentry_desc *txdesc)
+ {
+       struct data_queue *queue = entry->queue;
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
  
        /*
         * Check if we need to kick the queue, there are however a few rules
-        *      1) Don't kick beacon queue
-        *      2) Don't kick unless this is the last in frame in a burst.
+        *      1) Don't kick unless this is the last in frame in a burst.
         *         When the burst flag is set, this frame is always followed
         *         by another frame which in some way are related to eachother.
         *         This is true for fragments, RTS or CTS-to-self frames.
-        *      3) Rule 2 can be broken when the available entries
+        *      2) Rule 1 can be broken when the available entries
         *         in the queue are less then a certain threshold.
         */
-       if (entry->queue->qid == QID_BEACON)
-               return;
        if (rt2x00queue_threshold(queue) ||
            !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
                rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
@@@ -496,7 -498,7 +499,7 @@@ int rt2x00queue_write_tx_frame(struct d
        /*
         * When hardware encryption is supported, and this frame
         * is to be encrypted, we should strip the IV/EIV data from
 -       * the frame so we can provide it to the driver seperately.
 +       * the frame so we can provide it to the driver separately.
         */
        if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
            !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
  
        rt2x00queue_index_inc(queue, Q_INDEX);
        rt2x00queue_write_tx_descriptor(entry, &txdesc);
+       rt2x00queue_kick_tx_queue(entry, &txdesc);
  
        return 0;
  }
@@@ -603,12 -606,9 +607,9 @@@ int rt2x00queue_update_beacon(struct rt
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
  
        /*
-        * Send beacon to hardware.
-        * Also enable beacon generation, which might have been disabled
-        * by the driver during the config_beacon() callback function.
+        * Send beacon to hardware and enable beacon genaration..
         */
-       rt2x00dev->ops->lib->write_beacon(intf->beacon);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
+       rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
  
        mutex_unlock(&intf->beacon_skb_mutex);
  
index 26ee7911fba92c406330798a654539ffadcaa7df,24363634e6fd13ac0cd1d82f2c86f5ffd6f84093..86c75b9c3f255ebc5048dcb46afb2557f019ac52
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
 +#include <linux/slab.h>
  #include <linux/pci.h>
  #include <linux/eeprom_93cx6.h>
  
@@@ -477,7 -476,7 +477,7 @@@ static int rt61pci_config_pairwise_key(
                 * The driver does not support the IV/EIV generation
                 * in hardware. However it doesn't support the IV/EIV
                 * inside the ieee80211 frame either, but requires it
 -               * to be provided seperately for the descriptor.
 +               * to be provided separately for the descriptor.
                 * rt2x00lib will cut the IV/EIV data out of all frames
                 * given to us by mac80211, but we must tell mac80211
                 * to generate the IV/EIV data.
@@@ -1843,7 -1842,8 +1843,8 @@@ static void rt61pci_write_tx_desc(struc
  /*
   * TX data initialization
   */
- static void rt61pci_write_beacon(struct queue_entry *entry)
+ static void rt61pci_write_beacon(struct queue_entry *entry,
+                                struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
                                      beacon_base + skbdesc->desc_len,
                                      entry->skb->data, entry->skb->len);
  
+       /*
+        * Enable beaconing again.
+        *
+        * For Wi-Fi faily generated beacons between participating
+        * stations. Set TBTT phase adaptive adjustment step to 8us.
+        */
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
        /*
         * Clean up beacon skb.
         */
@@@ -1881,23 -1894,6 +1895,6 @@@ static void rt61pci_kick_tx_queue(struc
  {
        u32 reg;
  
-       if (queue == QID_BEACON) {
-               /*
-                * For Wi-Fi faily generated beacons between participating
-                * stations. Set TBTT phase adaptive adjustment step to 8us.
-                */
-               rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
-               rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
-               if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-                       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-                       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
-               }
-               return;
-       }
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
        rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
@@@ -1969,12 -1965,8 +1966,8 @@@ static void rt61pci_fill_rxdone(struct 
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
  
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               rxdesc->cipher =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+       rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
  
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]);
index 39b3c6d04af4b6260b80322ffe4d46339a000a42,81f6db1b16f2b1271180dab06f4fc8b0df7f0e80..11c1307482065dfcd882864871beb57aa3074fc8
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
 +#include <linux/slab.h>
  #include <linux/usb.h>
  
  #include "rt2x00.h"
@@@ -340,7 -339,7 +340,7 @@@ static int rt73usb_config_shared_key(st
                 * The driver does not support the IV/EIV generation
                 * in hardware. However it doesn't support the IV/EIV
                 * inside the ieee80211 frame either, but requires it
 -               * to be provided seperately for the descriptor.
 +               * to be provided separately for the descriptor.
                 * rt2x00lib will cut the IV/EIV data out of all frames
                 * given to us by mac80211, but we must tell mac80211
                 * to generate the IV/EIV data.
@@@ -440,7 -439,7 +440,7 @@@ static int rt73usb_config_pairwise_key(
                 * The driver does not support the IV/EIV generation
                 * in hardware. However it doesn't support the IV/EIV
                 * inside the ieee80211 frame either, but requires it
 -               * to be provided seperately for the descriptor.
 +               * to be provided separately for the descriptor.
                 * rt2x00lib will cut the IV/EIV data out of all frames
                 * given to us by mac80211, but we must tell mac80211
                 * to generate the IV/EIV data.
@@@ -1505,7 -1504,8 +1505,8 @@@ static void rt73usb_write_tx_desc(struc
  /*
   * TX data initialization
   */
- static void rt73usb_write_beacon(struct queue_entry *entry)
+ static void rt73usb_write_beacon(struct queue_entry *entry,
+                                struct txentry_desc *txdesc)
  {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
                                            entry->skb->data, entry->skb->len,
                                            REGISTER_TIMEOUT32(entry->skb->len));
  
+       /*
+        * Enable beaconing again.
+        *
+        * For Wi-Fi faily generated beacons between participating stations.
+        * Set TBTT phase adaptive adjustment step to 8us (default 16us)
+        */
+       rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+       rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
        /*
         * Clean up the beacon skb.
         */
@@@ -1557,31 -1570,6 +1571,6 @@@ static int rt73usb_get_tx_data_len(stru
        return length;
  }
  
- static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid queue)
- {
-       u32 reg;
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-       /*
-        * For Wi-Fi faily generated beacons between participating stations.
-        * Set TBTT phase adaptive adjustment step to 8us (default 16us)
-        */
-       rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
-       rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
-       if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
-               rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-               rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-               rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-               rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
-       }
- }
  /*
   * RX control handlers
   */
@@@ -1645,12 -1633,8 +1634,8 @@@ static void rt73usb_fill_rxdone(struct 
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
  
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               rxdesc->cipher =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+       rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
  
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
  
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
 -               * decryption. It has provided the data seperately but rt2x00lib
 +               * decryption. It has provided the data separately but rt2x00lib
                 * should decide if it should be reinserted.
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
@@@ -2266,7 -2250,7 +2251,7 @@@ static const struct rt2x00lib_ops rt73u
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt73usb_write_beacon,
        .get_tx_data_len        = rt73usb_get_tx_data_len,
-       .kick_tx_queue          = rt73usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt73usb_fill_rxdone,
        .config_shared_key      = rt73usb_config_shared_key,
index 21307f2412b8367e01f46b949438a15fd91918a0,9430f962c1683737613b0ec5047b844540266f7a..515817de29058483c25d00d7537de67fd9b8776a
@@@ -17,7 -17,6 +17,7 @@@
  
  #include <linux/init.h>
  #include <linux/pci.h>
 +#include <linux/slab.h>
  #include <linux/delay.h>
  #include <linux/etherdevice.h>
  #include <linux/eeprom_93cx6.h>
@@@ -234,6 -233,7 +234,7 @@@ static irqreturn_t rtl8180_interrupt(in
  static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
  {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
        }
  
        spin_lock_irqsave(&priv->lock, flags);
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                       priv->seqno += 0x10;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+       }
        idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
        entry = &ring->desc[idx];
  
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
                ieee80211_stop_queue(dev, prio);
        spin_unlock_irqrestore(&priv->lock, flags);
  
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@@@ -653,10 -662,59 +663,59 @@@ static void rtl8180_stop(struct ieee802
                rtl8180_free_tx_ring(dev, i);
  }
  
+ static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+ {
+       struct rtl8180_priv *priv = dev->priv;
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+ }
+ void rtl8180_beacon_work(struct work_struct *work)
+ {
+       struct rtl8180_vif *vif_priv =
+               container_of(work, struct rtl8180_vif, beacon_work.work);
+       struct ieee80211_vif *vif =
+               container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
+       struct ieee80211_hw *dev = vif_priv->dev;
+       struct ieee80211_mgmt *mgmt;
+       struct sk_buff *skb;
+       int err = 0;
+       /* don't overflow the tx ring */
+       if (ieee80211_queue_stopped(dev, 0))
+               goto resched;
+       /* grab a fresh beacon */
+       skb = ieee80211_beacon_get(dev, vif);
+       /*
+        * update beacon timestamp w/ TSF value
+        * TODO: make hardware update beacon timestamp
+        */
+       mgmt = (struct ieee80211_mgmt *)skb->data;
+       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
+       /* TODO: use actual beacon queue */
+       skb_set_queue_mapping(skb, 0);
+       err = rtl8180_tx(dev, skb);
+       WARN_ON(err);
+ resched:
+       /*
+        * schedule next beacon
+        * TODO: use hardware support for beacon timing
+        */
+       schedule_delayed_work(&vif_priv->beacon_work,
+                       usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
+ }
  static int rtl8180_add_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_vif *vif)
  {
        struct rtl8180_priv *priv = dev->priv;
+       struct rtl8180_vif *vif_priv;
  
        /*
         * We only support one active interface at a time.
  
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
                break;
        default:
                return -EOPNOTSUPP;
  
        priv->vif = vif;
  
+       /* Initialize driver private area */
+       vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
+       vif_priv->dev = dev;
+       INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work);
+       vif_priv->enable_beacon = false;
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
                          le32_to_cpu(*(__le32 *)vif->addr));
@@@ -706,8 -771,11 +772,11 @@@ static void rtl8180_bss_info_changed(st
                                     u32 changed)
  {
        struct rtl8180_priv *priv = dev->priv;
+       struct rtl8180_vif *vif_priv;
        int i;
  
+       vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
        if (changed & BSS_CHANGED_BSSID) {
                for (i = 0; i < ETH_ALEN; i++)
                        rtl818x_iowrite8(priv, &priv->map->BSSID[i],
        }
  
        if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
-               priv->rf->conf_erp(dev, info);
+               priv->rf->conf_erp(dev, info);
+       if (changed & BSS_CHANGED_BEACON_ENABLED)
+               vif_priv->enable_beacon = info->enable_beacon;
+       if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
+               cancel_delayed_work_sync(&vif_priv->beacon_work);
+               if (vif_priv->enable_beacon)
+                       schedule_work(&vif_priv->beacon_work.work);
+       }
  }
  
 -static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
 -                                   struct dev_addr_list *mc_list)
 +static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev,
 +                                   struct netdev_hw_addr_list *mc_list)
  {
 -      return mc_count;
 +      return netdev_hw_addr_list_count(mc_list);
  }
  
  static void rtl8180_configure_filter(struct ieee80211_hw *dev,
        rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
  }
  
- static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
- {
-       struct rtl8180_priv *priv = dev->priv;
-       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
-              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
- }
  static const struct ieee80211_ops rtl8180_ops = {
        .tx                     = rtl8180_tx,
        .start                  = rtl8180_start,
@@@ -857,8 -926,8 +927,8 @@@ static int __devinit rtl8180_probe(stru
                goto err_free_reg;
        }
  
-       if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) ||
-           (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) {
+       if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) ||
+           (err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))) {
                printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n",
                       pci_name(pdev));
                goto err_free_reg;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_SIGNAL_UNSPEC;
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       dev->vif_data_size = sizeof(struct rtl8180_vif);
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                       BIT(NL80211_IFTYPE_ADHOC);
        dev->queues = 1;
        dev->max_signal = 65;
  
index acb1d9e6b7d2f0fc2578a6019653579f102d1d96,139a1e0fc7e30bfec7e3a73cd1e0e9e14b9bd370..1a36d8a2196e7c7c19f8b81dd079c9eaa9140461
@@@ -22,7 -22,6 +22,7 @@@
   */
  
  #include <linux/gpio.h>
 +#include <linux/slab.h>
  
  #include "wl1271_acx.h"
  #include "wl1271_reg.h"
@@@ -441,11 -440,23 +441,23 @@@ static int wl1271_boot_write_irq_polari
        return 0;
  }
  
+ static void wl1271_boot_hw_version(struct wl1271 *wl)
+ {
+       u32 fuse;
+       fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
+       fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
+       wl->hw_pg_ver = (s8)fuse;
+ }
  int wl1271_boot(struct wl1271 *wl)
  {
        int ret = 0;
        u32 tmp, clk, pause;
  
+       wl1271_boot_hw_version(wl);
        if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
                /* ref clk: 19.2/38.4/38.4-XTAL */
                clk = 0x3;
index 62c11af1d8e2066a1606bac832aa61dea691422b,0a2d2ed1e1bfe9966e55e948bfb22c224b09ff78..19393e236e2c8426fb4002d4e77038a9b13055c4
@@@ -27,7 -27,6 +27,7 @@@
  #include <linux/spi/spi.h>
  #include <linux/etherdevice.h>
  #include <linux/ieee80211.h>
 +#include <linux/slab.h>
  
  #include "wl1271.h"
  #include "wl1271_reg.h"
@@@ -516,7 -515,7 +516,7 @@@ int wl1271_cmd_ps_mode(struct wl1271 *w
        ps_params->ps_mode = ps_mode;
        ps_params->send_null_data = send;
        ps_params->retries = 5;
-       ps_params->hang_over_period = 128;
+       ps_params->hang_over_period = 1;
        ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
  
        ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
index 62e544041d0d738ad71beda7196d14e33cdedf66,3e4b9fbe8a00e46e5d7c45277060e2b57bdccb04..5bb9e3fff961077db3b17c9b3bc78d8c690a1723
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/vmalloc.h>
  #include <linux/inetdevice.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  
  #include "wl1271.h"
  #include "wl12xx_80211.h"
        return ret;
  }
  
- static int wl1271_join(struct wl1271 *wl)
+ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
  {
        int ret;
  
+       /*
+        * One of the side effects of the JOIN command is that is clears
+        * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
+        * to a WPA/WPA2 access point will therefore kill the data-path.
+        * Currently there is no supported scenario for JOIN during
+        * association - if it becomes a supported scenario, the WPA/WPA2 keys
+        * must be handled somehow.
+        *
+        */
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               wl1271_info("JOIN while associated.");
+       if (set_assoc)
+               set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
        ret = wl1271_cmd_join(wl, wl->set_bss_type);
        if (ret < 0)
                goto out;
@@@ -1190,7 -1204,6 +1205,6 @@@ static int wl1271_unjoin(struct wl1271 
                goto out;
  
        clear_bit(WL1271_FLAG_JOINED, &wl->flags);
-       wl->channel = 0;
        memset(wl->bssid, 0, ETH_ALEN);
  
        /* stop filterting packets based on bssid */
@@@ -1250,7 -1263,9 +1264,9 @@@ static int wl1271_op_config(struct ieee
                goto out;
  
        /* if the channel changes while joined, join again */
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
+           ((wl->band != conf->channel->band) ||
+            (wl->channel != channel))) {
                wl->band = conf->channel->band;
                wl->channel = channel;
  
                                       "failed %d", ret);
  
                if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
-                       ret = wl1271_join(wl);
+                       ret = wl1271_join(wl, false);
                        if (ret < 0)
                                wl1271_warning("cmd join to update channel "
                                               "failed %d", ret);
@@@ -1344,12 -1359,12 +1360,12 @@@ struct wl1271_filter_params 
        u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
  };
  
 -static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
 -                                     struct dev_addr_list *mc_list)
 +static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
 +                                     struct netdev_hw_addr_list *mc_list)
  {
        struct wl1271_filter_params *fp;
 +      struct netdev_hw_addr *ha;
        struct wl1271 *wl = hw->priv;
 -      int i;
  
        if (unlikely(wl->state == WL1271_STATE_OFF))
                return 0;
        }
  
        /* update multicast filtering parameters */
 -      fp->enabled = true;
 -      if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
 -              mc_count = 0;
 -              fp->enabled = false;
 -      }
 -
        fp->mc_list_length = 0;
 -      for (i = 0; i < mc_count; i++) {
 -              if (mc_list->da_addrlen == ETH_ALEN) {
 +      if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
 +              fp->enabled = false;
 +      } else {
 +              fp->enabled = true;
 +              netdev_hw_addr_list_for_each(ha, mc_list) {
                        memcpy(fp->mc_list[fp->mc_list_length],
 -                             mc_list->da_addr, ETH_ALEN);
 +                                      ha->addr, ETH_ALEN);
                        fp->mc_list_length++;
 -              } else
 -                      wl1271_warning("Unknown mc address length.");
 -              mc_list = mc_list->next;
 +              }
        }
  
        return (u64)(unsigned long)fp;
@@@ -1647,6 -1667,7 +1663,7 @@@ static void wl1271_op_bss_info_changed(
        enum wl1271_cmd_ps_mode mode;
        struct wl1271 *wl = hw->priv;
        bool do_join = false;
+       bool set_assoc = false;
        int ret;
  
        wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
                if (bss_conf->assoc) {
                        u32 rates;
                        wl->aid = bss_conf->aid;
-                       set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
+                       set_assoc = true;
  
                        /*
                         * use basic rates from AP, and determine lowest rate
        }
  
        if (do_join) {
-               ret = wl1271_join(wl);
+               ret = wl1271_join(wl, set_assoc);
                if (ret < 0) {
                        wl1271_warning("cmd join failed %d", ret);
                        goto out_sleep;
@@@ -2228,6 -2249,29 +2245,29 @@@ static DEVICE_ATTR(bt_coex_state, S_IRU
                   wl1271_sysfs_show_bt_coex_state,
                   wl1271_sysfs_store_bt_coex_state);
  
+ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+ {
+       struct wl1271 *wl = dev_get_drvdata(dev);
+       ssize_t len;
+       /* FIXME: what's the maximum length of buf? page size?*/
+       len = 500;
+       mutex_lock(&wl->mutex);
+       if (wl->hw_pg_ver >= 0)
+               len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
+       else
+               len = snprintf(buf, len, "n/a\n");
+       mutex_unlock(&wl->mutex);
+       return len;
+ }
+ static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
+                  wl1271_sysfs_show_hw_pg_ver, NULL);
  int wl1271_register_hw(struct wl1271 *wl)
  {
        int ret;
@@@ -2347,6 -2391,7 +2387,7 @@@ struct ieee80211_hw *wl1271_alloc_hw(vo
        wl->vif = NULL;
        wl->flags = 0;
        wl->sg_enabled = true;
+       wl->hw_pg_ver = -1;
  
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                wl->tx_frames[i] = NULL;
                goto err_platform;
        }
  
+       /* Create sysfs file to get HW PG version */
+       ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
+       if (ret < 0) {
+               wl1271_error("failed to create sysfs file hw_pg_ver");
+               goto err_bt_coex_state;
+       }
        return hw;
  
+ err_bt_coex_state:
+       device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
  err_platform:
        platform_device_unregister(wl->plat_dev);
  
diff --combined include/net/mac80211.h
index 54aa16b98b76e4ffecfb45fbce7b3bab910f8f31,9448a5b1bb1567083bcc2f81cf71e9a4a9c5c4d0..ac45c5b9d7e20bbe49292aca5235e985087e54b4
@@@ -160,6 -160,8 +160,8 @@@ enum ieee80211_bss_change 
        BSS_CHANGED_BEACON_ENABLED      = 1<<9,
        BSS_CHANGED_CQM                 = 1<<10,
        BSS_CHANGED_IBSS                = 1<<11,
+       /* when adding here, make sure to change ieee80211_reconfig */
  };
  
  /**
   *    the current band.
   * @bssid: The BSSID for this BSS
   * @enable_beacon: whether beaconing should be enabled or not
+  * @channel_type: Channel type for this BSS -- the hardware might be
+  *    configured for HT40+ while this BSS only uses no-HT, for
+  *    example.
   * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
   *    This field is only valid when the channel type is one of the HT types.
   * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
@@@ -213,6 -218,7 +218,7 @@@ struct ieee80211_bss_conf 
        u16 ht_operation_mode;
        s32 cqm_rssi_thold;
        u32 cqm_rssi_hyst;
+       enum nl80211_channel_type channel_type;
  };
  
  /**
@@@ -1640,7 -1646,7 +1646,7 @@@ struct ieee80211_ops 
                                 struct ieee80211_bss_conf *info,
                                 u32 changed);
        u64 (*prepare_multicast)(struct ieee80211_hw *hw,
 -                               int mc_count, struct dev_addr_list *mc_list);
 +                               struct netdev_hw_addr_list *mc_list);
        void (*configure_filter)(struct ieee80211_hw *hw,
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
diff --combined net/mac80211/cfg.c
index ae37270a063338f57d188c5189c67007372240e4,ab166c6d9399f7bdc4e221faeb3050e548d7d1a8..c7000a6ca379a2e206be38292dd550a39b396a17
@@@ -9,7 -9,6 +9,7 @@@
  #include <linux/ieee80211.h>
  #include <linux/nl80211.h>
  #include <linux/rtnetlink.h>
 +#include <linux/slab.h>
  #include <net/net_namespace.h>
  #include <linux/rcupdate.h>
  #include <net/cfg80211.h>
@@@ -1162,15 -1161,39 +1162,39 @@@ static int ieee80211_set_txq_params(str
  }
  
  static int ieee80211_set_channel(struct wiphy *wiphy,
+                                struct net_device *netdev,
                                 struct ieee80211_channel *chan,
                                 enum nl80211_channel_type channel_type)
  {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = NULL;
+       if (netdev)
+               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+       switch (ieee80211_get_channel_mode(local, NULL)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel != chan)
+                       return -EBUSY;
+               if (!sdata && local->_oper_channel_type == channel_type)
+                       return 0;
+               break;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
  
        local->oper_channel = chan;
-       local->oper_channel_type = channel_type;
  
-       return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!ieee80211_set_channel_type(local, sdata, channel_type))
+               return -EBUSY;
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
+       return 0;
  }
  
  #ifdef CONFIG_PM
@@@ -1214,6 -1237,20 +1238,20 @@@ static int ieee80211_auth(struct wiphy 
  static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_assoc_request *req)
  {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel == req->bss->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
        return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
  }
  
@@@ -1236,8 -1273,22 +1274,22 @@@ static int ieee80211_disassoc(struct wi
  static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                               struct cfg80211_ibss_params *params)
  {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (!params->channel_fixed)
+                       return -EBUSY;
+               if (local->oper_channel == params->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
        return ieee80211_ibss_join(sdata, params);
  }
  
@@@ -1366,7 -1417,7 +1418,7 @@@ int __ieee80211_request_smps(struct iee
         * association, there's no need to send an action frame.
         */
        if (!sdata->u.mgd.associated ||
-           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_smps(sdata->local, sdata);
                mutex_unlock(&sdata->local->iflist_mtx);
diff --combined net/mac80211/ibss.c
index b72ee6435fa35e17c85bd93daf4664e6c0713c49,36745f494f63bd1c9a29c9b7cd9f3b3072504c78..b2cc1fda6cfdb6ba1054aa2bb224f9fce7bba5e8
@@@ -13,7 -13,6 +13,7 @@@
   */
  
  #include <linux/delay.h>
 +#include <linux/slab.h>
  #include <linux/if_ether.h>
  #include <linux/skbuff.h>
  #include <linux/if_arp.h>
@@@ -103,7 -102,7 +103,7 @@@ static void __ieee80211_sta_join_ibss(s
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
  
        local->oper_channel = chan;
-       local->oper_channel_type = NL80211_CHAN_NO_HT;
+       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
  
        sband = local->hw.wiphy->bands[chan->band];
@@@ -911,7 -910,8 +911,8 @@@ int ieee80211_ibss_join(struct ieee8021
        /* fix ourselves to that channel now already */
        if (params->channel_fixed) {
                sdata->local->oper_channel = params->channel;
-               sdata->local->oper_channel_type = NL80211_CHAN_NO_HT;
+               WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
+                                                   NL80211_CHAN_NO_HT));
        }
  
        if (params->ie) {
index cbaf4981e110918f74970de39761a6d69de7dcca,69e7f4131f465493d73b4be833d779dd312c433e..7ef7798d04cd53ce8d2bd791dca28fec5ce61299
@@@ -665,7 -665,8 +665,7 @@@ struct ieee80211_local 
        struct work_struct recalc_smps;
  
        /* aggregated multicast list */
 -      struct dev_addr_list *mc_list;
 -      int mc_count;
 +      struct netdev_hw_addr_list mc_list;
  
        bool tim_in_locked_section; /* see ieee80211_beacon_get() */
  
        enum mac80211_scan_state next_scan_state;
        struct delayed_work scan_work;
        struct ieee80211_sub_if_data *scan_sdata;
-       enum nl80211_channel_type oper_channel_type;
+       enum nl80211_channel_type _oper_channel_type;
        struct ieee80211_channel *oper_channel, *csa_channel;
  
        /* Temporary remain-on-channel for off-channel operations */
@@@ -1228,6 -1229,20 +1228,20 @@@ int ieee80211_wk_remain_on_channel(stru
  int ieee80211_wk_cancel_remain_on_channel(
        struct ieee80211_sub_if_data *sdata, u64 cookie);
  
+ /* channel management */
+ enum ieee80211_chan_mode {
+       CHAN_MODE_UNDEFINED,
+       CHAN_MODE_HOPPING,
+       CHAN_MODE_FIXED,
+ };
+ enum ieee80211_chan_mode
+ ieee80211_get_channel_mode(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *ignore);
+ bool ieee80211_set_channel_type(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata,
+                               enum nl80211_channel_type chantype);
  #ifdef CONFIG_MAC80211_NOINLINE
  #define debug_noinline noinline
  #else
diff --combined net/mac80211/main.c
index bd632e1ee2c5b66f531d46c70d0fb195a8bfae81,d763d76e809f075424cd74faaf438f2a56ccd607..22a384dfab65d1bd3a8539f39066d8401ff0f649
@@@ -71,7 -71,7 +71,7 @@@ void ieee80211_configure_filter(struct 
        spin_lock_bh(&local->filter_lock);
        changed_flags = local->filter_flags ^ new_flags;
  
 -      mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
 +      mc = drv_prepare_multicast(local, &local->mc_list);
        spin_unlock_bh(&local->filter_lock);
  
        /* be a bit nasty */
@@@ -111,7 -111,7 +111,7 @@@ int ieee80211_hw_config(struct ieee8021
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
-               channel_type = local->oper_channel_type;
+               channel_type = local->_oper_channel_type;
        }
  
        if (chan != local->hw.conf.channel ||
@@@ -390,9 -390,6 +390,9 @@@ struct ieee80211_hw *ieee80211_alloc_hw
        local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
  
        INIT_LIST_HEAD(&local->interfaces);
 +
 +      __hw_addr_init(&local->mc_list);
 +
        mutex_init(&local->iflist_mtx);
        mutex_init(&local->scan_mtx);
  
diff --combined net/mac80211/mlme.c
index 358226f63b81f5fe90af933b61bfa624e2f91e9f,6e149b49d4f01f0233678a8638887adc86f7ce7d..11783192a6254d543e73de0bd45860adbb714f0b
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/rtnetlink.h>
  #include <linux/pm_qos_params.h>
  #include <linux/crc32.h>
 +#include <linux/slab.h>
  #include <net/mac80211.h>
  #include <asm/unaligned.h>
  
@@@ -137,11 -136,14 +137,14 @@@ static u32 ieee80211_enable_ht(struct i
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
-       bool enable_ht = true, ht_changed;
+       bool enable_ht = true;
+       enum nl80211_channel_type prev_chantype;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
  
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  
+       prev_chantype = sdata->vif.bss_conf.channel_type;
        /* HT is not supported */
        if (!sband->ht_cap.ht_supported)
                enable_ht = false;
                }
        }
  
-       ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
-                    channel_type != local->hw.conf.channel_type;
        if (local->tmp_channel)
                local->tmp_channel_type = channel_type;
-       local->oper_channel_type = channel_type;
  
-       if (ht_changed) {
-                 /* channel_type change automatically detected */
-               ieee80211_hw_config(local, 0);
+       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, channel_type));
+       }
  
+       /* channel_type change automatically detected */
+       ieee80211_hw_config(local, 0);
+       if (prev_chantype != channel_type) {
                rcu_read_lock();
                sta = sta_info_get(sdata, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED,
-                                                local->oper_channel_type);
+                                                channel_type);
                rcu_read_unlock();
-         }
-       /* disable HT */
-       if (!enable_ht)
-               return 0;
+       }
  
        ht_opmode = le16_to_cpu(hti->operation_mode);
  
        /* if bss configuration changed store the new one */
-       if (!sdata->ht_opmode_valid ||
-           sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
+       if (sdata->ht_opmode_valid != enable_ht ||
+           sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
+           prev_chantype != channel_type) {
                changed |= BSS_CHANGED_HT;
                sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
-               sdata->ht_opmode_valid = true;
+               sdata->ht_opmode_valid = enable_ht;
        }
  
        return changed;
@@@ -866,7 -867,7 +868,7 @@@ static void ieee80211_set_disassoc(stru
        ieee80211_set_wmm_default(sdata);
  
        /* channel(_type) changes are handled by ieee80211_hw_config */
-       local->oper_channel_type = NL80211_CHAN_NO_HT;
+       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
  
        /* on the next assoc, re-program HT parameters */
        sdata->ht_opmode_valid = false;
  
        ieee80211_hw_config(local, config_changed);
  
-       /* And the BSSID changed -- not very interesting here */
-       changed |= BSS_CHANGED_BSSID;
+       /* The BSSID (not really interesting) and HT changed */
+       changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
  
        if (remove_sta)
@@@ -2266,7 -2267,7 +2268,7 @@@ int ieee80211_mgd_action(struct ieee802
        if ((chan != local->tmp_channel ||
             channel_type != local->tmp_channel_type) &&
            (chan != local->oper_channel ||
-            channel_type != local->oper_channel_type))
+            channel_type != local->_oper_channel_type))
                return -EBUSY;
  
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
diff --combined net/wireless/ibss.c
index 6a5acf7501740a1da95520f8f867cd2187b46c18,9825317e653aaf748c7511083c64ea62c5bb2417..adcabba02e20c78199d3913a626fe74f209e002d
@@@ -6,7 -6,6 +6,7 @@@
  
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
 +#include <linux/slab.h>
  #include <net/cfg80211.h>
  #include "wext-compat.h"
  #include "nl80211.h"
@@@ -81,15 -80,10 +81,10 @@@ int __cfg80211_join_ibss(struct cfg8021
                         struct cfg80211_cached_keys *connkeys)
  {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct ieee80211_channel *chan;
        int err;
  
        ASSERT_WDEV_LOCK(wdev);
  
-       chan = rdev_fixed_channel(rdev, wdev);
-       if (chan && chan != params->channel)
-               return -EBUSY;
        if (wdev->ssid_len)
                return -EALREADY;
  
diff --combined net/wireless/nl80211.c
index 01da83ddcff775955ef14c358f1819ff77e74d44,ec1b4a896c6ea01ad54d57ea56ebbf7f0ea90521..aaa1aad566cda4fb16ea866d5a078f8346f33340
@@@ -7,7 -7,6 +7,7 @@@
  #include <linux/if.h>
  #include <linux/module.h>
  #include <linux/err.h>
 +#include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/if_ether.h>
  #include <linux/ieee80211.h>
@@@ -589,6 -588,7 +589,7 @@@ static int nl80211_send_wiphy(struct sk
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
        }
+       CMD(set_channel, SET_CHANNEL);
  
  #undef CMD
  
@@@ -689,10 -689,90 +690,90 @@@ static int parse_txq_params(struct nlat
        return 0;
  }
  
+ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
+ {
+       /*
+        * You can only set the channel explicitly for AP, mesh
+        * and WDS type interfaces; all others have their channel
+        * managed via their respective "establish a connection"
+        * command (connect, join, ...)
+        *
+        * Monitors are special as they are normally slaved to
+        * whatever else is going on, so they behave as though
+        * you tried setting the wiphy channel itself.
+        */
+       return !wdev ||
+               wdev->iftype == NL80211_IFTYPE_AP ||
+               wdev->iftype == NL80211_IFTYPE_WDS ||
+               wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+               wdev->iftype == NL80211_IFTYPE_MONITOR;
+ }
+ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
+                                struct wireless_dev *wdev,
+                                struct genl_info *info)
+ {
+       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+       u32 freq;
+       int result;
+       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+               return -EINVAL;
+       if (!nl80211_can_set_dev_channel(wdev))
+               return -EOPNOTSUPP;
+       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               channel_type = nla_get_u32(info->attrs[
+                                  NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               if (channel_type != NL80211_CHAN_NO_HT &&
+                   channel_type != NL80211_CHAN_HT20 &&
+                   channel_type != NL80211_CHAN_HT40PLUS &&
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       return -EINVAL;
+       }
+       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+       mutex_lock(&rdev->devlist_mtx);
+       if (wdev) {
+               wdev_lock(wdev);
+               result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
+               wdev_unlock(wdev);
+       } else {
+               result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+       }
+       mutex_unlock(&rdev->devlist_mtx);
+       return result;
+ }
+ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
+ {
+       struct cfg80211_registered_device *rdev;
+       struct net_device *netdev;
+       int result;
+       rtnl_lock();
+       result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
+       if (result)
+               goto unlock;
+       result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+  unlock:
+       rtnl_unlock();
+       return result;
+ }
  static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
  {
        struct cfg80211_registered_device *rdev;
-       int result = 0, rem_txq_params = 0;
+       struct net_device *netdev = NULL;
+       struct wireless_dev *wdev;
+       int result, rem_txq_params = 0;
        struct nlattr *nl_txq_params;
        u32 changed;
        u8 retry_short = 0, retry_long = 0;
  
        rtnl_lock();
  
+       /*
+        * Try to find the wiphy and netdev. Normally this
+        * function shouldn't need the netdev, but this is
+        * done for backward compatibility -- previously
+        * setting the channel was done per wiphy, but now
+        * it is per netdev. Previous userland like hostapd
+        * also passed a netdev to set_wiphy, so that it is
+        * possible to let that go to the right netdev!
+        */
        mutex_lock(&cfg80211_mutex);
  
-       rdev = __cfg80211_rdev_from_info(info);
-       if (IS_ERR(rdev)) {
-               mutex_unlock(&cfg80211_mutex);
-               result = PTR_ERR(rdev);
-               goto unlock;
+       if (info->attrs[NL80211_ATTR_IFINDEX]) {
+               int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+               netdev = dev_get_by_index(genl_info_net(info), ifindex);
+               if (netdev && netdev->ieee80211_ptr) {
+                       rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
+                       mutex_lock(&rdev->mtx);
+               } else
+                       netdev = NULL;
        }
  
-       mutex_lock(&rdev->mtx);
+       if (!netdev) {
+               rdev = __cfg80211_rdev_from_info(info);
+               if (IS_ERR(rdev)) {
+                       mutex_unlock(&cfg80211_mutex);
+                       result = PTR_ERR(rdev);
+                       goto unlock;
+               }
+               wdev = NULL;
+               netdev = NULL;
+               result = 0;
+               mutex_lock(&rdev->mtx);
+       } else if (netif_running(netdev) &&
+                  nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+               wdev = netdev->ieee80211_ptr;
+       else
+               wdev = NULL;
+       /*
+        * end workaround code, by now the rdev is available
+        * and locked, and wdev may or may not be NULL.
+        */
  
        if (info->attrs[NL80211_ATTR_WIPHY_NAME])
                result = cfg80211_dev_rename(
        }
  
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-               u32 freq;
-               result = -EINVAL;
-               if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
-                       channel_type = nla_get_u32(info->attrs[
-                                          NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
-                       if (channel_type != NL80211_CHAN_NO_HT &&
-                           channel_type != NL80211_CHAN_HT20 &&
-                           channel_type != NL80211_CHAN_HT40PLUS &&
-                           channel_type != NL80211_CHAN_HT40MINUS)
-                               goto bad_res;
-               }
-               freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
-               mutex_lock(&rdev->devlist_mtx);
-               result = rdev_set_freq(rdev, NULL, freq, channel_type);
-               mutex_unlock(&rdev->devlist_mtx);
+               result = __nl80211_set_channel(rdev, wdev, info);
                if (result)
                        goto bad_res;
        }
  
   bad_res:
        mutex_unlock(&rdev->mtx);
+       if (netdev)
+               dev_put(netdev);
   unlock:
        rtnl_unlock();
        return result;
@@@ -3562,9 -3659,8 +3660,8 @@@ static int nl80211_associate(struct sk_
  {
        struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct wireless_dev *wdev;
        struct cfg80211_crypto_settings crypto;
-       struct ieee80211_channel *chan, *fixedchan;
+       struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
        int err, ssid_len, ie_len = 0;
        bool use_mfp = false;
                goto out;
        }
  
-       mutex_lock(&rdev->devlist_mtx);
-       wdev = dev->ieee80211_ptr;
-       fixedchan = rdev_fixed_channel(rdev, wdev);
-       if (fixedchan && chan != fixedchan) {
-               err = -EBUSY;
-               mutex_unlock(&rdev->devlist_mtx);
-               goto out;
-       }
-       mutex_unlock(&rdev->devlist_mtx);
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
  
@@@ -5186,6 -5272,12 +5273,12 @@@ static struct genl_ops nl80211_ops[] = 
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
+       {
+               .cmd = NL80211_CMD_SET_CHANNEL,
+               .doit = nl80211_set_channel,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
  };
  
  static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --combined net/wireless/sme.c
index 8ddf5ae0dd036442f67f46289414e83682193ef1,14cf8163912ad3a28c348c00efe3e455ba0c4311..72222f0074dbd4b24914386b85e02257d499941d
@@@ -7,7 -7,6 +7,7 @@@
  
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
 +#include <linux/slab.h>
  #include <linux/workqueue.h>
  #include <linux/wireless.h>
  #include <net/iw_handler.h>
@@@ -741,7 -740,6 +741,6 @@@ int __cfg80211_connect(struct cfg80211_
                       const u8 *prev_bssid)
  {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct ieee80211_channel *chan;
        struct cfg80211_bss *bss = NULL;
        int err;
  
        if (wdev->sme_state != CFG80211_SME_IDLE)
                return -EALREADY;
  
-       chan = rdev_fixed_channel(rdev, wdev);
-       if (chan && chan != connect->channel)
-               return -EBUSY;
        if (WARN_ON(wdev->connect_keys)) {
                kfree(wdev->connect_keys);
                wdev->connect_keys = NULL;
index a60a2773b49726b01fc86b58a74a432a8f54fc26,75848c6cb22a0d0ee6adda4974148f5ff2dd0ae6..96342993cf933237d76c33595497d938ed86ec3c
@@@ -12,7 -12,6 +12,7 @@@
  #include <linux/nl80211.h>
  #include <linux/if_arp.h>
  #include <linux/etherdevice.h>
 +#include <linux/slab.h>
  #include <net/iw_handler.h>
  #include <net/cfg80211.h>
  #include "wext-compat.h"
@@@ -782,16 -781,22 +782,22 @@@ int cfg80211_wext_siwfreq(struct net_de
                return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
-       default:
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_WDS:
+       case NL80211_IFTYPE_MESH_POINT:
                freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
                if (freq < 0)
                        return freq;
                if (freq == 0)
                        return -EINVAL;
+               wdev_lock(wdev);
                mutex_lock(&rdev->devlist_mtx);
-               err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
                mutex_unlock(&rdev->devlist_mtx);
+               wdev_unlock(wdev);
                return err;
+       default:
+               return -EOPNOTSUPP;
        }
  }
  EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
@@@ -801,7 -806,6 +807,6 @@@ int cfg80211_wext_giwfreq(struct net_de
                          struct iw_freq *freq, char *extra)
  {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
  
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
        default:
-               if (!rdev->channel)
+               if (!wdev->channel)
                        return -EINVAL;
-               freq->m = rdev->channel->center_freq;
+               freq->m = wdev->channel->center_freq;
                freq->e = 6;
                return 0;
        }
diff --combined net/wireless/wext-sme.c
index d5c6140f4cb8ee25b80da910b4884b351c0b87c5,8e5ab4f4e9c4b142db5162ef70e5788e10dad53b..9818198add8a21444ba9183bbb8e4fc2c2199491
@@@ -7,7 -7,6 +7,7 @@@
  
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
 +#include <linux/slab.h>
  #include <net/cfg80211.h>
  #include "wext-compat.h"
  #include "nl80211.h"
@@@ -108,7 -107,7 +108,7 @@@ int cfg80211_mgd_wext_siwfreq(struct ne
  
        /* SSID is not set, we just want to switch channel */
        if (chan && !wdev->wext.connect.ssid_len) {
-               err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
                goto out;
        }