Merge branch 'iwlwifi-fixes' into iwlwifi-next
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 12 Mar 2015 12:38:26 +0000 (14:38 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 12 Mar 2015 12:38:26 +0000 (14:38 +0200)
1  2 
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/time-event.c

index c7358a9d5b7125741d51e3b8a402d3da6113e85d,7810c41cf9a7300e0d3b9bc16bca22a44188b463..770b0e2a9b46c36cf334105965f8c498f21dc668
  #include "mvm.h"
  #include "iwl-debug.h"
  
 -const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
 -      [BT_KILL_MSK_DEFAULT] = 0xfffffc00,
 -      [BT_KILL_MSK_NEVER] = 0xffffffff,
 -      [BT_KILL_MSK_ALWAYS] = 0,
 -};
 -
 -const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
 -      {
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -      },
 -      {
 -              BT_KILL_MSK_NEVER,
 -              BT_KILL_MSK_NEVER,
 -              BT_KILL_MSK_NEVER,
 -      },
 -      {
 -              BT_KILL_MSK_NEVER,
 -              BT_KILL_MSK_NEVER,
 -              BT_KILL_MSK_NEVER,
 -      },
 -      {
 -              BT_KILL_MSK_DEFAULT,
 -              BT_KILL_MSK_NEVER,
 -              BT_KILL_MSK_DEFAULT,
 -      },
 -};
 -
 -const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
 -      {
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -      },
 -      {
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -      },
 -      {
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_ALWAYS,
 -      },
 -      {
 -              BT_KILL_MSK_DEFAULT,
 -              BT_KILL_MSK_ALWAYS,
 -              BT_KILL_MSK_DEFAULT,
 -      },
 -};
 -
 -static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
 -      cpu_to_le32(0xf0f0f0f0), /* 50% */
 -      cpu_to_le32(0xc0c0c0c0), /* 25% */
 -      cpu_to_le32(0xfcfcfcfc), /* 75% */
 -      cpu_to_le32(0xfefefefe), /* 87.5% */
 -};
 -
 -static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
 -      {
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -      {
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -      {
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x40000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x44000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -};
 -
 -static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
 -      {
 -              /* Tight */
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaeaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xcc00ff28),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0xcc00aaaa),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0x00004000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -      {
 -              /* Loose */
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xcc00ff28),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0xcc00aaaa),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0x00000000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -      {
 -              /* Tx Tx disabled */
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xeeaaaaaa),
 -              cpu_to_le32(0xaaaaaaaa),
 -              cpu_to_le32(0xcc00ff28),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0xcc00aaaa),
 -              cpu_to_le32(0x0000aaaa),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xc0004000),
 -              cpu_to_le32(0xf0005000),
 -              cpu_to_le32(0xf0005000),
 -      },
 -};
 -
  /* 20MHz / 40MHz below / 40Mhz above*/
  static const __le64 iwl_ci_mask[][3] = {
        /* dummy entry for channel 0 */
@@@ -444,6 -596,14 +444,6 @@@ int iwl_send_bt_init_conf(struct iwl_mv
                goto send_cmd;
        }
  
 -      bt_cmd->max_kill = cpu_to_le32(5);
 -      bt_cmd->bt4_antenna_isolation_thr =
 -              cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS);
 -      bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
 -      bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
 -      bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
 -      bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
 -
        mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE;
        bt_cmd->mode = cpu_to_le32(mode);
  
                bt_cmd->enabled_modules |=
                        cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
  
 -      if (IWL_MVM_BT_COEX_CORUNNING)
 +      if (iwl_mvm_bt_is_plcr_supported(mvm))
                bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
  
        if (IWL_MVM_BT_COEX_MPLUT) {
  
        bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
  
 -      if (mvm->cfg->bt_shared_single_ant)
 -              memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
 -                     sizeof(iwl_single_shared_ant));
 -      else
 -              memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
 -                     sizeof(iwl_combined_lookup));
 -
 -      memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
 -             sizeof(iwl_bt_prio_boost));
 -      bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
 -      bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
 -
  send_cmd:
        memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
        memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
        return ret;
  }
  
 -static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm)
 -{
 -      struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
 -      u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
 -      u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut);
 -      u32 ag = le32_to_cpu(notif->bt_activity_grading);
 -      struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
 -      u8 ack_kill_msk[NUM_PHY_CTX] = {};
 -      u8 cts_kill_msk[NUM_PHY_CTX] = {};
 -      int i;
 -
 -      lockdep_assert_held(&mvm->mutex);
 -
 -      ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut];
 -      cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut];
 -
 -      ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut];
 -      cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut];
 -
 -      /* Don't send HCMD if there is no update */
 -      if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) ||
 -          !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk)))
 -              return 0;
 -
 -      memcpy(mvm->bt_ack_kill_msk, ack_kill_msk,
 -             sizeof(mvm->bt_ack_kill_msk));
 -      memcpy(mvm->bt_cts_kill_msk, cts_kill_msk,
 -             sizeof(mvm->bt_cts_kill_msk));
 -
 -      BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values));
 -
 -      for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) {
 -              cmd.boost_values[i].kill_ack_msk =
 -                      cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]);
 -              cmd.boost_values[i].kill_cts_msk =
 -                      cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]);
 -      }
 -
 -      return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0,
 -                                  sizeof(cmd), &cmd);
 -}
 -
  static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
                                       bool enable)
  {
@@@ -579,7 -793,8 +579,8 @@@ static void iwl_mvm_bt_notif_iterator(v
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
-       if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
+       if (mvmvif->phy_ctxt &&
+           IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
@@@ -736,6 -951,9 +737,6 @@@ static void iwl_mvm_bt_coex_notif_handl
                        IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
                memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
        }
 -
 -      if (iwl_mvm_bt_udpate_sw_boost(mvm))
 -              IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
  }
  
  int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
@@@ -856,6 -1074,9 +857,6 @@@ void iwl_mvm_bt_rssi_event(struct iwl_m
        ieee80211_iterate_active_interfaces_atomic(
                mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                iwl_mvm_bt_rssi_iterator, &data);
 -
 -      if (iwl_mvm_bt_udpate_sw_boost(mvm))
 -              IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
  }
  
  #define LINK_QUAL_AGG_TIME_LIMIT_DEF  (4000)
@@@ -1014,7 -1235,7 +1015,7 @@@ int iwl_mvm_rx_ant_coupling_notif(struc
        if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
                return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
  
 -      if (!IWL_MVM_BT_COEX_CORUNNING)
 +      if (!iwl_mvm_bt_is_plcr_supported(mvm))
                return 0;
  
        lockdep_assert_held(&mvm->mutex);
index 897dd5330b0dbcc3d2c4dad7d95b9638fc83b46b,542ee74f290aec1a3f356b3c69718b5029c4e708..4f303639147b94636c1663da0aada5ff325d3488
@@@ -288,65 -288,6 +288,65 @@@ static const __le64 iwl_ci_mask[][3] = 
        },
  };
  
 +enum iwl_bt_kill_msk {
 +      BT_KILL_MSK_DEFAULT,
 +      BT_KILL_MSK_NEVER,
 +      BT_KILL_MSK_ALWAYS,
 +      BT_KILL_MSK_MAX,
 +};
 +
 +static const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
 +      [BT_KILL_MSK_DEFAULT] = 0xfffffc00,
 +      [BT_KILL_MSK_NEVER] = 0xffffffff,
 +      [BT_KILL_MSK_ALWAYS] = 0,
 +};
 +
 +static const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
 +      {
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +      },
 +      {
 +              BT_KILL_MSK_NEVER,
 +              BT_KILL_MSK_NEVER,
 +              BT_KILL_MSK_NEVER,
 +      },
 +      {
 +              BT_KILL_MSK_NEVER,
 +              BT_KILL_MSK_NEVER,
 +              BT_KILL_MSK_NEVER,
 +      },
 +      {
 +              BT_KILL_MSK_DEFAULT,
 +              BT_KILL_MSK_NEVER,
 +              BT_KILL_MSK_DEFAULT,
 +      },
 +};
 +
 +static const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
 +      {
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +      },
 +      {
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +      },
 +      {
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_ALWAYS,
 +      },
 +      {
 +              BT_KILL_MSK_DEFAULT,
 +              BT_KILL_MSK_ALWAYS,
 +              BT_KILL_MSK_DEFAULT,
 +      },
 +};
 +
  struct corunning_block_luts {
        u8 range;
        __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
@@@ -678,7 -619,7 +678,7 @@@ int iwl_send_bt_init_conf_old(struct iw
        if (IWL_MVM_BT_COEX_SYNC2SCO)
                bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);
  
 -      if (IWL_MVM_BT_COEX_CORUNNING) {
 +      if (iwl_mvm_bt_is_plcr_supported(mvm)) {
                bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 |
                                                     BT_VALID_CORUN_LUT_40);
                bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);
        if (IWL_MVM_BT_COEX_TTC)
                bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC);
  
 -      if (IWL_MVM_BT_COEX_RRC)
 +      if (iwl_mvm_bt_is_rrc_supported(mvm))
                bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC);
  
        if (mvm->cfg->bt_shared_single_ant)
@@@ -891,7 -832,8 +891,8 @@@ static void iwl_mvm_bt_notif_iterator(v
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
-       if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
+       if (mvmvif->phy_ctxt &&
+           data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
        IWL_DEBUG_COEX(data->mvm,
@@@ -1226,10 -1168,16 +1227,10 @@@ bool iwl_mvm_bt_coex_is_mimo_allowed_ol
        return lut_type != BT_COEX_LOOSE_LUT;
  }
  
 -bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant)
 -{
 -      u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
 -      return ag < BT_HIGH_TRAFFIC;
 -}
 -
  bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
  {
        u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
 -      return ag == BT_OFF;
 +      return ag < BT_HIGH_TRAFFIC;
  }
  
  bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,
@@@ -1266,7 -1214,7 +1267,7 @@@ int iwl_mvm_rx_ant_coupling_notif_old(s
                .dataflags = { IWL_HCMD_DFL_NOCOPY, },
        };
  
 -      if (!IWL_MVM_BT_COEX_CORUNNING)
 +      if (!iwl_mvm_bt_is_plcr_supported(mvm))
                return 0;
  
        lockdep_assert_held(&mvm->mutex);
index 6b3f4d0284a71f1971cd789fd7edfe316b911da5,09654e73a533f7733c2a5b1e47bf6251d6267585..302c8cc50f25a695c40ce59555f8a05bf58cae2d
@@@ -86,7 -86,6 +86,7 @@@
  #include "iwl-fw-error-dump.h"
  #include "iwl-prph.h"
  #include "iwl-csr.h"
 +#include "iwl-nvm-parse.h"
  
  static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
        {
@@@ -302,109 -301,6 +302,109 @@@ static void iwl_mvm_reset_phy_ctxts(str
        }
  }
  
 +struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
 +                                                const char *alpha2,
 +                                                enum iwl_mcc_source src_id,
 +                                                bool *changed)
 +{
 +      struct ieee80211_regdomain *regd = NULL;
 +      struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 +      struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +      struct iwl_mcc_update_resp *resp;
 +
 +      IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);
 +
 +      lockdep_assert_held(&mvm->mutex);
 +
 +      resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
 +      if (IS_ERR_OR_NULL(resp)) {
 +              IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
 +                            PTR_RET(resp));
 +              goto out;
 +      }
 +
 +      if (changed)
 +              *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
 +
 +      regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
 +                                    __le32_to_cpu(resp->n_channels),
 +                                    resp->channels,
 +                                    __le16_to_cpu(resp->mcc));
 +      /* Store the return source id */
 +      src_id = resp->source_id;
 +      kfree(resp);
 +      if (IS_ERR_OR_NULL(regd)) {
 +              IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
 +                            PTR_RET(regd));
 +              goto out;
 +      }
 +
 +      IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n",
 +                    regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id);
 +      mvm->lar_regdom_set = true;
 +      mvm->mcc_src = src_id;
 +
 +out:
 +      return regd;
 +}
 +
 +void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm)
 +{
 +      bool changed;
 +      struct ieee80211_regdomain *regd;
 +
 +      if (!iwl_mvm_is_lar_supported(mvm))
 +              return;
 +
 +      regd = iwl_mvm_get_current_regdomain(mvm, &changed);
 +      if (!IS_ERR_OR_NULL(regd)) {
 +              /* only update the regulatory core if changed */
 +              if (changed)
 +                      regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
 +
 +              kfree(regd);
 +      }
 +}
 +
 +struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
 +                                                        bool *changed)
 +{
 +      return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",
 +                                   iwl_mvm_is_wifi_mcc_supported(mvm) ?
 +                                   MCC_SOURCE_GET_CURRENT :
 +                                   MCC_SOURCE_OLD_FW, changed);
 +}
 +
 +int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
 +{
 +      enum iwl_mcc_source used_src;
 +      struct ieee80211_regdomain *regd;
 +      const struct ieee80211_regdomain *r =
 +                      rtnl_dereference(mvm->hw->wiphy->regd);
 +
 +      if (!r)
 +              return 0;
 +
 +      /* save the last source in case we overwrite it below */
 +      used_src = mvm->mcc_src;
 +      if (iwl_mvm_is_wifi_mcc_supported(mvm)) {
 +              /* Notify the firmware we support wifi location updates */
 +              regd = iwl_mvm_get_current_regdomain(mvm, NULL);
 +              if (!IS_ERR_OR_NULL(regd))
 +                      kfree(regd);
 +      }
 +
 +      /* Now set our last stored MCC and source */
 +      regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL);
 +      if (IS_ERR_OR_NULL(regd))
 +              return -EIO;
 +
 +      regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
 +      kfree(regd);
 +
 +      return 0;
 +}
 +
  int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
  {
        struct ieee80211_hw *hw = mvm->hw;
            !iwlwifi_mod_params.sw_crypto)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
  
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
 -          mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
 -              hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
 -              hw->wiphy->features |=
 -                      NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
 -                      NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
 -      }
 +      hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
 +      hw->wiphy->features |=
 +              NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
 +              NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
  
        hw->sta_data_size = sizeof(struct iwl_mvm_sta);
        hw->vif_data_size = sizeof(struct iwl_mvm_vif);
                BIT(NL80211_IFTYPE_ADHOC);
  
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 -      hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
 -                                     REGULATORY_DISABLE_BEACON_HINTS;
 +      hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
 +      if (iwl_mvm_is_lar_supported(mvm))
 +              hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
 +      else
 +              hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
 +                                             REGULATORY_DISABLE_BEACON_HINTS;
  
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
                hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
  
-               if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+               if ((mvm->fw->ucode_capa.capa[0] &
+                    IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+                   (mvm->fw->ucode_capa.api[0] &
+                    IWL_UCODE_TLV_API_LQ_SS_PARAMS))
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
                                IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
        }
@@@ -994,23 -892,12 +997,23 @@@ static void iwl_mvm_dump_fifos(struct i
        iwl_trans_release_nic_access(mvm->trans, &flags);
  }
  
 +void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
 +{
 +      if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert ||
 +          !mvm->fw_dump_desc)
 +              return;
 +
 +      kfree(mvm->fw_dump_desc);
 +      mvm->fw_dump_desc = NULL;
 +}
 +
  void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
  {
        struct iwl_fw_error_dump_file *dump_file;
        struct iwl_fw_error_dump_data *dump_data;
        struct iwl_fw_error_dump_info *dump_info;
        struct iwl_fw_error_dump_mem *dump_mem;
 +      struct iwl_fw_error_dump_trigger_desc *dump_trig;
        struct iwl_mvm_dump_ptrs *fw_error_dump;
        u32 sram_len, sram_ofs;
        u32 file_len, fifo_data_len = 0;
                   fifo_data_len +
                   sizeof(*dump_info);
  
 +      if (mvm->fw_dump_desc)
 +              file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
 +                          mvm->fw_dump_desc->len;
 +
        /* Make room for the SMEM, if it exists */
        if (smem_len)
                file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
        dump_file = vzalloc(file_len);
        if (!dump_file) {
                kfree(fw_error_dump);
 +              iwl_mvm_free_fw_dump_desc(mvm);
                return;
        }
  
        if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
                iwl_mvm_dump_fifos(mvm, &dump_data);
  
 +      if (mvm->fw_dump_desc) {
 +              dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
 +              dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
 +                                           mvm->fw_dump_desc->len);
 +              dump_trig = (void *)dump_data->data;
 +              memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc,
 +                     sizeof(*dump_trig) + mvm->fw_dump_desc->len);
 +
 +              /* now we can free this copy */
 +              iwl_mvm_free_fw_dump_desc(mvm);
 +              dump_data = iwl_fw_error_next_data(dump_data);
 +      }
 +
        dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
        dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
        dump_mem = (void *)dump_data->data;
  
        dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
                      GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
 +
 +      clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
  }
  
 +struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = {
 +      .trig_desc = {
 +              .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
 +      },
 +};
 +
  static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
  {
        /* clear the D3 reconfig, we only need it to avoid dumping a
         * firmware coredump on reconfiguration, we shouldn't do that
         * on D3->D0 transition
         */
 -      if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status))
 +      if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) {
 +              mvm->fw_dump_desc = &iwl_mvm_dump_desc_assert;
                iwl_mvm_fw_error_dump(mvm);
 +      }
  
        /* cleanup all stale references (scan, roc), but keep the
         * ucode_down ref until reconfig is complete
  
        mvm->vif_count = 0;
        mvm->rx_ba_sessions = 0;
 +      mvm->fw_dbg_conf = FW_DBG_INVALID;
 +
 +      /* keep statistics ticking */
 +      iwl_mvm_accu_radio_stats(mvm);
  }
  
  int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
@@@ -1298,7 -1153,7 +1301,7 @@@ static void iwl_mvm_restart_complete(st
  
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        iwl_mvm_d0i3_enable_tx(mvm, NULL);
 -      ret = iwl_mvm_update_quotas(mvm, NULL);
 +      ret = iwl_mvm_update_quotas(mvm, false, NULL);
        if (ret)
                IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
                        ret);
@@@ -1361,11 -1216,6 +1364,11 @@@ void __iwl_mvm_mac_stop(struct iwl_mvm 
  {
        lockdep_assert_held(&mvm->mutex);
  
 +      /* firmware counters are obviously reset now, but we shouldn't
 +       * partially track so also clear the fw_reset_accu counters.
 +       */
 +      memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));
 +
        /*
         * Disallow low power states when the FW is down by taking
         * the UCODE_DOWN ref. in case of ongoing hw restart the
@@@ -1405,8 -1255,7 +1408,8 @@@ static void iwl_mvm_mac_stop(struct iee
  
        flush_work(&mvm->d0i3_exit_work);
        flush_work(&mvm->async_handlers_wk);
 -      flush_work(&mvm->fw_error_dump_wk);
 +      cancel_delayed_work_sync(&mvm->fw_dump_wk);
 +      iwl_mvm_free_fw_dump_desc(mvm);
  
        mutex_lock(&mvm->mutex);
        __iwl_mvm_mac_stop(mvm);
@@@ -1454,8 -1303,6 +1457,8 @@@ static int iwl_mvm_mac_add_interface(st
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
  
 +      mvmvif->mvm = mvm;
 +
        /*
         * make sure D0i3 exit is completed, otherwise a target access
         * during tx queue configuration could be done when still in
  
        mutex_lock(&mvm->mutex);
  
 +      /* make sure that beacon statistics don't go backwards with FW reset */
 +      if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
 +              mvmvif->beacon_stats.accu_num_beacons +=
 +                      mvmvif->beacon_stats.num_beacons;
 +
        /* Allocate resources for the MAC context, and add it to the fw  */
        ret = iwl_mvm_mac_ctxt_init(mvm, vif);
        if (ret)
@@@ -1971,13 -1813,8 +1974,13 @@@ static void iwl_mvm_bss_info_changed_st
  
        if (changes & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
 +                      /* clear statistics to get clean beacon counter */
 +                      iwl_mvm_request_statistics(mvm, true);
 +                      memset(&mvmvif->beacon_stats, 0,
 +                             sizeof(mvmvif->beacon_stats));
 +
                        /* add quota for this interface */
 -                      ret = iwl_mvm_update_quotas(mvm, NULL);
 +                      ret = iwl_mvm_update_quotas(mvm, true, NULL);
                        if (ret) {
                                IWL_ERR(mvm, "failed to update quotas\n");
                                return;
                                mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
                        mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
                        /* remove quota for this interface */
 -                      ret = iwl_mvm_update_quotas(mvm, NULL);
 +                      ret = iwl_mvm_update_quotas(mvm, false, NULL);
                        if (ret)
                                IWL_ERR(mvm, "failed to update quotas\n");
  
@@@ -2148,7 -1985,7 +2151,7 @@@ static int iwl_mvm_start_ap_ibss(struc
        /* power updated needs to be done before quotas */
        iwl_mvm_power_update_mac(mvm);
  
 -      ret = iwl_mvm_update_quotas(mvm, NULL);
 +      ret = iwl_mvm_update_quotas(mvm, false, NULL);
        if (ret)
                goto out_quota_failed;
  
@@@ -2214,7 -2051,7 +2217,7 @@@ static void iwl_mvm_stop_ap_ibss(struc
        if (vif->p2p && mvm->p2p_device_vif)
                iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
  
 -      iwl_mvm_update_quotas(mvm, NULL);
 +      iwl_mvm_update_quotas(mvm, false, NULL);
        iwl_mvm_send_rm_bcast_sta(mvm, vif);
        iwl_mvm_binding_remove_vif(mvm, vif);
  
@@@ -2353,12 -2190,6 +2356,12 @@@ static int iwl_mvm_mac_hw_scan(struct i
  
        mutex_lock(&mvm->mutex);
  
 +      if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
 +              IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
 +              ret = -EBUSY;
 +              goto out;
 +      }
 +
        if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
                ret = -EBUSY;
                goto out;
  
        if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
                ret = iwl_mvm_scan_umac(mvm, vif, hw_req);
 -      else if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
 -              ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
        else
 -              ret = iwl_mvm_scan_request(mvm, vif, req);
 +              ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
  
        if (ret)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
@@@ -2385,7 -2218,19 +2388,19 @@@ static void iwl_mvm_mac_cancel_hw_scan(
  
        mutex_lock(&mvm->mutex);
  
-       iwl_mvm_cancel_scan(mvm);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a hw_scan when it's already stopped.  This can
+        * happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_scan_completed() and the userspace called
+        * cancel scan scan before ieee80211_scan_work() could run.
+        * To handle that, simply return if the scan is not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+           (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+               iwl_mvm_cancel_scan(mvm);
  
        mutex_unlock(&mvm->mutex);
  }
@@@ -2427,35 -2272,25 +2442,35 @@@ static void iwl_mvm_mac_sta_notify(stru
  {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 +      unsigned long txqs = 0, tids = 0;
        int tid;
  
 +      spin_lock_bh(&mvmsta->lock);
 +      for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
 +              struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
 +
 +              if (tid_data->state != IWL_AGG_ON &&
 +                  tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
 +                      continue;
 +
 +              __set_bit(tid_data->txq_id, &txqs);
 +
 +              if (iwl_mvm_tid_queued(tid_data) == 0)
 +                      continue;
 +
 +              __set_bit(tid, &tids);
 +      }
 +
        switch (cmd) {
        case STA_NOTIFY_SLEEP:
                if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
                        ieee80211_sta_block_awake(hw, sta, true);
 -              spin_lock_bh(&mvmsta->lock);
 -              for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
 -                      struct iwl_mvm_tid_data *tid_data;
  
 -                      tid_data = &mvmsta->tid_data[tid];
 -                      if (tid_data->state != IWL_AGG_ON &&
 -                          tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
 -                              continue;
 -                      if (iwl_mvm_tid_queued(tid_data) == 0)
 -                              continue;
 +              for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT)
                        ieee80211_sta_set_buffered(sta, tid, true);
 -              }
 -              spin_unlock_bh(&mvmsta->lock);
 +
 +              if (txqs)
 +                      iwl_trans_freeze_txq_timer(mvm->trans, txqs, true);
                /*
                 * The fw updates the STA to be asleep. Tx packets on the Tx
                 * queues to this station will not be transmitted. The fw will
        case STA_NOTIFY_AWAKE:
                if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
                        break;
 +
 +              if (txqs)
 +                      iwl_trans_freeze_txq_timer(mvm->trans, txqs, false);
                iwl_mvm_sta_modify_ps_wake(mvm, sta);
                break;
        default:
                break;
        }
 +      spin_unlock_bh(&mvmsta->lock);
  }
  
  static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
@@@ -2711,13 -2542,13 +2726,13 @@@ static int iwl_mvm_mac_sched_scan_start
  
        mutex_lock(&mvm->mutex);
  
 -      /* Newest FW fixes sched scan while connected on another interface */
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
 -              if (!vif->bss_conf.idle) {
 -                      ret = -EBUSY;
 -                      goto out;
 -              }
 -      } else if (!iwl_mvm_is_idle(mvm)) {
 +      if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
 +              IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
 +              ret = -EBUSY;
 +              goto out;
 +      }
 +
 +      if (!vif->bss_conf.idle) {
                ret = -EBUSY;
                goto out;
        }
@@@ -2743,12 -2574,29 +2758,29 @@@ static int iwl_mvm_mac_sched_scan_stop(
        int ret;
  
        mutex_lock(&mvm->mutex);
+       /* Due to a race condition, it's possible that mac80211 asks
+        * us to stop a sched_scan when it's already stopped.  This
+        * can happen, for instance, if we stopped the scan ourselves,
+        * called ieee80211_sched_scan_stopped() and the userspace called
+        * stop sched scan scan before ieee80211_sched_scan_stopped_work()
+        * could run.  To handle this, simply return if the scan is
+        * not running.
+       */
+       /* FIXME: for now, we ignore this race for UMAC scans, since
+        * they don't set the scan_status.
+        */
+       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+           !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+               mutex_unlock(&mvm->mutex);
+               return 0;
+       }
        ret = iwl_mvm_scan_offload_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
  
        return ret;
  }
  
  static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
@@@ -3261,14 -3109,14 +3293,14 @@@ static int __iwl_mvm_assign_vif_chanctx
         */
        if (vif->type == NL80211_IFTYPE_MONITOR) {
                mvmvif->monitor_active = true;
 -              ret = iwl_mvm_update_quotas(mvm, NULL);
 +              ret = iwl_mvm_update_quotas(mvm, false, NULL);
                if (ret)
                        goto out_remove_binding;
        }
  
        /* Handle binding during CSA */
        if (vif->type == NL80211_IFTYPE_AP) {
 -              iwl_mvm_update_quotas(mvm, NULL);
 +              iwl_mvm_update_quotas(mvm, false, NULL);
                iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
        }
  
  
                iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
  
 -              iwl_mvm_update_quotas(mvm, NULL);
 +              iwl_mvm_update_quotas(mvm, false, NULL);
        }
  
        goto out;
@@@ -3365,7 -3213,7 +3397,7 @@@ static void __iwl_mvm_unassign_vif_chan
                break;
        }
  
 -      iwl_mvm_update_quotas(mvm, disabled_vif);
 +      iwl_mvm_update_quotas(mvm, false, disabled_vif);
        iwl_mvm_binding_remove_vif(mvm, vif);
  
  out:
@@@ -3557,7 -3405,7 +3589,7 @@@ static int __iwl_mvm_mac_testmode_cmd(s
                mvm->noa_duration = noa_duration;
                mvm->noa_vif = vif;
  
 -              return iwl_mvm_update_quotas(mvm, NULL);
 +              return iwl_mvm_update_quotas(mvm, false, NULL);
        case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
                /* must be associated client vif - ignore authorized */
                if (!vif || vif->type != NL80211_IFTYPE_STATION ||
@@@ -3617,9 -3465,6 +3649,9 @@@ static int iwl_mvm_pre_channel_switch(s
        IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n",
                           chsw->chandef.center_freq1);
  
 +      iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH,
 +                                     NULL, 0);
 +
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
                csa_vif =
@@@ -3768,95 -3613,6 +3800,95 @@@ static void iwl_mvm_mac_flush(struct ie
        }
  }
  
 +static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
 +                                struct survey_info *survey)
 +{
 +      struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +      int ret;
 +
 +      memset(survey, 0, sizeof(*survey));
 +
 +      /* only support global statistics right now */
 +      if (idx != 0)
 +              return -ENOENT;
 +
 +      if (!(mvm->fw->ucode_capa.capa[0] &
 +                      IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
 +              return -ENOENT;
 +
 +      mutex_lock(&mvm->mutex);
 +
 +      if (mvm->ucode_loaded) {
 +              ret = iwl_mvm_request_statistics(mvm, false);
 +              if (ret)
 +                      goto out;
 +      }
 +
 +      survey->filled = SURVEY_INFO_TIME |
 +                       SURVEY_INFO_TIME_RX |
 +                       SURVEY_INFO_TIME_TX |
 +                       SURVEY_INFO_TIME_SCAN;
 +      survey->time = mvm->accu_radio_stats.on_time_rf +
 +                     mvm->radio_stats.on_time_rf;
 +      do_div(survey->time, USEC_PER_MSEC);
 +
 +      survey->time_rx = mvm->accu_radio_stats.rx_time +
 +                        mvm->radio_stats.rx_time;
 +      do_div(survey->time_rx, USEC_PER_MSEC);
 +
 +      survey->time_tx = mvm->accu_radio_stats.tx_time +
 +                        mvm->radio_stats.tx_time;
 +      do_div(survey->time_tx, USEC_PER_MSEC);
 +
 +      survey->time_scan = mvm->accu_radio_stats.on_time_scan +
 +                          mvm->radio_stats.on_time_scan;
 +      do_div(survey->time_scan, USEC_PER_MSEC);
 +
 + out:
 +      mutex_unlock(&mvm->mutex);
 +      return ret;
 +}
 +
 +static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
 +                                     struct ieee80211_vif *vif,
 +                                     struct ieee80211_sta *sta,
 +                                     struct station_info *sinfo)
 +{
 +      struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +      struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 +      struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 +
 +      if (!(mvm->fw->ucode_capa.capa[0] &
 +                              IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
 +              return;
 +
 +      /* if beacon filtering isn't on mac80211 does it anyway */
 +      if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
 +              return;
 +
 +      if (!vif->bss_conf.assoc)
 +              return;
 +
 +      mutex_lock(&mvm->mutex);
 +
 +      if (mvmvif->ap_sta_id != mvmsta->sta_id)
 +              goto unlock;
 +
 +      if (iwl_mvm_request_statistics(mvm, false))
 +              goto unlock;
 +
 +      sinfo->rx_beacon = mvmvif->beacon_stats.num_beacons +
 +                         mvmvif->beacon_stats.accu_num_beacons;
 +      sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX);
 +      if (mvmvif->beacon_stats.avg_signal) {
 +              /* firmware only reports a value after RXing a few beacons */
 +              sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal;
 +              sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
 +      }
 + unlock:
 +      mutex_unlock(&mvm->mutex);
 +}
 +
  const struct ieee80211_ops iwl_mvm_hw_ops = {
        .tx = iwl_mvm_mac_tx,
        .ampdu_action = iwl_mvm_mac_ampdu_action,
  #endif
        .set_default_unicast_key = iwl_mvm_set_default_unicast_key,
  #endif
 +      .get_survey = iwl_mvm_mac_get_survey,
 +      .sta_statistics = iwl_mvm_mac_sta_statistics,
  };
index f0946b5dd7c88b2b833d59a60c0dd753e8399352,c47c8051da7770f2a2a89c9b33868151c62f0ff6..a75bb150ea275ef18fd6449e8c1d5543fc466bf6
@@@ -82,7 -82,6 +82,7 @@@ struct iwl_mvm_scan_params 
        struct _dwell {
                u16 passive;
                u16 active;
 +              u16 fragmented;
        } dwell[IEEE80211_NUM_BANDS];
  };
  
@@@ -192,6 -191,101 +192,6 @@@ static u16 iwl_mvm_get_passive_dwell(st
        return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
  }
  
 -static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
 -                                     struct cfg80211_scan_request *req,
 -                                     bool basic_ssid,
 -                                     struct iwl_mvm_scan_params *params)
 -{
 -      struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
 -              (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
 -      int i;
 -      int type = BIT(req->n_ssids) - 1;
 -      enum ieee80211_band band = req->channels[0]->band;
 -
 -      if (!basic_ssid)
 -              type |= BIT(req->n_ssids);
 -
 -      for (i = 0; i < cmd->channel_count; i++) {
 -              chan->channel = cpu_to_le16(req->channels[i]->hw_value);
 -              chan->type = cpu_to_le32(type);
 -              if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
 -                      chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
 -              chan->active_dwell = cpu_to_le16(params->dwell[band].active);
 -              chan->passive_dwell = cpu_to_le16(params->dwell[band].passive);
 -              chan->iteration_count = cpu_to_le16(1);
 -              chan++;
 -      }
 -}
 -
 -/*
 - * Fill in probe request with the following parameters:
 - * TA is our vif HW address, which mac80211 ensures we have.
 - * Packet is broadcasted, so this is both SA and DA.
 - * The probe request IE is made out of two: first comes the most prioritized
 - * SSID if a directed scan is requested. Second comes whatever extra
 - * information was given to us as the scan request IE.
 - */
 -static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
 -                                int n_ssids, const u8 *ssid, int ssid_len,
 -                                const u8 *band_ie, int band_ie_len,
 -                                const u8 *common_ie, int common_ie_len,
 -                                int left)
 -{
 -      int len = 0;
 -      u8 *pos = NULL;
 -
 -      /* Make sure there is enough space for the probe request,
 -       * two mandatory IEs and the data */
 -      left -= 24;
 -      if (left < 0)
 -              return 0;
 -
 -      frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
 -      eth_broadcast_addr(frame->da);
 -      memcpy(frame->sa, ta, ETH_ALEN);
 -      eth_broadcast_addr(frame->bssid);
 -      frame->seq_ctrl = 0;
 -
 -      len += 24;
 -
 -      /* for passive scans, no need to fill anything */
 -      if (n_ssids == 0)
 -              return (u16)len;
 -
 -      /* points to the payload of the request */
 -      pos = &frame->u.probe_req.variable[0];
 -
 -      /* fill in our SSID IE */
 -      left -= ssid_len + 2;
 -      if (left < 0)
 -              return 0;
 -      *pos++ = WLAN_EID_SSID;
 -      *pos++ = ssid_len;
 -      if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
 -              memcpy(pos, ssid, ssid_len);
 -              pos += ssid_len;
 -      }
 -
 -      len += ssid_len + 2;
 -
 -      if (WARN_ON(left < band_ie_len + common_ie_len))
 -              return len;
 -
 -      if (band_ie && band_ie_len) {
 -              memcpy(pos, band_ie, band_ie_len);
 -              pos += band_ie_len;
 -              len += band_ie_len;
 -      }
 -
 -      if (common_ie && common_ie_len) {
 -              memcpy(pos, common_ie, common_ie_len);
 -              pos += common_ie_len;
 -              len += common_ie_len;
 -      }
 -
 -      return (u16)len;
 -}
 -
  static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
                                            struct ieee80211_vif *vif)
  {
@@@ -231,7 -325,7 +231,7 @@@ static void iwl_mvm_scan_calc_params(st
                         * If there is more than one active interface make
                         * passive scan more fragmented.
                         */
 -                      frag_passive_dwell = (global_cnt < 2) ? 40 : 20;
 +                      frag_passive_dwell = 40;
                        params->max_out_time = frag_passive_dwell;
                } else {
                        params->suspend_time = 120;
@@@ -264,10 -358,10 +264,10 @@@ not_bound
  
        for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
                if (params->passive_fragmented)
 -                      params->dwell[band].passive = frag_passive_dwell;
 -              else
 -                      params->dwell[band].passive =
 -                              iwl_mvm_get_passive_dwell(mvm, band);
 +                      params->dwell[band].fragmented = frag_passive_dwell;
 +
 +              params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm,
 +                                                                      band);
                params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
                                                                      n_ssids);
        }
@@@ -285,11 -379,20 +285,11 @@@ static int iwl_mvm_max_scan_ie_fw_cmd_r
  {
        int max_probe_len;
  
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
 -              max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE;
 -      else
 -              max_probe_len = mvm->fw->ucode_capa.max_probe_length;
 +      max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE;
  
        /* we create the 802.11 header and SSID element */
        max_probe_len -= 24 + 2;
  
 -      /* basic ssid is added only for hw_scan with and old api */
 -      if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) &&
 -          !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) &&
 -          !is_sched_scan)
 -              max_probe_len -= 32;
 -
        /* DS parameter set element is added on 2.4GHZ band if required */
        if (iwl_mvm_rrm_scan_needed(mvm))
                max_probe_len -= 3;
@@@ -301,6 -404,9 +301,6 @@@ int iwl_mvm_max_scan_ie_len(struct iwl_
  {
        int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);
  
 -      if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN))
 -              return max_ie_len;
 -
        /* TODO: [BUG] This function should return the maximum allowed size of
         * scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
         * in the same command. So the correct implementation of this function
        return max_ie_len;
  }
  
 -int iwl_mvm_scan_request(struct iwl_mvm *mvm,
 -                       struct ieee80211_vif *vif,
 -                       struct cfg80211_scan_request *req)
 -{
 -      struct iwl_host_cmd hcmd = {
 -              .id = SCAN_REQUEST_CMD,
 -              .len = { 0, },
 -              .data = { mvm->scan_cmd, },
 -              .dataflags = { IWL_HCMD_DFL_NOCOPY, },
 -      };
 -      struct iwl_scan_cmd *cmd = mvm->scan_cmd;
 -      int ret;
 -      u32 status;
 -      int ssid_len = 0;
 -      u8 *ssid = NULL;
 -      bool basic_ssid = !(mvm->fw->ucode_capa.flags &
 -                         IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
 -      struct iwl_mvm_scan_params params = {};
 -
 -      lockdep_assert_held(&mvm->mutex);
 -
 -      /* we should have failed registration if scan_cmd was NULL */
 -      if (WARN_ON(mvm->scan_cmd == NULL))
 -              return -ENOMEM;
 -
 -      IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
 -      mvm->scan_status = IWL_MVM_SCAN_OS;
 -      memset(cmd, 0, ksize(cmd));
 -
 -      cmd->channel_count = (u8)req->n_channels;
 -      cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
 -      cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
 -      cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
 -
 -      iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, &params);
 -      cmd->max_out_time = cpu_to_le32(params.max_out_time);
 -      cmd->suspend_time = cpu_to_le32(params.suspend_time);
 -      if (params.passive_fragmented)
 -              cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
 -
 -      cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
 -      cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
 -                                      MAC_FILTER_IN_BEACON);
 -
 -      if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
 -              cmd->type = cpu_to_le32(SCAN_TYPE_DISCOVERY_FORCED);
 -      else
 -              cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
 -
 -      cmd->repeats = cpu_to_le32(1);
 -
 -      /*
 -       * If the user asked for passive scan, don't change to active scan if
 -       * you see any activity on the channel - remain passive.
 -       */
 -      if (req->n_ssids > 0) {
 -              cmd->passive2active = cpu_to_le16(1);
 -              cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE;
 -              if (basic_ssid) {
 -                      ssid = req->ssids[0].ssid;
 -                      ssid_len = req->ssids[0].ssid_len;
 -              }
 -      } else {
 -              cmd->passive2active = 0;
 -              cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE;
 -      }
 -
 -      iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->ssids, req->n_ssids,
 -                              basic_ssid ? 1 : 0);
 -
 -      cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
 -                                         3 << TX_CMD_FLG_BT_PRIO_POS);
 -
 -      cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
 -      cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
 -      cmd->tx_cmd.rate_n_flags =
 -                      iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band,
 -                                                req->no_cck);
 -
 -      cmd->tx_cmd.len =
 -              cpu_to_le16(iwl_mvm_fill_probe_req(
 -                          (struct ieee80211_mgmt *)cmd->data,
 -                          vif->addr,
 -                          req->n_ssids, ssid, ssid_len,
 -                          req->ie, req->ie_len, NULL, 0,
 -                          mvm->fw->ucode_capa.max_probe_length));
 -
 -      iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, &params);
 -
 -      cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
 -              le16_to_cpu(cmd->tx_cmd.len) +
 -              (cmd->channel_count * sizeof(struct iwl_scan_channel)));
 -      hcmd.len[0] = le16_to_cpu(cmd->len);
 -
 -      status = SCAN_RESPONSE_OK;
 -      ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
 -      if (!ret && status == SCAN_RESPONSE_OK) {
 -              IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
 -      } else {
 -              /*
 -               * If the scan failed, it usually means that the FW was unable
 -               * to allocate the time events. Warn on it, but maybe we
 -               * should try to send the command again with different params.
 -               */
 -              IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n",
 -                      status, ret);
 -              mvm->scan_status = IWL_MVM_SCAN_NONE;
 -              ret = -EIO;
 -      }
 -      return ret;
 -}
 -
 -int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 -                        struct iwl_device_cmd *cmd)
 -{
 -      struct iwl_rx_packet *pkt = rxb_addr(rxb);
 -      struct iwl_cmd_response *resp = (void *)pkt->data;
 -
 -      IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n",
 -                     le32_to_cpu(resp->status));
 -      return 0;
 -}
 -
  int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
                                                struct iwl_rx_cmd_buffer *rxb,
                                                struct iwl_device_cmd *cmd)
        return 0;
  }
  
 -int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 -                        struct iwl_device_cmd *cmd)
 -{
 -      struct iwl_rx_packet *pkt = rxb_addr(rxb);
 -      struct iwl_scan_complete_notif *notif = (void *)pkt->data;
 -
 -      lockdep_assert_held(&mvm->mutex);
 -
 -      IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
 -                     notif->status, notif->scanned_channels);
 -
 -      if (mvm->scan_status == IWL_MVM_SCAN_OS)
 -              mvm->scan_status = IWL_MVM_SCAN_NONE;
 -      ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
 -
 -      iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 -
 -      return 0;
 -}
 -
  int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
                                    struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd)
  {
 -      struct iwl_rx_packet *pkt = rxb_addr(rxb);
 -
 -      if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) &&
 -          !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
 -              struct iwl_sched_scan_results *notif = (void *)pkt->data;
 -
 -              if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN))
 -                      return 0;
 -      }
 -
        IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
        ieee80211_sched_scan_results(mvm->hw);
  
        return 0;
  }
  
 -static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
 -                                   struct iwl_rx_packet *pkt, void *data)
 -{
 -      struct iwl_mvm *mvm =
 -              container_of(notif_wait, struct iwl_mvm, notif_wait);
 -      struct iwl_scan_complete_notif *notif;
 -      u32 *resp;
 -
 -      switch (pkt->hdr.cmd) {
 -      case SCAN_ABORT_CMD:
 -              resp = (void *)pkt->data;
 -              if (*resp == CAN_ABORT_STATUS) {
 -                      IWL_DEBUG_SCAN(mvm,
 -                                     "Scan can be aborted, wait until completion\n");
 -                      return false;
 -              }
 -
 -              /*
 -               * If scan cannot be aborted, it means that we had a
 -               * SCAN_COMPLETE_NOTIFICATION in the pipe and it called
 -               * ieee80211_scan_completed already.
 -               */
 -              IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n",
 -                             *resp);
 -              return true;
 -
 -      case SCAN_COMPLETE_NOTIFICATION:
 -              notif = (void *)pkt->data;
 -              IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n",
 -                             notif->status);
 -              return true;
 -
 -      default:
 -              WARN_ON(1);
 -              return false;
 -      };
 -}
 -
 -static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm)
 -{
 -      struct iwl_notification_wait wait_scan_abort;
 -      static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
 -                                             SCAN_COMPLETE_NOTIFICATION };
 -      int ret;
 -
 -      iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
 -                                 scan_abort_notif,
 -                                 ARRAY_SIZE(scan_abort_notif),
 -                                 iwl_mvm_scan_abort_notif, NULL);
 -
 -      ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, 0, 0, NULL);
 -      if (ret) {
 -              IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
 -              /* mac80211's state will be cleaned in the nic_restart flow */
 -              goto out_remove_notif;
 -      }
 -
 -      return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ);
 -
 -out_remove_notif:
 -      iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
 -      return ret;
 -}
 -
  int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
                                           struct iwl_rx_cmd_buffer *rxb,
                                           struct iwl_device_cmd *cmd)
  {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 -      u8 status, ebs_status;
 +      struct iwl_periodic_scan_complete *scan_notif;
  
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
 -              struct iwl_periodic_scan_complete *scan_notif;
 +      scan_notif = (void *)pkt->data;
  
 -              scan_notif = (void *)pkt->data;
 -              status = scan_notif->status;
 -              ebs_status = scan_notif->ebs_status;
 -      } else  {
 -              struct iwl_scan_offload_complete *scan_notif;
 -
 -              scan_notif = (void *)pkt->data;
 -              status = scan_notif->status;
 -              ebs_status = scan_notif->ebs_status;
 -      }
        /* scan status must be locked for proper checking */
        lockdep_assert_held(&mvm->mutex);
  
                       "%s completed, status %s, EBS status %s\n",
                       mvm->scan_status == IWL_MVM_SCAN_SCHED ?
                                "Scheduled scan" : "Scan",
 -                     status == IWL_SCAN_OFFLOAD_COMPLETED ?
 +                     scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
                                "completed" : "aborted",
 -                     ebs_status == IWL_SCAN_EBS_SUCCESS ?
 +                     scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
                                "success" : "failed");
  
  
        } else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
                mvm->scan_status = IWL_MVM_SCAN_NONE;
                ieee80211_scan_completed(mvm->hw,
 -                                       status == IWL_SCAN_OFFLOAD_ABORTED);
 +                              scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        }
  
 -      if (ebs_status)
 +      if (scan_notif->ebs_status)
                mvm->last_ebs_successful = false;
  
        return 0;
  }
  
 -static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
 -                                        struct ieee80211_vif *vif,
 -                                        struct ieee80211_scan_ies *ies,
 -                                        enum ieee80211_band band,
 -                                        struct iwl_tx_cmd *cmd,
 -                                        u8 *data)
 -{
 -      u16 cmd_len;
 -
 -      cmd->tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
 -      cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
 -      cmd->sta_id = mvm->aux_sta.sta_id;
 -
 -      cmd->rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, band, false);
 -
 -      cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
 -                                       vif->addr,
 -                                       1, NULL, 0,
 -                                       ies->ies[band], ies->len[band],
 -                                       ies->common_ies, ies->common_ie_len,
 -                                       SCAN_OFFLOAD_PROBE_REQ_SIZE);
 -      cmd->len = cpu_to_le16(cmd_len);
 -}
 -
 -static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
 -                             struct ieee80211_vif *vif,
 -                             struct cfg80211_sched_scan_request *req,
 -                             struct iwl_scan_offload_cmd *scan,
 -                             struct iwl_mvm_scan_params *params)
 -{
 -      scan->channel_count = req->n_channels;
 -      scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
 -      scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
 -      scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
 -      scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
 -
 -      scan->max_out_time = cpu_to_le32(params->max_out_time);
 -      scan->suspend_time = cpu_to_le32(params->suspend_time);
 -
 -      scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
 -                                        MAC_FILTER_IN_BEACON);
 -      scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
 -      scan->rep_count = cpu_to_le32(1);
 -
 -      if (params->passive_fragmented)
 -              scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
 -}
 -
  static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
  {
        int i;
@@@ -433,6 -815,127 +433,6 @@@ static void iwl_scan_offload_build_ssid
        }
  }
  
 -static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
 -                                struct cfg80211_sched_scan_request *req,
 -                                u8 *channels_buffer,
 -                                enum ieee80211_band band,
 -                                int *head,
 -                                u32 ssid_bitmap,
 -                                struct iwl_mvm_scan_params *params)
 -{
 -      u32 n_channels = mvm->fw->ucode_capa.n_scan_channels;
 -      __le32 *type = (__le32 *)channels_buffer;
 -      __le16 *channel_number = (__le16 *)(type + n_channels);
 -      __le16 *iter_count = channel_number + n_channels;
 -      __le32 *iter_interval = (__le32 *)(iter_count + n_channels);
 -      u8 *active_dwell = (u8 *)(iter_interval + n_channels);
 -      u8 *passive_dwell = active_dwell + n_channels;
 -      int i, index = 0;
 -
 -      for (i = 0; i < req->n_channels; i++) {
 -              struct ieee80211_channel *chan = req->channels[i];
 -
 -              if (chan->band != band)
 -                      continue;
 -
 -              index = *head;
 -              (*head)++;
 -
 -              channel_number[index] = cpu_to_le16(chan->hw_value);
 -              active_dwell[index] = params->dwell[band].active;
 -              passive_dwell[index] = params->dwell[band].passive;
 -
 -              iter_count[index] = cpu_to_le16(1);
 -              iter_interval[index] = 0;
 -
 -              if (!(chan->flags & IEEE80211_CHAN_NO_IR))
 -                      type[index] |=
 -                              cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
 -
 -              type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL |
 -                                         IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
 -
 -              if (chan->flags & IEEE80211_CHAN_NO_HT40)
 -                      type[index] |=
 -                              cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW);
 -
 -              /* scan for all SSIDs from req->ssids */
 -              type[index] |= cpu_to_le32(ssid_bitmap);
 -      }
 -}
 -
 -int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
 -                            struct ieee80211_vif *vif,
 -                            struct cfg80211_sched_scan_request *req,
 -                            struct ieee80211_scan_ies *ies)
 -{
 -      int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
 -      int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
 -      int head = 0;
 -      u32 ssid_bitmap;
 -      int cmd_len;
 -      int ret;
 -      u8 *probes;
 -      bool basic_ssid = !(mvm->fw->ucode_capa.flags &
 -                          IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
 -
 -      struct iwl_scan_offload_cfg *scan_cfg;
 -      struct iwl_host_cmd cmd = {
 -              .id = SCAN_OFFLOAD_CONFIG_CMD,
 -      };
 -      struct iwl_mvm_scan_params params = {};
 -
 -      lockdep_assert_held(&mvm->mutex);
 -
 -      cmd_len = sizeof(struct iwl_scan_offload_cfg) +
 -                mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE +
 -                2 * SCAN_OFFLOAD_PROBE_REQ_SIZE;
 -
 -      scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
 -      if (!scan_cfg)
 -              return -ENOMEM;
 -
 -      probes = scan_cfg->data +
 -              mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE;
 -
 -      iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
 -      iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params);
 -      scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
 -
 -      iwl_scan_offload_build_ssid(req, scan_cfg->scan_cmd.direct_scan,
 -                                  &ssid_bitmap, basic_ssid);
 -      /* build tx frames for supported bands */
 -      if (band_2ghz) {
 -              iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
 -                                            IEEE80211_BAND_2GHZ,
 -                                            &scan_cfg->scan_cmd.tx_cmd[0],
 -                                            probes);
 -              iwl_build_channel_cfg(mvm, req, scan_cfg->data,
 -                                    IEEE80211_BAND_2GHZ, &head,
 -                                    ssid_bitmap, &params);
 -      }
 -      if (band_5ghz) {
 -              iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
 -                                            IEEE80211_BAND_5GHZ,
 -                                            &scan_cfg->scan_cmd.tx_cmd[1],
 -                                            probes +
 -                                              SCAN_OFFLOAD_PROBE_REQ_SIZE);
 -              iwl_build_channel_cfg(mvm, req, scan_cfg->data,
 -                                    IEEE80211_BAND_5GHZ, &head,
 -                                    ssid_bitmap, &params);
 -      }
 -
 -      cmd.data[0] = scan_cfg;
 -      cmd.len[0] = cmd_len;
 -      cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
 -
 -      IWL_DEBUG_SCAN(mvm, "Sending scheduled scan config\n");
 -
 -      ret = iwl_mvm_send_cmd(mvm, &cmd);
 -      kfree(scan_cfg);
 -      return ret;
 -}
 -
  int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
                                       struct cfg80211_sched_scan_request *req)
  {
@@@ -515,6 -1018,33 +515,6 @@@ static bool iwl_mvm_scan_pass_all(struc
        return true;
  }
  
 -int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
 -                           struct cfg80211_sched_scan_request *req)
 -{
 -      struct iwl_scan_offload_req scan_req = {
 -              .watchdog = IWL_SCHED_SCAN_WATCHDOG,
 -
 -              .schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS,
 -              .schedule_line[0].delay = cpu_to_le16(req->interval / 1000),
 -              .schedule_line[0].full_scan_mul = 1,
 -
 -              .schedule_line[1].iterations = 0xff,
 -              .schedule_line[1].delay = cpu_to_le16(req->interval / 1000),
 -              .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER,
 -      };
 -
 -      if (iwl_mvm_scan_pass_all(mvm, req))
 -              scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL);
 -
 -      if (mvm->last_ebs_successful &&
 -          mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT)
 -              scan_req.flags |=
 -                      cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE);
 -
 -      return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, 0,
 -                                  sizeof(scan_req), &scan_req);
 -}
 -
  int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               struct cfg80211_sched_scan_request *req,
                if (ret)
                        return ret;
                ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
 -      } else if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
 -              mvm->scan_status = IWL_MVM_SCAN_SCHED;
 -              ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
 -              if (ret)
 -                      return ret;
 -              ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
        } else {
                mvm->scan_status = IWL_MVM_SCAN_SCHED;
 -              ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
 -              if (ret)
 -                      return ret;
                ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
                if (ret)
                        return ret;
 -              ret = iwl_mvm_sched_scan_start(mvm, req);
 +              ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
        }
  
        return ret;
@@@ -549,7 -1088,9 +549,7 @@@ static int iwl_mvm_send_scan_offload_ab
        /* Exit instantly with error when device is not ready
         * to receive scan abort command or it does not perform
         * scheduled scan currently */
 -      if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
 -          (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
 -           mvm->scan_status != IWL_MVM_SCAN_OS))
 +      if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return -EIO;
  
        ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
@@@ -587,9 -1128,18 +587,11 @@@ int iwl_mvm_scan_offload_stop(struct iw
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return 0;
  
-       if (iwl_mvm_is_radio_killed(mvm))
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ret = 0;
                goto out;
+       }
  
 -      if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
 -          (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
 -           mvm->scan_status != IWL_MVM_SCAN_OS)) {
 -              IWL_DEBUG_SCAN(mvm, "No scan to stop\n");
 -              return 0;
 -      }
 -
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
                                   scan_done_notif,
                                   ARRAY_SIZE(scan_done_notif),
                IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
                               sched ? "offloaded " : "", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
-               return ret;
+               goto out;
        }
  
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
                       sched ? "offloaded " : "");
  
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-       if (ret)
-               return ret;
+ out:
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
  
- out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
  
        if (notify) {
                        ieee80211_scan_completed(mvm->hw, true);
        }
  
-       return 0;
+       return ret;
  }
  
  static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
@@@ -769,7 -1316,7 +768,7 @@@ iwl_mvm_build_generic_unified_scan_cmd(
        cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
        if (params->passive_fragmented)
                cmd->fragmented_dwell =
 -                              params->dwell[IEEE80211_BAND_2GHZ].passive;
 +                              params->dwell[IEEE80211_BAND_2GHZ].fragmented;
        cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
        cmd->max_out_time = cpu_to_le32(params->max_out_time);
        cmd->suspend_time = cpu_to_le32(params->suspend_time);
@@@ -1032,7 -1579,9 +1031,7 @@@ int iwl_mvm_cancel_scan(struct iwl_mvm 
                return 0;
        }
  
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
 -              return iwl_mvm_scan_offload_stop(mvm, true);
 -      return iwl_mvm_cancel_regular_scan(mvm);
 +      return iwl_mvm_scan_offload_stop(mvm, true);
  }
  
  /* UMAC scan API */
@@@ -1215,7 -1764,7 +1214,7 @@@ iwl_mvm_build_generic_umac_scan_cmd(str
        cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
        if (params->passive_fragmented)
                cmd->fragmented_dwell =
 -                              params->dwell[IEEE80211_BAND_2GHZ].passive;
 +                              params->dwell[IEEE80211_BAND_2GHZ].fragmented;
        cmd->max_out_time = cpu_to_le32(params->max_out_time);
        cmd->suspend_time = cpu_to_le32(params->suspend_time);
        cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
@@@ -1609,8 -2158,14 +1608,8 @@@ int iwl_mvm_scan_size(struct iwl_mvm *m
                                mvm->fw->ucode_capa.n_scan_channels +
                        sizeof(struct iwl_scan_req_umac_tail);
  
 -      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
 -              return sizeof(struct iwl_scan_req_unified_lmac) +
 -                      sizeof(struct iwl_scan_channel_cfg_lmac) *
 -                              mvm->fw->ucode_capa.n_scan_channels +
 -                      sizeof(struct iwl_scan_probe_req);
 -
 -      return sizeof(struct iwl_scan_cmd) +
 -              mvm->fw->ucode_capa.max_probe_length +
 -                      mvm->fw->ucode_capa.n_scan_channels *
 -              sizeof(struct iwl_scan_channel);
 +      return sizeof(struct iwl_scan_req_unified_lmac) +
 +              sizeof(struct iwl_scan_channel_cfg_lmac) *
 +              mvm->fw->ucode_capa.n_scan_channels +
 +              sizeof(struct iwl_scan_probe_req);
  }
index 1dbfcc43d82c9d81759bcd5334ac37fabd4e7a8e,4b81c0bf63b0a86173afde87ef2822c0dfa8860f..8d179ab67cc237026e8653d18e791d826d9ee0e4
@@@ -197,6 -197,8 +197,8 @@@ iwl_mvm_te_handle_notify_csa(struct iwl
                             struct iwl_time_event_notif *notif)
  {
        if (!le32_to_cpu(notif->status)) {
+               if (te_data->vif->type == NL80211_IFTYPE_STATION)
+                       ieee80211_connection_loss(te_data->vif);
                IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
                iwl_mvm_te_clear_data(mvm, te_data);
                return;
@@@ -261,23 -263,17 +263,23 @@@ static void iwl_mvm_te_handle_notif(str
                             "TE ended - current time %lu, estimated end %lu\n",
                             jiffies, te_data->end_jiffies);
  
 -              if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
 +              switch (te_data->vif->type) {
 +              case NL80211_IFTYPE_P2P_DEVICE:
                        ieee80211_remain_on_channel_expired(mvm->hw);
                        iwl_mvm_roc_finished(mvm);
 +                      break;
 +              case NL80211_IFTYPE_STATION:
 +                      /*
 +                       * By now, we should have finished association
 +                       * and know the dtim period.
 +                       */
 +                      iwl_mvm_te_check_disconnect(mvm, te_data->vif,
 +                              "No association and the time event is over already...");
 +                      break;
 +              default:
 +                      break;
                }
  
 -              /*
 -               * By now, we should have finished association
 -               * and know the dtim period.
 -               */
 -              iwl_mvm_te_check_disconnect(mvm, te_data->vif,
 -                      "No association and the time event is over already...");
                iwl_mvm_te_clear_data(mvm, te_data);
        } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
                te_data->running = true;
@@@ -756,8 -752,7 +758,7 @@@ void iwl_mvm_stop_roc(struct iwl_mvm *m
         * request
         */
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
-                   te_data->running) {
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
                        is_p2p = true;
                        goto remove_te;
         * request
         */
        list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
-               if (te_data->running) {
-                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       goto remove_te;
-               }
+               mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+               goto remove_te;
        }
  
  remove_te: