]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge remote-tracking branch 'iwlwifi-fixes/master' into HEAD
authorJohannes Berg <johannes.berg@intel.com>
Mon, 27 May 2013 11:30:49 +0000 (13:30 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 May 2013 11:30:49 +0000 (13:30 +0200)
Conflicts:
drivers/net/wireless/iwlwifi/mvm/ops.c

1  2 
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c

index 6031dbf83a964ba0dc8603c1c1436f95f971408a,c6384555aab4de0172c7f1a7c5662cce776e76ed..733153c3b66c040cd2843163c95898f2b2ccf940
@@@ -170,11 -170,11 +170,13 @@@ enum 
        BT_COEX_PROT_ENV = 0xcd,
        BT_PROFILE_NOTIFICATION = 0xce,
  
 +      REPLY_BEACON_FILTERING_CMD = 0xd2,
 +
        REPLY_DEBUG_CMD = 0xf0,
        DEBUG_LOG_MSG = 0xf7,
  
+       MCAST_FILTER_CMD = 0xd0,
        /* D3 commands/notifications */
        D3_CONFIG_CMD = 0xd3,
        PROT_OFFLOAD_CONFIG_CMD = 0xd4,
@@@ -950,4 -950,29 +952,29 @@@ struct iwl_set_calib_default_cmd 
        u8 data[0];
  } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
  
+ #define MAX_PORT_ID_NUM       2
+ /**
+  * struct iwl_mcast_filter_cmd - configure multicast filter.
+  * @filter_own: Set 1 to filter out multicast packets sent by station itself
+  * @port_id:  Multicast MAC addresses array specifier. This is a strange way
+  *            to identify network interface adopted in host-device IF.
+  *            It is used by FW as index in array of addresses. This array has
+  *            MAX_PORT_ID_NUM members.
+  * @count:    Number of MAC addresses in the array
+  * @pass_all: Set 1 to pass all multicast packets.
+  * @bssid:    current association BSSID.
+  * @addr_list:        Place holder for array of MAC addresses.
+  *            IMPORTANT: add padding if necessary to ensure DWORD alignment.
+  */
+ struct iwl_mcast_filter_cmd {
+       u8 filter_own;
+       u8 port_id;
+       u8 count;
+       u8 pass_all;
+       u8 bssid[6];
+       u8 reserved[2];
+       u8 addr_list[0];
+ } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
  #endif /* __fw_api_h__ */
index fe22772f3421c33ebed816a7cd124d2a698527b5,a5eb8c82f16a806fea43738629e738cdeaaba0b6..c9924c12e0fec5f0bf152595051cf4a733e134b0
@@@ -127,17 -127,6 +127,17 @@@ static const struct wiphy_wowlan_tcp_su
  };
  #endif
  
 +static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
 +{
 +      int i;
 +
 +      memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts));
 +      for (i = 0; i < NUM_PHY_CTX; i++) {
 +              mvm->phy_ctxts[i].id = i;
 +              mvm->phy_ctxts[i].ref = 0;
 +      }
 +}
 +
  int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
  {
        struct ieee80211_hw *hw = mvm->hw;
  
        hw->sta_data_size = sizeof(struct iwl_mvm_sta);
        hw->vif_data_size = sizeof(struct iwl_mvm_vif);
 -      hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt);
 +      hw->chanctx_data_size = sizeof(u16);
  
        hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_P2P_CLIENT) |
                hw->wiphy->n_addresses++;
        }
  
 +      iwl_mvm_reset_phy_ctxts(mvm);
 +
        /* we create the 802.11 header and a max-length SSID element */
        hw->wiphy->max_scan_ie_len =
                mvm->fw->ucode_capa.max_probe_length - 24 - 34;
@@@ -358,7 -345,8 +358,7 @@@ static void iwl_mvm_cleanup_iterator(vo
        iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
        spin_unlock_bh(&mvm->time_event_lock);
  
 -      if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
 -              mvmvif->phy_ctxt = NULL;
 +      mvmvif->phy_ctxt = NULL;
  }
  
  static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
                mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
                iwl_mvm_cleanup_iterator, mvm);
  
 +      mvm->p2p_device_vif = NULL;
 +
 +      iwl_mvm_reset_phy_ctxts(mvm);
        memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
        memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
  
@@@ -471,20 -456,6 +471,20 @@@ static void iwl_mvm_power_update_iterat
        iwl_mvm_power_update_mode(mvm, vif);
  }
  
 +static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
 +{
 +      u16 i;
 +
 +      lockdep_assert_held(&mvm->mutex);
 +
 +      for (i = 0; i < NUM_PHY_CTX; i++)
 +              if (!mvm->phy_ctxts[i].ref)
 +                      return &mvm->phy_ctxts[i];
 +
 +      IWL_ERR(mvm, "No available PHY context\n");
 +      return NULL;
 +}
 +
  static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
  {
         */
        iwl_mvm_power_update_mode(mvm, vif);
  
 +      /* beacon filtering */
 +      if (!mvm->bf_allowed_vif &&
 +          vif->type == NL80211_IFTYPE_STATION && !vif->p2p){
 +              mvm->bf_allowed_vif = mvmvif;
 +              vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
 +      }
 +
 +      ret = iwl_mvm_disable_beacon_filter(mvm, vif);
 +      if (ret)
 +              goto out_release;
 +
        /*
         * P2P_DEVICE interface does not have a channel context assigned to it,
         * so a dedicated PHY context is allocated to it and the corresponding
         * MAC context is bound to it at this stage.
         */
        if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
 -              struct ieee80211_channel *chan;
 -              struct cfg80211_chan_def chandef;
  
 -              mvmvif->phy_ctxt = &mvm->phy_ctxt_roc;
 -
 -              /*
 -               * The channel used here isn't relevant as it's
 -               * going to be overwritten as part of the ROC flow.
 -               * For now use the first channel we have.
 -               */
 -              chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
 -              cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
 -              ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt,
 -                                         &chandef, 1, 1);
 -              if (ret)
 +              mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
 +              if (!mvmvif->phy_ctxt) {
 +                      ret = -ENOSPC;
                        goto out_remove_mac;
 +              }
  
 +              iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
                ret = iwl_mvm_binding_add_vif(mvm, vif);
                if (ret)
 -                      goto out_remove_phy;
 +                      goto out_unref_phy;
  
                ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
                if (ret)
  
   out_unbind:
        iwl_mvm_binding_remove_vif(mvm, vif);
 - out_remove_phy:
 -      iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
 + out_unref_phy:
 +      iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
   out_remove_mac:
        mvmvif->phy_ctxt = NULL;
        iwl_mvm_mac_ctxt_remove(mvm, vif);
@@@ -677,11 -646,6 +677,11 @@@ static void iwl_mvm_mac_remove_interfac
  
        mutex_lock(&mvm->mutex);
  
 +      if (mvm->bf_allowed_vif == mvmvif) {
 +              mvm->bf_allowed_vif = NULL;
 +              vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
 +      }
 +
        iwl_mvm_vif_dbgfs_clean(mvm, vif);
  
        /*
                mvm->p2p_device_vif = NULL;
                iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
                iwl_mvm_binding_remove_vif(mvm, vif);
 -              iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
 +              iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
                mvmvif->phy_ctxt = NULL;
        }
  
@@@ -737,6 -701,20 +737,20 @@@ static void iwl_mvm_configure_filter(st
        *total_flags = 0;
  }
  
+ static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif)
+ {
+       struct iwl_mcast_filter_cmd mcast_filter_cmd = {
+               .pass_all = 1,
+       };
+       memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
+       return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
+                                   sizeof(mcast_filter_cmd),
+                                   &mcast_filter_cmd);
+ }
  static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                             struct ieee80211_vif *vif,
                                             struct ieee80211_bss_conf *bss_conf,
                                return;
                        }
                        iwl_mvm_bt_coex_vif_assoc(mvm, vif);
+                       iwl_mvm_configure_mcast_filter(mvm, vif);
                } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                        /* remove AP station now that the MAC is unassoc */
                        ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@@@ -967,7 -946,7 +982,7 @@@ static void iwl_mvm_mac_sta_notify(stru
  
        switch (cmd) {
        case STA_NOTIFY_SLEEP:
-               if (atomic_read(&mvmsta->pending_frames) > 0)
+               if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
                        ieee80211_sta_block_awake(hw, sta, true);
                /*
                 * The fw updates the STA to be asleep. Tx packets on the Tx
@@@ -1020,13 -999,9 +1035,13 @@@ static int iwl_mvm_mac_sta_state(struc
                                             mvmvif->phy_ctxt->channel->band);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTHORIZED) {
 +              /* enable beacon filtering */
 +              WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTHORIZED &&
                   new_state == IEEE80211_STA_ASSOC) {
 +              /* disable beacon filtering */
 +              WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif));
                ret = 0;
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH) {
@@@ -1192,107 -1167,29 +1207,107 @@@ static int iwl_mvm_roc(struct ieee80211
                       enum ieee80211_roc_type type)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +      struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct cfg80211_chan_def chandef;
 -      int ret;
 +      struct iwl_mvm_phy_ctxt *phy_ctxt;
 +      int ret, i;
 +
 +      IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
 +                         duration, type);
  
        if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
                IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
                return -EINVAL;
        }
  
 -      IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
 -                         duration, type);
 -
        mutex_lock(&mvm->mutex);
  
 +      for (i = 0; i < NUM_PHY_CTX; i++) {
 +              phy_ctxt = &mvm->phy_ctxts[i];
 +              if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
 +                      continue;
 +
 +              if (phy_ctxt->ref && channel == phy_ctxt->channel) {
 +                      /*
 +                       * Unbind the P2P_DEVICE from the current PHY context,
 +                       * and if the PHY context is not used remove it.
 +                       */
 +                      ret = iwl_mvm_binding_remove_vif(mvm, vif);
 +                      if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
 +                              goto out_unlock;
 +
 +                      iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
 +
 +                      /* Bind the P2P_DEVICE to the current PHY Context */
 +                      mvmvif->phy_ctxt = phy_ctxt;
 +
 +                      ret = iwl_mvm_binding_add_vif(mvm, vif);
 +                      if (WARN(ret, "Failed binding P2P_DEVICE\n"))
 +                              goto out_unlock;
 +
 +                      iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
 +                      goto schedule_time_event;
 +              }
 +      }
 +
 +      /* Need to update the PHY context only if the ROC channel changed */
 +      if (channel == mvmvif->phy_ctxt->channel)
 +              goto schedule_time_event;
 +
        cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
 -      ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc,
 -                                     &chandef, 1, 1);
  
 +      /*
 +       * Change the PHY context configuration as it is currently referenced
 +       * only by the P2P Device MAC
 +       */
 +      if (mvmvif->phy_ctxt->ref == 1) {
 +              ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt,
 +                                             &chandef, 1, 1);
 +              if (ret)
 +                      goto out_unlock;
 +      } else {
 +              /*
 +               * The PHY context is shared with other MACs. Need to remove the
 +               * P2P Device from the binding, allocate an new PHY context and
 +               * create a new binding
 +               */
 +              phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
 +              if (!phy_ctxt) {
 +                      ret = -ENOSPC;
 +                      goto out_unlock;
 +              }
 +
 +              ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef,
 +                                             1, 1);
 +              if (ret) {
 +                      IWL_ERR(mvm, "Failed to change PHY context\n");
 +                      goto out_unlock;
 +              }
 +
 +              /* Unbind the P2P_DEVICE from the current PHY context */
 +              ret = iwl_mvm_binding_remove_vif(mvm, vif);
 +              if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
 +                      goto out_unlock;
 +
 +              iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
 +
 +              /* Bind the P2P_DEVICE to the new allocated PHY context */
 +              mvmvif->phy_ctxt = phy_ctxt;
 +
 +              ret = iwl_mvm_binding_add_vif(mvm, vif);
 +              if (WARN(ret, "Failed binding P2P_DEVICE\n"))
 +                      goto out_unlock;
 +
 +              iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
 +      }
 +
 +schedule_time_event:
        /* Schedule the time events */
        ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);
  
 +out_unlock:
        mutex_unlock(&mvm->mutex);
        IWL_DEBUG_MAC80211(mvm, "leave\n");
 -
        return ret;
  }
  
@@@ -1314,30 -1211,15 +1329,30 @@@ static int iwl_mvm_add_chanctx(struct i
                               struct ieee80211_chanctx_conf *ctx)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 -      struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
 +      u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
 +      struct iwl_mvm_phy_ctxt *phy_ctxt;
        int ret;
  
 +      IWL_DEBUG_MAC80211(mvm, "Add channel context\n");
 +
        mutex_lock(&mvm->mutex);
 +      phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
 +      if (!phy_ctxt) {
 +              ret = -ENOSPC;
 +              goto out;
 +      }
 +
 +      ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
 +                                     ctx->rx_chains_static,
 +                                     ctx->rx_chains_dynamic);
 +      if (ret) {
 +              IWL_ERR(mvm, "Failed to add PHY context\n");
 +              goto out;
 +      }
  
 -      IWL_DEBUG_MAC80211(mvm, "Add PHY context\n");
 -      ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def,
 -                                 ctx->rx_chains_static,
 -                                 ctx->rx_chains_dynamic);
 +      iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt);
 +      *phy_ctxt_id = phy_ctxt->id;
 +out:
        mutex_unlock(&mvm->mutex);
        return ret;
  }
@@@ -1346,11 -1228,10 +1361,11 @@@ static void iwl_mvm_remove_chanctx(stru
                                   struct ieee80211_chanctx_conf *ctx)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 -      struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
 +      u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
 +      struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
  
        mutex_lock(&mvm->mutex);
 -      iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt);
 +      iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt);
        mutex_unlock(&mvm->mutex);
  }
  
@@@ -1359,16 -1240,7 +1374,16 @@@ static void iwl_mvm_change_chanctx(stru
                                   u32 changed)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 -      struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
 +      u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
 +      struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
 +
 +      if (WARN_ONCE((phy_ctxt->ref > 1) &&
 +                    (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
 +                                 IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
 +                                 IEEE80211_CHANCTX_CHANGE_RADAR)),
 +                    "Cannot change PHY. Ref=%d, changed=0x%X\n",
 +                    phy_ctxt->ref, changed))
 +              return;
  
        mutex_lock(&mvm->mutex);
        iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
@@@ -1382,14 -1254,13 +1397,14 @@@ static int iwl_mvm_assign_vif_chanctx(s
                                      struct ieee80211_chanctx_conf *ctx)
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 -      struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv;
 +      u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
 +      struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
  
        mutex_lock(&mvm->mutex);
  
 -      mvmvif->phy_ctxt = phyctx;
 +      mvmvif->phy_ctxt = phy_ctxt;
  
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
index 02ba8303a09f5feff61278a0ade258000a2f4129,9f46b23801bc84187b6aba6ed4b89ca7149eafc6..4e87a321e107cbb9b4df17cf6eb3d694ea244907
@@@ -109,7 -109,6 +109,7 @@@ extern struct iwl_mvm_mod_params iwlmvm
  struct iwl_mvm_phy_ctxt {
        u16 id;
        u16 color;
 +      u32 ref;
  
        /*
         * TODO: This should probably be removed. Currently here only for rate
@@@ -173,8 -172,6 +173,8 @@@ struct iwl_mvm_vif 
        bool uploaded;
        bool ap_active;
        bool monitor_active;
 +      /* indicate whether beacon filtering is enabled */
 +      bool bf_enabled;
  
        u32 ap_beacon_time;
  
@@@ -269,12 -266,6 +269,12 @@@ struct iwl_mvm 
  
        unsigned long status;
  
 +      /*
 +       * for beacon filtering -
 +       * currently only one interface can be supported
 +       */
 +      struct iwl_mvm_vif *bf_allowed_vif;
 +
        enum iwl_ucode_type cur_ucode;
        bool ucode_loaded;
        bool init_ucode_run;
        struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
        struct work_struct sta_drained_wk;
        unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
+       atomic_t pending_frames[IWL_MVM_STATION_COUNT];
  
        /* configured by mac80211 */
        u32 rts_threshold;
        bool prevent_power_down_d3;
  #endif
  
 -      struct iwl_mvm_phy_ctxt phy_ctxt_roc;
 +      struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
  
        struct list_head time_event_list;
        spinlock_t time_event_lock;
  
  #ifdef CONFIG_PM_SLEEP
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
 +#ifdef CONFIG_IWLWIFI_DEBUGFS
 +      bool store_d3_resume_sram;
 +      void *d3_resume_sram;
 +#endif
  #endif
  
        /* BT-Coex */
@@@ -455,10 -443,8 +456,10 @@@ int iwl_mvm_phy_ctxt_add(struct iwl_mv
  int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
                             struct cfg80211_chan_def *chandef,
                             u8 chains_static, u8 chains_dynamic);
 -void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm,
 -                           struct iwl_mvm_phy_ctxt *ctxt);
 +void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm,
 +                        struct iwl_mvm_phy_ctxt *ctxt);
 +void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm,
 +                          struct iwl_mvm_phy_ctxt *ctxt);
  
  /* MAC (virtual interface) programming */
  int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@@@ -548,10 -534,4 +549,10 @@@ void iwl_mvm_bt_rssi_event(struct iwl_m
                           enum ieee80211_rssi_event rssi_event);
  void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
  
 +/* beacon filtering */
 +int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
 +                               struct ieee80211_vif *vif);
 +int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
 +                                struct ieee80211_vif *vif);
 +
  #endif /* __IWL_MVM_H__ */
index e3f69a08251d7f5101cac0642b4a40e7a594a3c6,b29c31a41594ecbfd66989e0eaaa020758007aac..7998baca5a8b73707e873e87a514077be1883725
@@@ -292,7 -292,7 +292,8 @@@ static const char *iwl_mvm_cmd_strings[
        CMD(BT_COEX_PROT_ENV),
        CMD(BT_PROFILE_NOTIFICATION),
        CMD(BT_CONFIG),
+       CMD(MCAST_FILTER_CMD),
 +      CMD(REPLY_BEACON_FILTERING_CMD),
  };
  #undef CMD
  
@@@ -396,8 -396,7 +397,8 @@@ iwl_op_mode_mvm_start(struct iwl_trans 
        mutex_lock(&mvm->mutex);
        err = iwl_run_init_mvm_ucode(mvm, true);
        mutex_unlock(&mvm->mutex);
 -      if (err && !iwlmvm_mod_params.init_dbg) {
 +      /* returns 0 if successful, 1 if success but in rfkill */
 +      if (err < 0 && !iwlmvm_mod_params.init_dbg) {
                IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
                goto out_free;
        }
@@@ -444,10 -443,6 +445,10 @@@ static void iwl_op_mode_mvm_stop(struc
  
        kfree(mvm->scan_cmd);
  
 +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
 +      kfree(mvm->d3_resume_sram);
 +#endif
 +
        iwl_trans_stop_hw(mvm->trans, true);
  
        iwl_phy_db_free(mvm->phy_db);