]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'mac80211-next/master'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:04:35 +0000 (12:04 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:04:35 +0000 (12:04 +1100)
15 files changed:
1  2 
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
net/mac80211/agg-rx.c
net/mac80211/debugfs.c
net/mac80211/ibss.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mlme.c
net/mac80211/sta_info.c
net/mac80211/util.c
net/rfkill/core.c
net/wireless/core.c
net/wireless/reg.c

index 4db4cb7aa73aa8593b0a3061281ab2c013885690,151721e4040c9dc67951eb60fbf21fc19f187429..c63ea79571ff5f0d6b0bbfd07b4a6faba42f1593
@@@ -396,7 -396,7 +396,7 @@@ static int iwlagn_mac_suspend(struct ie
        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
                    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
  
 -      iwl_trans_d3_suspend(priv->trans, false);
 +      iwl_trans_d3_suspend(priv->trans, false, true);
  
        goto out;
  
@@@ -469,7 -469,7 +469,7 @@@ static int iwlagn_mac_resume(struct iee
        /* we'll clear ctx->vif during iwlagn_prepare_restart() */
        vif = ctx->vif;
  
 -      ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
 +      ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true);
        if (ret)
                goto out_unlock;
  
@@@ -732,12 -732,15 +732,15 @@@ static inline bool iwl_enable_tx_ampdu(
  
  static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size, bool amsdu)
+                                  struct ieee80211_ampdu_params *params)
  {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret = -EINVAL;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
        struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
  
        IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
index 01476f5456956b199b262d58efa840eda62dbdb2,1bd3f0b700d3ec67ff924e70ba8353d76b250adf..24c46c2232463d5b42d2314ce30da5aaaf13d964
@@@ -837,13 -837,16 +837,16 @@@ iwl_mvm_ampdu_check_trigger(struct iwl_
  
  static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
-                                   enum ieee80211_ampdu_mlme_action action,
-                                   struct ieee80211_sta *sta, u16 tid,
-                                   u16 *ssn, u8 buf_size, bool amsdu)
+                                   struct ieee80211_ampdu_params *params)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
        bool tx_agg_ref = false;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
  
        IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
                     sta->addr, tid, action);
                        ret = -EINVAL;
                        break;
                }
 -              ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true);
 +              ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);
                break;
        case IEEE80211_AMPDU_RX_STOP:
 -              ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
 +              ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);
                break;
        case IEEE80211_AMPDU_TX_START:
                if (!iwl_enable_tx_ampdu(mvm->cfg)) {
index a28414c50edf11131e41aa65f02957a5a07c796f,ee37af1066d2fb7efb2a82e9ad3b7723f9895ed0..a723a85f5635716aae4afa86cc1d45657f899af0
@@@ -991,8 -991,7 +991,8 @@@ static void mac80211_hwsim_tx_frame_nl(
                goto nla_put_failure;
        }
  
 -      if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2))
 +      if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
 +                  ETH_ALEN, data->addresses[1].addr))
                goto nla_put_failure;
  
        /* We get the skb->data */
@@@ -1334,10 -1333,8 +1334,8 @@@ static void mac80211_hwsim_tx(struct ie
        data->tx_bytes += skb->len;
        ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
  
-       if (ack && skb->len >= 16) {
-               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       if (ack && skb->len >= 16)
                mac80211_hwsim_monitor_ack(channel, hdr->addr2);
-       }
  
        ieee80211_tx_info_clear_status(txi);
  
@@@ -1846,10 -1843,12 +1844,12 @@@ static int mac80211_hwsim_testmode_cmd(
  
  static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
-                                      enum ieee80211_ampdu_mlme_action action,
-                                      struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                      u8 buf_size, bool amsdu)
+                                      struct ieee80211_ampdu_params *params)
  {
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@@ -2737,7 -2736,7 +2737,7 @@@ static struct mac80211_hwsim_data *get_
  
        spin_lock_bh(&hwsim_radio_lock);
        list_for_each_entry(data, &hwsim_radios, list) {
 -              if (mac80211_hwsim_addr_match(data, addr)) {
 +              if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
                        _found = true;
                        break;
                }
index a26afcab03ed02242fdc7fa2f3b94307fc52024e,69c1c09687a30c5c2338cc84f12981eb4133d40d..7fa0128de7e310be2978b35a97746bc011acb324
@@@ -1490,8 -1490,7 +1490,8 @@@ void rt2800_config_filter(struct rt2x00
                           !(filter_flags & FIF_FCSFAIL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
                           !(filter_flags & FIF_PLCPFAIL));
 -      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
 +      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
 +                         !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
@@@ -7936,10 -7935,11 +7936,11 @@@ u64 rt2800_get_tsf(struct ieee80211_hw 
  EXPORT_SYMBOL_GPL(rt2800_get_tsf);
  
  int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size, bool amsdu)
+                       struct ieee80211_ampdu_params *params)
  {
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
        struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
        int ret = 0;
  
diff --combined net/mac80211/agg-rx.c
index 367784be5df20f26fd3940c4608f1ea715bfddd6,1b8a5caa221eb6a2554a95fdfb2a53ea7f17d9c3..3a8f881b22f10c983ab354a4393157e090fd6d3a
@@@ -7,6 -7,7 +7,7 @@@
   * Copyright 2006-2007        Jiri Benc <jbenc@suse.cz>
   * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   * Copyright 2007-2010, Intel Corporation
+  * Copyright(c) 2015 Intel Deutschland GmbH
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
@@@ -61,16 -62,25 +62,25 @@@ void ___ieee80211_stop_rx_ba_session(st
  {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_rx *tid_rx;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_RX_STOP,
+               .tid = tid,
+               .amsdu = false,
+               .timeout = 0,
+               .ssn = 0,
+       };
  
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
  
        tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
                                        lockdep_is_held(&sta->ampdu_mlme.mtx));
  
-       if (!tid_rx)
+       if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
                return;
  
        RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
+       __clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
  
        ht_dbg(sta->sdata,
               "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
@@@ -78,8 -88,7 +88,7 @@@
               initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
               (int)reason);
  
-       if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
-                            &sta->sta, tid, NULL, 0, false))
+       if (drv_ampdu_action(local, sta->sdata, &params))
                sdata_info(sta->sdata,
                           "HW problem - can not stop rx aggregation for %pM tid %d\n",
                           sta->sta.addr, tid);
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, WLAN_BACK_RECIPIENT, reason);
  
+       /*
+        * return here in case tid_rx is not assigned - which will happen if
+        * IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
+        */
+       if (!tid_rx)
+               return;
        del_timer_sync(&tid_rx->session_timer);
  
        /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
@@@ -237,6 -253,15 +253,15 @@@ void __ieee80211_start_rx_ba_session(st
  {
        struct ieee80211_local *local = sta->sdata->local;
        struct tid_ampdu_rx *tid_agg_rx;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_RX_START,
+               .tid = tid,
+               .amsdu = false,
+               .timeout = timeout,
+               .ssn = start_seq_num,
+       };
        int i, ret = -EOPNOTSUPP;
        u16 status = WLAN_STATUS_REQUEST_DECLINED;
  
        /* make sure the size doesn't exceed the maximum supported by the hw */
        if (buf_size > local->hw.max_rx_aggregation_subframes)
                buf_size = local->hw.max_rx_aggregation_subframes;
+       params.buf_size = buf_size;
  
        /* examine state machine */
        mutex_lock(&sta->ampdu_mlme.mtx);
  
-       if (sta->ampdu_mlme.tid_rx[tid]) {
+       if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
                ht_dbg_ratelimited(sta->sdata,
                                   "unexpected AddBA Req from %pM on tid %u\n",
                                   sta->sta.addr, tid);
                                                false);
        }
  
+       if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
+               ret = drv_ampdu_action(local, sta->sdata, &params);
+               ht_dbg(sta->sdata,
+                      "Rx A-MPDU request on %pM tid %d result %d\n",
+                      sta->sta.addr, tid, ret);
+               if (!ret)
+                       status = WLAN_STATUS_SUCCESS;
+               goto end;
+       }
        /* prepare A-MPDU MLME for Rx aggregation */
 -      tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
 +      tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
        if (!tid_agg_rx)
                goto end;
  
        for (i = 0; i < buf_size; i++)
                __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
  
-       ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
-                              &sta->sta, tid, &start_seq_num, 0, false);
+       ret = drv_ampdu_action(local, sta->sdata, &params);
        ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
               sta->sta.addr, tid, ret);
        if (ret) {
        tid_agg_rx->timeout = timeout;
        tid_agg_rx->stored_mpdu_num = 0;
        tid_agg_rx->auto_seq = auto_seq;
+       tid_agg_rx->reorder_buf_filtered = 0;
        status = WLAN_STATUS_SUCCESS;
  
        /* activate it for RX */
        }
  
  end:
+       if (status == WLAN_STATUS_SUCCESS)
+               __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
        mutex_unlock(&sta->ampdu_mlme.mtx);
  
  end_no_lock:
diff --combined net/mac80211/debugfs.c
index 3e24d0ddb51bfaca18d39669e41dba2bb6a91bb5,e433d0c97e86118394cd39c663f3531fd1145a75..4ab5c522ceeeee5def93f869fd96618999a2daf5
@@@ -91,7 -91,7 +91,7 @@@ static const struct file_operations res
  };
  #endif
  
 -static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
 +static const char *hw_flag_names[] = {
  #define FLAG(F)       [IEEE80211_HW_##F] = #F
        FLAG(HAS_RATE_CONTROL),
        FLAG(RX_INCLUDES_FCS),
        FLAG(SUPPORTS_AMSDU_IN_AMPDU),
        FLAG(BEACON_TX_STATUS),
        FLAG(NEEDS_UNIQUE_STA_ADDR),
 -
 -      /* keep last for the build bug below */
 -      (void *)0x1
+       FLAG(SUPPORTS_REORDERING_BUFFER),
  #undef FLAG
  };
  
@@@ -145,7 -149,7 +146,7 @@@ static ssize_t hwflags_read(struct fil
        /* fail compilation if somebody adds or removes
         * a flag without updating the name array above
         */
 -      BUILD_BUG_ON(hw_flag_names[NUM_IEEE80211_HW_FLAGS] != (void *)0x1);
 +      BUILD_BUG_ON(ARRAY_SIZE(hw_flag_names) != NUM_IEEE80211_HW_FLAGS);
  
        for (i = 0; i < NUM_IEEE80211_HW_FLAGS; i++) {
                if (test_bit(i, local->hw.flags))
diff --combined net/mac80211/ibss.c
index 978d3bc31df727468602a7b234d10b5b1e9ba35c,9b983788ee5180eff22407bc27a43791fe0503d2..fc3238376b39546d025f81ad92240356a77aa48b
@@@ -7,6 -7,7 +7,7 @@@
   * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
   * Copyright 2013-2014  Intel Mobile Communications GmbH
+  * Copyright(c) 2016 Intel Deutschland GmbH
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
@@@ -1050,9 -1051,8 +1051,8 @@@ static void ieee80211_update_sta_info(s
                struct cfg80211_chan_def chandef;
                enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
  
-               ieee80211_ht_oper_to_chandef(channel,
-                                            elems->ht_operation,
-                                            &chandef);
+               cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
+               ieee80211_chandef_ht_oper(elems->ht_operation, &chandef);
  
                memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
                rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                        struct ieee80211_vht_cap cap_ie;
                        struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
  
-                       ieee80211_vht_oper_to_chandef(channel,
-                                                     elems->vht_operation,
-                                                     &chandef);
+                       ieee80211_chandef_vht_oper(elems->vht_operation,
+                                                  &chandef);
                        memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
                        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                            &cap_ie, sta);
@@@ -1485,14 -1484,21 +1484,21 @@@ static void ieee80211_sta_find_ibss(str
  
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
  
-               num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
-                                                        &ifibss->chandef,
-                                                        channels,
-                                                        ARRAY_SIZE(channels));
                scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
-               ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-                                           ifibss->ssid_len, channels, num,
-                                           scan_width);
+               if (ifibss->fixed_channel) {
+                       num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+                                                                &ifibss->chandef,
+                                                                channels,
+                                                                ARRAY_SIZE(channels));
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, channels,
+                                                   num, scan_width);
+               } else {
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, NULL,
+                                                   0, scan_width);
+               }
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
  
@@@ -1733,6 -1739,7 +1739,6 @@@ void ieee80211_ibss_notify_scan_complet
                if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
                        continue;
                sdata->u.ibss.last_scan_completed = jiffies;
 -              ieee80211_queue_work(&local->hw, &sdata->work);
        }
        mutex_unlock(&local->iflist_mtx);
  }
diff --combined net/mac80211/mesh.c
index 6f85b6ab8e51015ab9a0520822fc4daff6af92b0,9a8e7b57c86efbb6f9304c4075bfda34be028871..d32cefcb63b02ecd4f1af220c559a2a82c75430d
@@@ -91,11 -91,10 +91,10 @@@ bool mesh_matches_local(struct ieee8021
        if (sdata->vif.bss_conf.basic_rates != basic_rates)
                return false;
  
-       ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
-                                    ie->ht_operation, &sta_chan_def);
-       ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
-                                     ie->vht_operation, &sta_chan_def);
+       cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
+                               NL80211_CHAN_NO_HT);
+       ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
+       ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
  
        if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
                                         &sta_chan_def))
@@@ -1370,6 -1369,17 +1369,6 @@@ out
        sdata_unlock(sdata);
  }
  
 -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
 -{
 -      struct ieee80211_sub_if_data *sdata;
 -
 -      rcu_read_lock();
 -      list_for_each_entry_rcu(sdata, &local->interfaces, list)
 -              if (ieee80211_vif_is_mesh(&sdata->vif) &&
 -                  ieee80211_sdata_running(sdata))
 -                      ieee80211_queue_work(&local->hw, &sdata->work);
 -      rcu_read_unlock();
 -}
  
  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
  {
diff --combined net/mac80211/mesh.h
index 4a8019f79fb2cba035a316b0a8d56a7e8f25d614,d941f3a73a4f9f9a8632c9869a3a1c95d303e80d..87c017a3b1ce8db928a999bec05fb1cf32169b73
@@@ -137,8 -137,6 +137,6 @@@ struct mesh_path 
   * @copy_node: function to copy nodes of the table
   * @size_order: determines size of the table, there will be 2^size_order hash
   *    buckets
-  * @mean_chain_len: maximum average length for the hash buckets' list, if it is
-  *    reached, the table will grow
   * @known_gates: list of known mesh gates and their mpaths by the station. The
   * gate's mpath may or may not be resolved and active.
   *
@@@ -154,7 -152,6 +152,6 @@@ struct mesh_table 
        void (*free_node) (struct hlist_node *p, bool free_leafs);
        int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
        int size_order;
-       int mean_chain_len;
        struct hlist_head *known_gates;
        spinlock_t gates_lock;
  
@@@ -362,10 -359,14 +359,10 @@@ static inline bool mesh_path_sel_is_hwm
        return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
  }
  
 -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
 -
  void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
  void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
  void ieee80211s_stop(void);
  #else
 -static inline void
 -ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
  static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
  { return false; }
  static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
diff --combined net/mac80211/mlme.c
index bfbb1acafdd1f004ff4960b2238fbc5343302f38,857089de475f62a46fdf13055176aa3ea22a26a3..cbb752ab21720f585a3f2412a3490a552b2786e6
@@@ -196,16 -196,7 +196,7 @@@ ieee80211_determine_chantype(struct iee
  
        /* check 40 MHz support, if we have it */
        if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
-               switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-               case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-                       chandef->width = NL80211_CHAN_WIDTH_40;
-                       chandef->center_freq1 += 10;
-                       break;
-               case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                       chandef->width = NL80211_CHAN_WIDTH_40;
-                       chandef->center_freq1 -= 10;
-                       break;
-               }
+               ieee80211_chandef_ht_oper(ht_oper, chandef);
        } else {
                /* 40 MHz (and 80 MHz) must be supported for VHT */
                ret = IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
  
-       vht_chandef.chan = channel;
-       vht_chandef.center_freq1 =
-               ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx,
-                                              channel->band);
-       vht_chandef.center_freq2 = 0;
-       switch (vht_oper->chan_width) {
-       case IEEE80211_VHT_CHANWIDTH_USE_HT:
-               vht_chandef.width = chandef->width;
-               vht_chandef.center_freq1 = chandef->center_freq1;
-               break;
-       case IEEE80211_VHT_CHANWIDTH_80MHZ:
-               vht_chandef.width = NL80211_CHAN_WIDTH_80;
-               break;
-       case IEEE80211_VHT_CHANWIDTH_160MHZ:
-               vht_chandef.width = NL80211_CHAN_WIDTH_160;
-               break;
-       case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
-               vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
-               vht_chandef.center_freq2 =
-                       ieee80211_channel_to_frequency(
-                               vht_oper->center_freq_seg2_idx,
-                               channel->band);
-               break;
-       default:
+       vht_chandef = *chandef;
+       if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
                if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
-                                  "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
-                                  vht_oper->chan_width);
+                                  "AP VHT information is invalid, disable VHT\n");
                ret = IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
@@@ -1638,8 -1605,7 +1605,7 @@@ void ieee80211_dynamic_ps_timer(unsigne
  
  void ieee80211_dfs_cac_timer_work(struct work_struct *work)
  {
-       struct delayed_work *delayed_work =
-               container_of(work, struct delayed_work, work);
+       struct delayed_work *delayed_work = to_delayed_work(work);
        struct ieee80211_sub_if_data *sdata =
                container_of(delayed_work, struct ieee80211_sub_if_data,
                             dfs_cac_timer_work);
@@@ -2079,6 -2045,13 +2045,13 @@@ static void ieee80211_set_disassoc(stru
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
        memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
        memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
+       /* reset MU-MIMO ownership and group data */
+       memset(sdata->vif.bss_conf.mu_group.membership, 0,
+              sizeof(sdata->vif.bss_conf.mu_group.membership));
+       memset(sdata->vif.bss_conf.mu_group.position, 0,
+              sizeof(sdata->vif.bss_conf.mu_group.position));
+       changed |= BSS_CHANGED_MU_GROUPS;
        sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
  
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@@ -3571,6 -3544,9 +3544,9 @@@ static void ieee80211_rx_mgmt_beacon(st
                                elems.ht_cap_elem, elems.ht_operation,
                                elems.vht_operation, bssid, &changed)) {
                mutex_unlock(&local->sta_mtx);
+               sdata_info(sdata,
+                          "failed to follow AP %pM bandwidth change, disconnect\n",
+                          bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DEAUTH_LEAVING,
                                       true, deauth_buf);
@@@ -3946,11 -3922,9 +3922,9 @@@ void ieee80211_sta_work(struct ieee8021
                         * We actually lost the connection ... or did we?
                         * Let's make sure!
                         */
-                       wiphy_debug(local->hw.wiphy,
-                                   "%s: No probe response from AP %pM"
-                                   " after %dms, disconnecting.\n",
-                                   sdata->name,
-                                   bssid, probe_wait_ms);
+                       mlme_dbg(sdata,
+                                "No probe response from AP %pM after %dms, disconnecting.\n",
+                                bssid, probe_wait_ms);
  
                        ieee80211_sta_connection_lost(sdata, bssid,
                                WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
@@@ -4005,6 -3979,8 +3979,6 @@@ static void ieee80211_restart_sta_timer
                if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
                        ieee80211_queue_work(&sdata->local->hw,
                                             &sdata->u.mgd.monitor_work);
 -              /* and do all the other regular work too */
 -              ieee80211_queue_work(&sdata->local->hw, &sdata->work);
        }
  }
  
@@@ -4536,6 -4512,9 +4510,9 @@@ int ieee80211_mgd_auth(struct ieee80211
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
  
+               sdata_info(sdata,
+                          "disconnect from AP %pM for new auth to %pM\n",
+                          ifmgd->associated->bssid, req->bss->bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
@@@ -4604,6 -4583,9 +4581,9 @@@ int ieee80211_mgd_assoc(struct ieee8021
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
  
+               sdata_info(sdata,
+                          "disconnect from AP %pM for new assoc to %pM\n",
+                          ifmgd->associated->bssid, req->bss->bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
diff --combined net/mac80211/sta_info.c
index a4a4f89d3ba01138c033a13a7d023a04a99e3e6d,87b7e7a7df6cc22a8aced080e86c765308ca9a0b..d20bab5c146c9d435ee67d6a11eec746db1b1bfa
@@@ -116,6 -116,7 +116,7 @@@ static void __cleanup_single_sta(struc
  
                        ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
                        atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
+                       txqi->byte_cnt = 0;
                }
        }
  
@@@ -498,11 -499,17 +499,17 @@@ static int sta_info_insert_finish(struc
  {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo;
+       struct station_info *sinfo;
        int err = 0;
  
        lockdep_assert_held(&local->sta_mtx);
  
+       sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
+       if (!sinfo) {
+               err = -ENOMEM;
+               goto out_err;
+       }
        /* check if STA exists already */
        if (sta_info_get_bss(sdata, sta->sta.addr)) {
                err = -EEXIST;
        /* accept BA sessions now */
        clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
  
-       ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
  
-       memset(&sinfo, 0, sizeof(sinfo));
-       sinfo.filled = 0;
-       sinfo.generation = local->sta_generation;
-       cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo->generation = local->sta_generation;
+       cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
  
        sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
  
        __cleanup_single_sta(sta);
   out_err:
        mutex_unlock(&local->sta_mtx);
+       kfree(sinfo);
        rcu_read_lock();
        return err;
  }
@@@ -898,7 -904,7 +904,7 @@@ static void __sta_info_destroy_part2(st
  {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo = {};
+       struct station_info *sinfo;
        int ret;
  
        /*
  
        sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
  
-       sta_set_sinfo(sta, &sinfo);
-       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
+       if (sinfo)
+               sta_set_sinfo(sta, sinfo);
+       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
  
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
-       ieee80211_recalc_min_chandef(sdata);
  
        cleanup_single_sta(sta);
  }
@@@ -1453,7 -1461,7 +1461,7 @@@ ieee80211_sta_ps_deliver_response(struc
  
        more_data = ieee80211_sta_ps_more_data(sta, ignored_acs, reason, driver_release_tids);
  
 -      if (reason == IEEE80211_FRAME_RELEASE_PSPOLL)
 +      if (driver_release_tids && reason == IEEE80211_FRAME_RELEASE_PSPOLL)
                driver_release_tids =
                        BIT(find_highest_prio_tid(driver_release_tids));
  
@@@ -1808,14 -1816,17 +1816,17 @@@ int sta_info_move_state(struct sta_inf
                        clear_bit(WLAN_STA_AUTH, &sta->_flags);
                break;
        case IEEE80211_STA_AUTH:
-               if (sta->sta_state == IEEE80211_STA_NONE)
+               if (sta->sta_state == IEEE80211_STA_NONE) {
                        set_bit(WLAN_STA_AUTH, &sta->_flags);
-               else if (sta->sta_state == IEEE80211_STA_ASSOC)
+               } else if (sta->sta_state == IEEE80211_STA_ASSOC) {
                        clear_bit(WLAN_STA_ASSOC, &sta->_flags);
+                       ieee80211_recalc_min_chandef(sta->sdata);
+               }
                break;
        case IEEE80211_STA_ASSOC:
                if (sta->sta_state == IEEE80211_STA_AUTH) {
                        set_bit(WLAN_STA_ASSOC, &sta->_flags);
+                       ieee80211_recalc_min_chandef(sta->sdata);
                } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
                        if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                            (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
diff --combined net/mac80211/util.c
index 58f58bd5202ff5ad99630bc7584a8afeb8c2cf26,f1e5b76eda708b86ae4a35bbd225a2eeac141593..74dd4d72b2332281f0ee3e73138b8fec3a53e380
@@@ -4,7 -4,7 +4,7 @@@
   * Copyright 2006-2007        Jiri Benc <jbenc@suse.cz>
   * Copyright 2007     Johannes Berg <johannes@sipsolutions.net>
   * Copyright 2013-2014  Intel Mobile Communications GmbH
-  * Copyright (C) 2015 Intel Deutschland GmbH
+  * Copyright (C) 2015-2016    Intel Deutschland GmbH
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
@@@ -1928,6 -1928,9 +1928,9 @@@ int ieee80211_reconfig(struct ieee80211
                          BSS_CHANGED_IDLE |
                          BSS_CHANGED_TXPOWER;
  
+               if (sdata->flags & IEEE80211_SDATA_MU_MIMO_OWNER)
+                       changed |= BSS_CHANGED_MU_GROUPS;
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC |
                 */
                if (sched_scan_req->n_scan_plans > 1 ||
                    __ieee80211_request_sched_scan_start(sched_scan_sdata,
 -                                                       sched_scan_req))
 +                                                       sched_scan_req)) {
 +                      RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
 +                      RCU_INIT_POINTER(local->sched_scan_req, NULL);
                        sched_scan_stopped = true;
 +              }
        mutex_unlock(&local->mtx);
  
        if (sched_scan_stopped)
                cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
  
   wake_up:
 -      local->in_reconfig = false;
 -      barrier();
 +      if (local->in_reconfig) {
 +              local->in_reconfig = false;
 +              barrier();
 +
 +              /* Restart deferred ROCs */
 +              mutex_lock(&local->mtx);
 +              ieee80211_start_next_roc(local);
 +              mutex_unlock(&local->mtx);
 +      }
  
        if (local->monitors == local->open_count && local->monitors > 0)
                ieee80211_add_virtual_monitor(local);
@@@ -2371,10 -2364,23 +2374,23 @@@ u8 *ieee80211_ie_build_vht_oper(u8 *pos
  
        switch (chandef->width) {
        case NL80211_CHAN_WIDTH_160:
-               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+               /*
+                * Convert 160 MHz channel width to new style as interop
+                * workaround.
+                */
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+               vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
+               if (chandef->chan->center_freq < chandef->center_freq1)
+                       vht_oper->center_freq_seg1_idx -= 8;
+               else
+                       vht_oper->center_freq_seg1_idx += 8;
                break;
        case NL80211_CHAN_WIDTH_80P80:
-               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+               /*
+                * Convert 80+80 MHz channel width to new style as interop
+                * workaround.
+                */
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
                break;
        case NL80211_CHAN_WIDTH_80:
                vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
        return pos + sizeof(struct ieee80211_vht_operation);
  }
  
- void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                 const struct ieee80211_ht_operation *ht_oper,
-                                 struct cfg80211_chan_def *chandef)
+ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
+                              struct cfg80211_chan_def *chandef)
  {
        enum nl80211_channel_type channel_type;
  
-       if (!ht_oper) {
-               cfg80211_chandef_create(chandef, control_chan,
-                                       NL80211_CHAN_NO_HT);
-               return;
-       }
+       if (!ht_oper)
+               return false;
  
        switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_NONE:
                break;
        default:
                channel_type = NL80211_CHAN_NO_HT;
+               return false;
        }
  
-       cfg80211_chandef_create(chandef, control_chan, channel_type);
+       cfg80211_chandef_create(chandef, chandef->chan, channel_type);
+       return true;
  }
  
- void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                  const struct ieee80211_vht_operation *oper,
-                                  struct cfg80211_chan_def *chandef)
+ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+                               struct cfg80211_chan_def *chandef)
  {
+       struct cfg80211_chan_def new = *chandef;
+       int cf1, cf2;
        if (!oper)
-               return;
+               return false;
  
-       chandef->chan = control_chan;
+       cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+                                            chandef->chan->band);
+       cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+                                            chandef->chan->band);
  
        switch (oper->chan_width) {
        case IEEE80211_VHT_CHANWIDTH_USE_HT:
                break;
        case IEEE80211_VHT_CHANWIDTH_80MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_80;
+               new.width = NL80211_CHAN_WIDTH_80;
+               new.center_freq1 = cf1;
+               /* If needed, adjust based on the newer interop workaround. */
+               if (oper->center_freq_seg2_idx) {
+                       unsigned int diff;
+                       diff = abs(oper->center_freq_seg2_idx -
+                                  oper->center_freq_seg1_idx);
+                       if (diff == 8) {
+                               new.width = NL80211_CHAN_WIDTH_160;
+                               new.center_freq1 = cf2;
+                       } else if (diff > 8) {
+                               new.width = NL80211_CHAN_WIDTH_80P80;
+                               new.center_freq2 = cf2;
+                       }
+               }
                break;
        case IEEE80211_VHT_CHANWIDTH_160MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_160;
+               new.width = NL80211_CHAN_WIDTH_160;
+               new.center_freq1 = cf1;
                break;
        case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_80P80;
+               new.width = NL80211_CHAN_WIDTH_80P80;
+               new.center_freq1 = cf1;
+               new.center_freq2 = cf2;
                break;
        default:
-               break;
+               return false;
        }
  
-       chandef->center_freq1 =
-               ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
-                                              control_chan->band);
-       chandef->center_freq2 =
-               ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
-                                              control_chan->band);
+       if (!cfg80211_chandef_valid(&new))
+               return false;
+       *chandef = new;
+       return true;
  }
  
  int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
@@@ -2672,6 -2698,18 +2708,18 @@@ u64 ieee80211_calculate_rx_timestamp(st
                sband = local->hw.wiphy->bands[status->band];
                bitrate = sband->bitrates[status->rate_idx].bitrate;
                ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
+               if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+                       /* TODO: handle HT/VHT preambles */
+                       if (status->band == IEEE80211_BAND_5GHZ) {
+                               ts += 20 << shift;
+                               mpdu_offset += 2;
+                       } else if (status->flag & RX_FLAG_SHORTPRE) {
+                               ts += 96;
+                       } else {
+                               ts += 192;
+                       }
+               }
        }
  
        rate = cfg80211_calculate_bitrate(&ri);
@@@ -3357,3 -3395,17 +3405,17 @@@ void ieee80211_init_tx_queue(struct iee
                txqi->txq.ac = IEEE80211_AC_BE;
        }
  }
+ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
+                            unsigned long *frame_cnt,
+                            unsigned long *byte_cnt)
+ {
+       struct txq_info *txqi = to_txq_info(txq);
+       if (frame_cnt)
+               *frame_cnt = txqi->queue.qlen;
+       if (byte_cnt)
+               *byte_cnt = txqi->byte_cnt;
+ }
+ EXPORT_SYMBOL(ieee80211_txq_get_depth);
diff --combined net/rfkill/core.c
index cf5b69ab18294bb2fa36a00f2a19dbf02d0f3045,a805831d5d9bc2ae0c2315daff1b0aad1c2d758c..48ebccf0fe727f70e9f09d77b053cf4e2d2324ca
@@@ -57,6 -57,8 +57,8 @@@ struct rfkill 
  
        bool                    registered;
        bool                    persistent;
+       bool                    polling_paused;
+       bool                    suspended;
  
        const struct rfkill_ops *ops;
        void                    *data;
@@@ -233,29 -235,6 +235,6 @@@ static void rfkill_event(struct rfkill 
        rfkill_send_events(rfkill, RFKILL_OP_CHANGE);
  }
  
- static bool __rfkill_set_hw_state(struct rfkill *rfkill,
-                                 bool blocked, bool *change)
- {
-       unsigned long flags;
-       bool prev, any;
-       BUG_ON(!rfkill);
-       spin_lock_irqsave(&rfkill->lock, flags);
-       prev = !!(rfkill->state & RFKILL_BLOCK_HW);
-       if (blocked)
-               rfkill->state |= RFKILL_BLOCK_HW;
-       else
-               rfkill->state &= ~RFKILL_BLOCK_HW;
-       *change = prev != blocked;
-       any = !!(rfkill->state & RFKILL_BLOCK_ANY);
-       spin_unlock_irqrestore(&rfkill->lock, flags);
-       rfkill_led_trigger_event(rfkill);
-       return any;
- }
  /**
   * rfkill_set_block - wrapper for set_block method
   *
@@@ -285,7 -264,7 +264,7 @@@ static void rfkill_set_block(struct rfk
        spin_lock_irqsave(&rfkill->lock, flags);
        prev = rfkill->state & RFKILL_BLOCK_SW;
  
-       if (rfkill->state & RFKILL_BLOCK_SW)
+       if (prev)
                rfkill->state |= RFKILL_BLOCK_SW_PREV;
        else
                rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
@@@ -332,8 -311,7 +311,7 @@@ static atomic_t rfkill_input_disabled 
   * @blocked: the new state
   *
   * This function sets the state of all switches of given type,
-  * unless a specific switch is claimed by userspace (in which case,
-  * that switch is left alone) or suspended.
+  * unless a specific switch is suspended.
   *
   * Caller must have acquired rfkill_global_mutex.
   */
@@@ -480,14 -458,26 +458,26 @@@ bool rfkill_get_global_sw_state(const e
  
  bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
  {
-       bool ret, change;
+       unsigned long flags;
+       bool ret, prev;
+       BUG_ON(!rfkill);
+       spin_lock_irqsave(&rfkill->lock, flags);
+       prev = !!(rfkill->state & RFKILL_BLOCK_HW);
+       if (blocked)
+               rfkill->state |= RFKILL_BLOCK_HW;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_HW;
+       ret = !!(rfkill->state & RFKILL_BLOCK_ANY);
+       spin_unlock_irqrestore(&rfkill->lock, flags);
  
-       ret = __rfkill_set_hw_state(rfkill, blocked, &change);
+       rfkill_led_trigger_event(rfkill);
  
        if (!rfkill->registered)
                return ret;
  
-       if (change)
+       if (prev != blocked)
                schedule_work(&rfkill->uevent_work);
  
        return ret;
@@@ -730,20 -720,12 +720,12 @@@ static ssize_t state_store(struct devic
  }
  static DEVICE_ATTR_RW(state);
  
- static ssize_t claim_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
- {
-       return sprintf(buf, "%d\n", 0);
- }
- static DEVICE_ATTR_RO(claim);
  static struct attribute *rfkill_dev_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_type.attr,
        &dev_attr_index.attr,
        &dev_attr_persistent.attr,
        &dev_attr_state.attr,
-       &dev_attr_claim.attr,
        &dev_attr_soft.attr,
        &dev_attr_hard.attr,
        NULL,
@@@ -786,6 -768,7 +768,7 @@@ void rfkill_pause_polling(struct rfkil
        if (!rfkill->ops->poll)
                return;
  
+       rfkill->polling_paused = true;
        cancel_delayed_work_sync(&rfkill->poll_work);
  }
  EXPORT_SYMBOL(rfkill_pause_polling);
@@@ -797,6 -780,11 +780,11 @@@ void rfkill_resume_polling(struct rfkil
        if (!rfkill->ops->poll)
                return;
  
+       rfkill->polling_paused = false;
+       if (rfkill->suspended)
+               return;
        queue_delayed_work(system_power_efficient_wq,
                           &rfkill->poll_work, 0);
  }
@@@ -807,7 -795,8 +795,8 @@@ static int rfkill_suspend(struct devic
  {
        struct rfkill *rfkill = to_rfkill(dev);
  
-       rfkill_pause_polling(rfkill);
+       rfkill->suspended = true;
+       cancel_delayed_work_sync(&rfkill->poll_work);
  
        return 0;
  }
@@@ -817,12 -806,16 +806,16 @@@ static int rfkill_resume(struct device 
        struct rfkill *rfkill = to_rfkill(dev);
        bool cur;
  
+       rfkill->suspended = false;
        if (!rfkill->persistent) {
                cur = !!(rfkill->state & RFKILL_BLOCK_SW);
                rfkill_set_block(rfkill, cur);
        }
  
-       rfkill_resume_polling(rfkill);
+       if (rfkill->ops->poll && !rfkill->polling_paused)
+               queue_delayed_work(system_power_efficient_wq,
+                                  &rfkill->poll_work, 0);
  
        return 0;
  }
@@@ -1095,6 -1088,17 +1088,6 @@@ static unsigned int rfkill_fop_poll(str
        return res;
  }
  
 -static bool rfkill_readable(struct rfkill_data *data)
 -{
 -      bool r;
 -
 -      mutex_lock(&data->mtx);
 -      r = !list_empty(&data->events);
 -      mutex_unlock(&data->mtx);
 -
 -      return r;
 -}
 -
  static ssize_t rfkill_fop_read(struct file *file, char __user *buf,
                               size_t count, loff_t *pos)
  {
                        goto out;
                }
                mutex_unlock(&data->mtx);
 +              /* since we re-check and it just compares pointers,
 +               * using !list_empty() without locking isn't a problem
 +               */
                ret = wait_event_interruptible(data->read_wait,
 -                                             rfkill_readable(data));
 +                                             !list_empty(&data->events));
                mutex_lock(&data->mtx);
  
                if (ret)
diff --combined net/wireless/core.c
index 8f0bac7e03c406466e0b5ca2b01b3ca2574ab79f,3a9c41bc849aa8f32fbc75eafe564b3a5385c4db..9f1c4aa851efdf55ab81044b10ef58b7bd73ecf6
@@@ -352,6 -352,16 +352,16 @@@ struct wiphy *wiphy_new_nm(const struc
        WARN_ON(ops->add_station && !ops->del_station);
        WARN_ON(ops->add_mpath && !ops->del_mpath);
        WARN_ON(ops->join_mesh && !ops->leave_mesh);
+       WARN_ON(ops->start_p2p_device && !ops->stop_p2p_device);
+       WARN_ON(ops->start_ap && !ops->stop_ap);
+       WARN_ON(ops->join_ocb && !ops->leave_ocb);
+       WARN_ON(ops->suspend && !ops->resume);
+       WARN_ON(ops->sched_scan_start && !ops->sched_scan_stop);
+       WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
+       WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
+       WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
+       WARN_ON(ops->set_tx_power && !ops->get_tx_power);
+       WARN_ON(ops->set_antenna && !ops->get_antenna);
  
        alloc_size = sizeof(*rdev) + sizeof_priv;
  
@@@ -1147,8 -1157,6 +1157,8 @@@ static int cfg80211_netdev_notifier_cal
                return NOTIFY_DONE;
        }
  
 +      wireless_nlevent_flush();
 +
        return NOTIFY_OK;
  }
  
diff --combined net/wireless/reg.c
index 547ceecc052310f3db3be04d827dff22d567dc1e,bc76b281ed3ae5704679025fabbc43e822da7e97..c5fb317eee68f15a4665a090f7aee16b08ec6765
  #include "regdb.h"
  #include "nl80211.h"
  
- #ifdef CONFIG_CFG80211_REG_DEBUG
- #define REG_DBG_PRINT(format, args...)                        \
-       printk(KERN_DEBUG pr_fmt(format), ##args)
- #else
- #define REG_DBG_PRINT(args...)
- #endif
  /*
   * Grace period we give before making sure all current interfaces reside on
   * channels allowed by the current regulatory domain.
@@@ -178,12 -171,10 +171,10 @@@ enum nl80211_dfs_regions reg_get_dfs_re
        if (wiphy_regd->dfs_region == regd->dfs_region)
                goto out;
  
-       REG_DBG_PRINT("%s: device specific dfs_region "
-                     "(%s) disagrees with cfg80211's "
-                     "central dfs_region (%s)\n",
-                     dev_name(&wiphy->dev),
-                     reg_dfs_region_str(wiphy_regd->dfs_region),
-                     reg_dfs_region_str(regd->dfs_region));
+       pr_debug("%s: device specific dfs_region (%s) disagrees with cfg80211's central dfs_region (%s)\n",
+                dev_name(&wiphy->dev),
+                reg_dfs_region_str(wiphy_regd->dfs_region),
+                reg_dfs_region_str(regd->dfs_region));
  
  out:
        return regd->dfs_region;
@@@ -231,22 -222,20 +222,22 @@@ static const struct ieee80211_regdomai
                /* IEEE 802.11b/g, channels 1..11 */
                REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
                /* IEEE 802.11b/g, channels 12..13. */
 -              REG_RULE(2467-10, 2472+10, 40, 6, 20,
 -                      NL80211_RRF_NO_IR),
 +              REG_RULE(2467-10, 2472+10, 20, 6, 20,
 +                      NL80211_RRF_NO_IR | NL80211_RRF_AUTO_BW),
                /* IEEE 802.11 channel 14 - Only JP enables
                 * this and for 802.11b only */
                REG_RULE(2484-10, 2484+10, 20, 6, 20,
                        NL80211_RRF_NO_IR |
                        NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..48 */
 -              REG_RULE(5180-10, 5240+10, 160, 6, 20,
 -                        NL80211_RRF_NO_IR),
 +              REG_RULE(5180-10, 5240+10, 80, 6, 20,
 +                        NL80211_RRF_NO_IR |
 +                        NL80211_RRF_AUTO_BW),
  
                /* IEEE 802.11a, channel 52..64 - DFS required */
 -              REG_RULE(5260-10, 5320+10, 160, 6, 20,
 +              REG_RULE(5260-10, 5320+10, 80, 6, 20,
                        NL80211_RRF_NO_IR |
 +                      NL80211_RRF_AUTO_BW |
                        NL80211_RRF_DFS),
  
                /* IEEE 802.11a, channel 100..144 - DFS required */
@@@ -543,7 -532,7 +534,7 @@@ static DECLARE_DELAYED_WORK(crda_timeou
  
  static void crda_timeout_work(struct work_struct *work)
  {
-       REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
        rtnl_lock();
        reg_crda_timeouts++;
        restore_regulatory_settings(true);
@@@ -585,7 -574,7 +576,7 @@@ static int call_crda(const char *alpha2
  
        if (!is_world_regdom((char *) alpha2))
                pr_debug("Calling CRDA for country: %c%c\n",
-                       alpha2[0], alpha2[1]);
+                        alpha2[0], alpha2[1]);
        else
                pr_debug("Calling CRDA to update world regulatory domain\n");
  
@@@ -1132,42 -1121,6 +1123,6 @@@ const char *reg_initiator_name(enum nl8
  }
  EXPORT_SYMBOL(reg_initiator_name);
  
- static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
-                                   struct ieee80211_channel *chan,
-                                   const struct ieee80211_reg_rule *reg_rule)
- {
- #ifdef CONFIG_CFG80211_REG_DEBUG
-       const struct ieee80211_power_rule *power_rule;
-       const struct ieee80211_freq_range *freq_range;
-       char max_antenna_gain[32], bw[32];
-       power_rule = &reg_rule->power_rule;
-       freq_range = &reg_rule->freq_range;
-       if (!power_rule->max_antenna_gain)
-               snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
-       else
-               snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d mBi",
-                        power_rule->max_antenna_gain);
-       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
-               snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
-                        freq_range->max_bandwidth_khz,
-                        reg_get_max_bandwidth(regd, reg_rule));
-       else
-               snprintf(bw, sizeof(bw), "%d KHz",
-                        freq_range->max_bandwidth_khz);
-       REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
-                     chan->center_freq);
-       REG_DBG_PRINT("(%d KHz - %d KHz @ %s), (%s, %d mBm)\n",
-                     freq_range->start_freq_khz, freq_range->end_freq_khz,
-                     bw, max_antenna_gain,
-                     power_rule->max_eirp);
- #endif
- }
  static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd,
                                          const struct ieee80211_reg_rule *reg_rule,
                                          const struct ieee80211_channel *chan)
@@@ -1242,20 -1195,19 +1197,19 @@@ static void handle_channel(struct wiph
                if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
                    request_wiphy && request_wiphy == wiphy &&
                    request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
-                       REG_DBG_PRINT("Disabling freq %d MHz for good\n",
-                                     chan->center_freq);
+                       pr_debug("Disabling freq %d MHz for good\n",
+                                chan->center_freq);
                        chan->orig_flags |= IEEE80211_CHAN_DISABLED;
                        chan->flags = chan->orig_flags;
                } else {
-                       REG_DBG_PRINT("Disabling freq %d MHz\n",
-                                     chan->center_freq);
+                       pr_debug("Disabling freq %d MHz\n",
+                                chan->center_freq);
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                }
                return;
        }
  
        regd = reg_get_regdomain(wiphy);
-       chan_reg_rule_print_dbg(regd, chan, reg_rule);
  
        power_rule = &reg_rule->power_rule;
        bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
@@@ -1393,18 -1345,15 +1347,15 @@@ static bool ignore_reg_update(struct wi
                return true;
  
        if (!lr) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since last_request is not set\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since last_request is not set\n",
+                        reg_initiator_name(initiator));
                return true;
        }
  
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
            wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since the driver uses its own custom "
-                             "regulatory domain\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since the driver uses its own custom regulatory domain\n",
+                        reg_initiator_name(initiator));
                return true;
        }
  
        if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
            initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
            !is_world_regdom(lr->alpha2)) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since the driver requires its own regulatory "
-                             "domain to be set first\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since the driver requires its own regulatory domain to be set first\n",
+                        reg_initiator_name(initiator));
                return true;
        }
  
@@@ -1699,7 -1646,7 +1648,7 @@@ static void reg_check_chans_work(struc
  {
        struct cfg80211_registered_device *rdev;
  
-       REG_DBG_PRINT("Verifying active interfaces after reg change\n");
+       pr_debug("Verifying active interfaces after reg change\n");
        rtnl_lock();
  
        list_for_each_entry(rdev, &cfg80211_rdev_list, list)
@@@ -1781,8 -1728,8 +1730,8 @@@ static void handle_channel_custom(struc
        }
  
        if (IS_ERR(reg_rule)) {
-               REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
-                             chan->center_freq);
+               pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
+                        chan->center_freq);
                if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                } else {
                return;
        }
  
-       chan_reg_rule_print_dbg(regd, chan, reg_rule);
        power_rule = &reg_rule->power_rule;
        bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
  
@@@ -2524,7 -2469,7 +2471,7 @@@ static void restore_alpha2(char *alpha2
        if (is_user_regdom_saved()) {
                /* Unless we're asked to ignore it and reset it */
                if (reset_user) {
-                       REG_DBG_PRINT("Restoring regulatory settings including user preference\n");
+                       pr_debug("Restoring regulatory settings including user preference\n");
                        user_alpha2[0] = '9';
                        user_alpha2[1] = '7';
  
                         * back as they were for a full restore.
                         */
                        if (!is_world_regdom(ieee80211_regdom)) {
-                               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
-                                             ieee80211_regdom[0], ieee80211_regdom[1]);
+                               pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                                        ieee80211_regdom[0], ieee80211_regdom[1]);
                                alpha2[0] = ieee80211_regdom[0];
                                alpha2[1] = ieee80211_regdom[1];
                        }
                } else {
-                       REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n",
-                                     user_alpha2[0], user_alpha2[1]);
+                       pr_debug("Restoring regulatory settings while preserving user preference for: %c%c\n",
+                                user_alpha2[0], user_alpha2[1]);
                        alpha2[0] = user_alpha2[0];
                        alpha2[1] = user_alpha2[1];
                }
        } else if (!is_world_regdom(ieee80211_regdom)) {
-               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
-                             ieee80211_regdom[0], ieee80211_regdom[1]);
+               pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                        ieee80211_regdom[0], ieee80211_regdom[1]);
                alpha2[0] = ieee80211_regdom[0];
                alpha2[1] = ieee80211_regdom[1];
        } else
-               REG_DBG_PRINT("Restoring regulatory settings\n");
+               pr_debug("Restoring regulatory settings\n");
  }
  
  static void restore_custom_reg_settings(struct wiphy *wiphy)
@@@ -2663,14 -2608,14 +2610,14 @@@ static void restore_regulatory_settings
        list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);
        spin_unlock(&reg_requests_lock);
  
-       REG_DBG_PRINT("Kicking the queue\n");
+       pr_debug("Kicking the queue\n");
  
        schedule_work(&reg_work);
  }
  
  void regulatory_hint_disconnect(void)
  {
-       REG_DBG_PRINT("All devices are disconnected, going to restore regulatory settings\n");
+       pr_debug("All devices are disconnected, going to restore regulatory settings\n");
        restore_regulatory_settings(false);
  }
  
@@@ -2718,10 -2663,10 +2665,10 @@@ int regulatory_hint_found_beacon(struc
        if (!reg_beacon)
                return -ENOMEM;
  
-       REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
-                     beacon_chan->center_freq,
-                     ieee80211_frequency_to_channel(beacon_chan->center_freq),
-                     wiphy_name(wiphy));
+       pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
+                beacon_chan->center_freq,
+                ieee80211_frequency_to_channel(beacon_chan->center_freq),
+                wiphy_name(wiphy));
  
        memcpy(&reg_beacon->chan, beacon_chan,
               sizeof(struct ieee80211_channel));
@@@ -2747,7 -2692,7 +2694,7 @@@ static void print_rd_rules(const struc
        const struct ieee80211_power_rule *power_rule = NULL;
        char bw[32], cac_time[32];
  
 -      pr_info("  (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
 +      pr_debug("  (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
  
        for (i = 0; i < rd->n_reg_rules; i++) {
                reg_rule = &rd->reg_rules[i];
                 * in certain regions
                 */
                if (power_rule->max_antenna_gain)
 -                      pr_info("  (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
 +                      pr_debug("  (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
                                bw,
                                power_rule->max_eirp,
                                cac_time);
                else
 -                      pr_info("  (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
 +                      pr_debug("  (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
                                bw,
@@@ -2800,8 -2745,7 +2747,7 @@@ bool reg_supported_dfs_region(enum nl80
        case NL80211_DFS_JP:
                return true;
        default:
-               REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
-                             dfs_region);
+               pr_debug("Ignoring uknown DFS master region: %d\n", dfs_region);
                return false;
        }
  }
@@@ -2815,35 -2759,35 +2761,35 @@@ static void print_regdomain(const struc
                        struct cfg80211_registered_device *rdev;
                        rdev = cfg80211_rdev_by_wiphy_idx(lr->wiphy_idx);
                        if (rdev) {
 -                              pr_info("Current regulatory domain updated by AP to: %c%c\n",
 +                              pr_debug("Current regulatory domain updated by AP to: %c%c\n",
                                        rdev->country_ie_alpha2[0],
                                        rdev->country_ie_alpha2[1]);
                        } else
 -                              pr_info("Current regulatory domain intersected:\n");
 +                              pr_debug("Current regulatory domain intersected:\n");
                } else
 -                      pr_info("Current regulatory domain intersected:\n");
 +                      pr_debug("Current regulatory domain intersected:\n");
        } else if (is_world_regdom(rd->alpha2)) {
 -              pr_info("World regulatory domain updated:\n");
 +              pr_debug("World regulatory domain updated:\n");
        } else {
                if (is_unknown_alpha2(rd->alpha2))
 -                      pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
 +                      pr_debug("Regulatory domain changed to driver built-in settings (unknown country)\n");
                else {
                        if (reg_request_cell_base(lr))
 -                              pr_info("Regulatory domain changed to country: %c%c by Cell Station\n",
 +                              pr_debug("Regulatory domain changed to country: %c%c by Cell Station\n",
                                        rd->alpha2[0], rd->alpha2[1]);
                        else
 -                              pr_info("Regulatory domain changed to country: %c%c\n",
 +                              pr_debug("Regulatory domain changed to country: %c%c\n",
                                        rd->alpha2[0], rd->alpha2[1]);
                }
        }
  
 -      pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));
 +      pr_debug(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));
        print_rd_rules(rd);
  }
  
  static void print_regdomain_info(const struct ieee80211_regdomain *rd)
  {
 -      pr_info("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]);
 +      pr_debug("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]);
        print_rd_rules(rd);
  }
  
@@@ -2864,8 -2808,7 +2810,8 @@@ static int reg_set_rd_user(const struc
                return -EALREADY;
  
        if (!is_valid_rd(rd)) {
 -              pr_err("Invalid regulatory domain detected:\n");
 +              pr_err("Invalid regulatory domain detected: %c%c\n",
 +                     rd->alpha2[0], rd->alpha2[1]);
                print_regdomain_info(rd);
                return -EINVAL;
        }
@@@ -2901,8 -2844,7 +2847,8 @@@ static int reg_set_rd_driver(const stru
                return -EALREADY;
  
        if (!is_valid_rd(rd)) {
 -              pr_err("Invalid regulatory domain detected:\n");
 +              pr_err("Invalid regulatory domain detected: %c%c\n",
 +                     rd->alpha2[0], rd->alpha2[1]);
                print_regdomain_info(rd);
                return -EINVAL;
        }
@@@ -2960,8 -2902,7 +2906,8 @@@ static int reg_set_rd_country_ie(const 
         */
  
        if (!is_valid_rd(rd)) {
 -              pr_err("Invalid regulatory domain detected:\n");
 +              pr_err("Invalid regulatory domain detected: %c%c\n",
 +                     rd->alpha2[0], rd->alpha2[1]);
                print_regdomain_info(rd);
                return -EINVAL;
        }