Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 16 Aug 2013 18:48:40 +0000 (14:48 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 16 Aug 2013 18:48:40 +0000 (14:48 -0400)
1  2 
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index d0d7a20266e6ec2cb8778549fbb7df40854c2cd2,ec07f0abbc6fdfab45160496d69c386eb42c7fae..417639f77b01c8a9a166de79e4374cefa2313ba6
@@@ -134,7 -134,7 +134,7 @@@ struct wowlan_key_data 
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
        struct iwl_wowlan_tkip_params_cmd *tkip;
        bool error, use_rsc_tsc, use_tkip;
 -      int gtk_key_idx;
 +      int wep_key_idx;
  };
  
  static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                        wkc.wep_key.key_offset = 0;
                } else {
                        /* others start at 1 */
 -                      data->gtk_key_idx++;
 -                      wkc.wep_key.key_offset = data->gtk_key_idx;
 +                      data->wep_key_idx++;
 +                      wkc.wep_key.key_offset = data->wep_key_idx;
                }
  
                ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
        } else {
 -              data->gtk_key_idx++;
 -              key->hw_key_idx = data->gtk_key_idx;
 +              /*
 +               * firmware only supports TSC/RSC for a single key,
 +               * so if there are multiple keep overwriting them
 +               * with new ones -- this relies on mac80211 doing
 +               * list_add_tail().
 +               */
 +              key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
        }
@@@ -1109,73 -1104,16 +1109,16 @@@ int iwl_mvm_suspend(struct ieee80211_h
        return __iwl_mvm_suspend(hw, wowlan, false);
  }
  
- static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
-                                        struct ieee80211_vif *vif)
+ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         struct iwl_wowlan_status *status)
  {
-       u32 base = mvm->error_event_table;
-       struct error_table_start {
-               /* cf. struct iwl_error_event_table */
-               u32 valid;
-               u32 error_id;
-       } err_info;
+       struct sk_buff *pkt = NULL;
        struct cfg80211_wowlan_wakeup wakeup = {
                .pattern_idx = -1,
        };
        struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
-       struct iwl_host_cmd cmd = {
-               .id = WOWLAN_GET_STATUSES,
-               .flags = CMD_SYNC | CMD_WANT_SKB,
-       };
-       struct iwl_wowlan_status *status;
-       u32 reasons;
-       int ret, len;
-       struct sk_buff *pkt = NULL;
-       iwl_trans_read_mem_bytes(mvm->trans, base,
-                                &err_info, sizeof(err_info));
-       if (err_info.valid) {
-               IWL_INFO(mvm, "error table is valid (%d)\n",
-                        err_info.valid);
-               if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
-                       wakeup.rfkill_release = true;
-                       ieee80211_report_wowlan_wakeup(vif, &wakeup,
-                                                      GFP_KERNEL);
-               }
-               return;
-       }
-       /* only for tracing for now */
-       ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
-       if (ret)
-               IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
-       ret = iwl_mvm_send_cmd(mvm, &cmd);
-       if (ret) {
-               IWL_ERR(mvm, "failed to query status (%d)\n", ret);
-               return;
-       }
-       /* RF-kill already asserted again... */
-       if (!cmd.resp_pkt)
-               return;
-       len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
-               IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
-               goto out;
-       }
-       status = (void *)cmd.resp_pkt->data;
-       if (len - sizeof(struct iwl_cmd_header) !=
-           sizeof(*status) +
-           ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
-               IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
-               goto out;
-       }
-       reasons = le32_to_cpu(status->wakeup_reasons);
+       u32 reasons = le32_to_cpu(status->wakeup_reasons);
  
        if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
                wakeup_report = NULL;
                        pktsize -= hdrlen;
  
                        if (ieee80211_has_protected(hdr->frame_control)) {
+                               /*
+                                * This is unlocked and using gtk_i(c)vlen,
+                                * but since everything is under RTNL still
+                                * that's not really a problem - changing
+                                * it would be difficult.
+                                */
                                if (is_multicast_ether_addr(hdr->addr1)) {
                                        ivlen = mvm->gtk_ivlen;
                                        icvlen += mvm->gtk_icvlen;
   report:
        ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
        kfree_skb(pkt);
+ }
  
-  out:
+ /* releases the MVM mutex */
+ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
+                                        struct ieee80211_vif *vif)
+ {
+       u32 base = mvm->error_event_table;
+       struct error_table_start {
+               /* cf. struct iwl_error_event_table */
+               u32 valid;
+               u32 error_id;
+       } err_info;
+       struct iwl_host_cmd cmd = {
+               .id = WOWLAN_GET_STATUSES,
+               .flags = CMD_SYNC | CMD_WANT_SKB,
+       };
+       struct iwl_wowlan_status *status;
+       int ret, len;
+       iwl_trans_read_mem_bytes(mvm->trans, base,
+                                &err_info, sizeof(err_info));
+       if (err_info.valid) {
+               IWL_INFO(mvm, "error table is valid (%d)\n",
+                        err_info.valid);
+               if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+                       struct cfg80211_wowlan_wakeup wakeup = {
+                               .rfkill_release = true,
+                       };
+                       ieee80211_report_wowlan_wakeup(vif, &wakeup,
+                                                      GFP_KERNEL);
+               }
+               goto out_unlock;
+       }
+       /* only for tracing for now */
+       ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
+       if (ret)
+               IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
+       ret = iwl_mvm_send_cmd(mvm, &cmd);
+       if (ret) {
+               IWL_ERR(mvm, "failed to query status (%d)\n", ret);
+               goto out_unlock;
+       }
+       /* RF-kill already asserted again... */
+       if (!cmd.resp_pkt)
+               goto out_unlock;
+       len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
+               IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+               goto out_free_resp;
+       }
+       status = (void *)cmd.resp_pkt->data;
+       if (len - sizeof(struct iwl_cmd_header) !=
+           sizeof(*status) +
+           ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
+               IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+               goto out_free_resp;
+       }
+       /* now we have all the data we need, unlock to avoid mac80211 issues */
+       mutex_unlock(&mvm->mutex);
+       iwl_mvm_report_wakeup_reasons(mvm, vif, status);
+       iwl_free_resp(&cmd);
+       return;
+  out_free_resp:
        iwl_free_resp(&cmd);
+  out_unlock:
+       mutex_unlock(&mvm->mutex);
  }
  
  static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
@@@ -1347,10 -1364,13 +1369,13 @@@ static int __iwl_mvm_resume(struct iwl_
        iwl_mvm_read_d3_sram(mvm);
  
        iwl_mvm_query_wakeup_reasons(mvm, vif);
+       /* has unlocked the mutex, so skip that */
+       goto out;
  
   out_unlock:
        mutex_unlock(&mvm->mutex);
  
+  out:
        if (!test && vif)
                ieee80211_resume_disconnect(vif);
  
index cc157734eb21742d218720e275db8d40820bef1f,2e60be2a7ee35e635409c84b004e8b71d3610a68..aac81b8984b05ec87f50fa09b32f7ab9a3dc36ed
@@@ -352,6 -352,10 +352,10 @@@ static void iwl_dbgfs_update_pm(struct 
                IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
                dbgfs_pm->lprx_rssi_threshold = val;
                break;
+       case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
+               IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
+               dbgfs_pm->snooze_ena = val;
+               break;
        }
  }
  
@@@ -405,6 -409,10 +409,10 @@@ static ssize_t iwl_dbgfs_pm_params_writ
                    POWER_LPRX_RSSI_THRESHOLD_MIN)
                        return -EINVAL;
                param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
+       } else if (!strncmp("snooze_enable=", buf, 14)) {
+               if (sscanf(buf + 14, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
        } else {
                return -EINVAL;
        }
@@@ -424,7 -432,7 +432,7 @@@ static ssize_t iwl_dbgfs_pm_params_read
        struct ieee80211_vif *vif = file->private_data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm *mvm = mvmvif->dbgfs_data;
-       char buf[256];
+       char buf[512];
        int bufsz = sizeof(buf);
        int pos;
  
@@@ -895,10 -903,7 +903,7 @@@ static ssize_t iwl_dbgfs_bf_params_writ
        if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) {
                ret = iwl_mvm_disable_beacon_filter(mvm, vif);
        } else {
-               if (mvmvif->bf_enabled)
-                       ret = iwl_mvm_enable_beacon_filter(mvm, vif);
-               else
-                       ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+               ret = iwl_mvm_enable_beacon_filter(mvm, vif);
        }
        mutex_unlock(&mvm->mutex);
  
@@@ -923,7 -928,7 +928,7 @@@ static ssize_t iwl_dbgfs_bf_params_read
        };
  
        iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
-       if (mvmvif->bf_enabled)
+       if (mvmvif->bf_data.bf_enabled)
                cmd.bf_enable_beacon_filter = cpu_to_le32(1);
        else
                cmd.bf_enable_beacon_filter = 0;
@@@ -1116,11 -1121,7 +1121,11 @@@ void iwl_mvm_vif_dbgfs_register(struct 
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        char buf[100];
  
 -      if (!dbgfs_dir)
 +      /*
 +       * Check if debugfs directory already exist before creating it.
 +       * This may happen when, for example, resetting hw or suspend-resume
 +       */
 +      if (!dbgfs_dir || mvmvif->dbgfs_dir)
                return;
  
        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
index 995f0250105eac5a35aef255202af697ccbba227,692d2ea211e85086b8e57bddbf7cd1b44d516d8a..9833cdf6177cd34d199de063cb0ff466042cfed0
@@@ -155,7 -155,8 +155,8 @@@ int iwl_mvm_mac_setup_register(struct i
                    IEEE80211_HW_TIMING_BEACON_ONLY |
                    IEEE80211_HW_CONNECTION_MONITOR |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                   IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+                   IEEE80211_HW_SUPPORTS_STATIC_SMPS |
+                   IEEE80211_HW_SUPPORTS_UAPSD;
  
        hw->queues = IWL_MVM_FIRST_AGG_QUEUE;
        hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
  
        hw->wiphy->max_remain_on_channel_duration = 10000;
        hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+       hw->uapsd_queues = IWL_UAPSD_AC_INFO;
+       hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
  
        /* Extract MAC address */
        memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
        if (ret)
                return ret;
  
 -      return ieee80211_register_hw(mvm->hw);
 +      ret = ieee80211_register_hw(mvm->hw);
 +      if (ret)
 +              iwl_mvm_leds_exit(mvm);
 +
 +      return ret;
  }
  
  static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@@ -391,7 -390,6 +394,7 @@@ static void iwl_mvm_restart_cleanup(str
        ieee80211_wake_queues(mvm->hw);
  
        mvm->vif_count = 0;
 +      mvm->rx_ba_sessions = 0;
  }
  
  static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@@ -513,27 -511,6 +516,27 @@@ static int iwl_mvm_mac_add_interface(st
        if (ret)
                goto out_unlock;
  
 +      /*
 +       * TODO: remove this temporary code.
 +       * Currently MVM FW supports power management only on single MAC.
 +       * If new interface added, disable PM on existing interface.
 +       * P2P device is a special case, since it is handled by FW similary to
 +       * scan. If P2P deviced is added, PM remains enabled on existing
 +       * interface.
 +       * Note: the method below does not count the new interface being added
 +       * at this moment.
 +       */
 +      if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
 +              mvm->vif_count++;
 +      if (mvm->vif_count > 1) {
 +              IWL_DEBUG_MAC80211(mvm,
 +                                 "Disable power on existing interfaces\n");
 +              ieee80211_iterate_active_interfaces_atomic(
 +                                          mvm->hw,
 +                                          IEEE80211_IFACE_ITER_NORMAL,
 +                                          iwl_mvm_pm_disable_iterator, mvm);
 +      }
 +
        /*
         * The AP binding flow can be done only after the beacon
         * template is configured (which happens only in the mac80211
                goto out_unlock;
        }
  
 -      /*
 -       * TODO: remove this temporary code.
 -       * Currently MVM FW supports power management only on single MAC.
 -       * If new interface added, disable PM on existing interface.
 -       * P2P device is a special case, since it is handled by FW similary to
 -       * scan. If P2P deviced is added, PM remains enabled on existing
 -       * interface.
 -       * Note: the method below does not count the new interface being added
 -       * at this moment.
 -       */
 -      if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
 -              mvm->vif_count++;
 -      if (mvm->vif_count > 1) {
 -              IWL_DEBUG_MAC80211(mvm,
 -                                 "Disable power on existing interfaces\n");
 -              ieee80211_iterate_active_interfaces_atomic(
 -                                          mvm->hw,
 -                                          IEEE80211_IFACE_ITER_NORMAL,
 -                                          iwl_mvm_pm_disable_iterator, mvm);
 -      }
 -
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
                goto out_release;
            vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
            mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){
                mvm->bf_allowed_vif = mvmvif;
-               vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+               vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+                                    IEEE80211_VIF_SUPPORTS_CQM_RSSI;
        }
  
        /*
   out_free_bf:
        if (mvm->bf_allowed_vif == mvmvif) {
                mvm->bf_allowed_vif = NULL;
-               vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+               vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
+                                      IEEE80211_VIF_SUPPORTS_CQM_RSSI);
        }
   out_remove_mac:
        mvmvif->phy_ctxt = NULL;
@@@ -683,7 -683,8 +688,8 @@@ static void iwl_mvm_mac_remove_interfac
  
        if (mvm->bf_allowed_vif == mvmvif) {
                mvm->bf_allowed_vif = NULL;
-               vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+               vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
+                                      IEEE80211_VIF_SUPPORTS_CQM_RSSI);
        }
  
        iwl_mvm_vif_dbgfs_clean(mvm, vif);
@@@ -801,6 -802,10 +807,10 @@@ static void iwl_mvm_bss_info_changed_st
                        if (ret)
                                IWL_ERR(mvm, "failed to update quotas\n");
                }
+               /* reset rssi values */
+               mvmvif->bf_data.ave_beacon_signal = 0;
                if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) {
                        /* Workaround for FW bug, otherwise FW disables device
                         * power save upon disassociation
                 */
                iwl_mvm_remove_time_event(mvm, mvmvif,
                                          &mvmvif->time_event_data);
-       } else if (changes & BSS_CHANGED_PS) {
+       } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) {
                ret = iwl_mvm_power_update_mode(mvm, vif);
                if (ret)
                        IWL_ERR(mvm, "failed to update power mode\n");
                                bss_conf->txpower);
                iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
        }
+       if (changes & BSS_CHANGED_CQM) {
+               IWL_DEBUG_MAC80211(mvm, "cqm info_changed");
+               /* reset cqm events tracking */
+               mvmvif->bf_data.last_cqm_event = 0;
+               ret = iwl_mvm_update_beacon_filter(mvm, vif);
+               if (ret)
+                       IWL_ERR(mvm, "failed to update CQM thresholds\n");
+       }
  }
  
  static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
@@@ -1044,21 -1058,6 +1063,21 @@@ static int iwl_mvm_mac_sta_state(struc
        mutex_lock(&mvm->mutex);
        if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
 +              /*
 +               * Firmware bug - it'll crash if the beacon interval is less
 +               * than 16. We can't avoid connecting at all, so refuse the
 +               * station state change, this will cause mac80211 to abandon
 +               * attempts to connect to this AP, and eventually wpa_s will
 +               * blacklist the AP...
 +               */
 +              if (vif->type == NL80211_IFTYPE_STATION &&
 +                  vif->bss_conf.beacon_int < 16) {
 +                      IWL_ERR(mvm,
 +                              "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
 +                              sta->addr, vif->bss_conf.beacon_int);
 +                      ret = -EINVAL;
 +                      goto out_unlock;
 +              }
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
        } else {
                ret = -EIO;
        }
 + out_unlock:
        mutex_unlock(&mvm->mutex);
  
        return ret;
index 4173bb57585f3836cb47117966b047699d682d33,0f33d7f20890b4ea197fff4c53097241ec992d9b..b0389279cc1ed774f9f90f20137d11b6691d8eae
@@@ -153,6 -153,11 +153,11 @@@ enum iwl_power_scheme 
  };
  
  #define IWL_CONN_MAX_LISTEN_INTERVAL  70
+ #define IWL_UAPSD_AC_INFO             (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
+                                        IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
+                                        IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
+                                        IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+ #define IWL_UAPSD_MAX_SP              IEEE80211_WMM_IE_STA_QOSINFO_SP_2
  
  struct iwl_mvm_power_ops {
        int (*power_update_mode)(struct iwl_mvm *mvm,
@@@ -175,6 -180,7 +180,7 @@@ enum iwl_dbgfs_pm_mask 
        MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5),
        MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
        MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
+       MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
  };
  
  struct iwl_dbgfs_pm {
        bool disable_power_off;
        bool lprx_ena;
        u32 lprx_rssi_threshold;
+       bool snooze_ena;
        int mask;
  };
  
@@@ -227,6 -234,21 +234,21 @@@ enum iwl_mvm_smps_type_request 
        NUM_IWL_MVM_SMPS_REQ,
  };
  
+ /**
+ * struct iwl_mvm_vif_bf_data - beacon filtering related data
+ * @bf_enabled: indicates if beacon filtering is enabled
+ * @ba_enabled: indicated if beacon abort is enabled
+ * @last_beacon_signal: last beacon rssi signal in dbm
+ * @ave_beacon_signal: average beacon signal
+ * @last_cqm_event: rssi of the last cqm event
+ */
+ struct iwl_mvm_vif_bf_data {
+       bool bf_enabled;
+       bool ba_enabled;
+       s8 ave_beacon_signal;
+       s8 last_cqm_event;
+ };
  /**
   * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
   * @id: between 0 and 3
@@@ -252,8 -274,7 +274,7 @@@ struct iwl_mvm_vif 
        bool uploaded;
        bool ap_active;
        bool monitor_active;
-       /* indicate whether beacon filtering is enabled */
-       bool bf_enabled;
+       struct iwl_mvm_vif_bf_data bf_data;
  
        u32 ap_beacon_time;
  
@@@ -440,7 -461,6 +461,7 @@@ struct iwl_mvm 
        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];
 +      u8 rx_ba_sessions;
  
        /* configured by mac80211 */
        u32 rts_threshold;
@@@ -754,6 -774,8 +775,8 @@@ int iwl_mvm_beacon_filter_send_cmd(stru
                                   struct iwl_beacon_filter_cmd *cmd);
  int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
                                struct ieee80211_vif *vif, bool enable);
+ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
+                                 struct ieee80211_vif *vif);
  
  /* SMPS */
  void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
index c47a635b56ffbf4c7622769c56a3ad84c095e4fe,9ae1bad8a359bd7dfe03ac286e343afc4b478cf0..4ffaa3fa153f78e7d14f2ad90223b01146562c50
@@@ -82,41 -82,35 +82,35 @@@ static const u8 ant_toggle_lookup[] = 
        [ANT_ABC] = ANT_ABC,
  };
  
- #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+ #define IWL_DECLARE_RATE_INFO(r, s, rp, rn)                  \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
                                    IWL_RATE_SISO_##s##M_PLCP, \
                                    IWL_RATE_MIMO2_##s##M_PLCP,\
-                                   IWL_RATE_MIMO3_##s##M_PLCP,\
-                                   IWL_RATE_##r##M_IEEE,      \
-                                   IWL_RATE_##ip##M_INDEX,    \
-                                   IWL_RATE_##in##M_INDEX,    \
                                    IWL_RATE_##rp##M_INDEX,    \
-                                   IWL_RATE_##rn##M_INDEX,    \
-                                   IWL_RATE_##pp##M_INDEX,    \
-                                   IWL_RATE_##np##M_INDEX }
+                                   IWL_RATE_##rn##M_INDEX }
  
  /*
   * Parameter order:
-  *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+  *   rate, ht rate, prev rate, next rate
   *
   * If there isn't a valid next or previous rate then INV is used which
   * maps to IWL_RATE_INVALID
   *
   */
  static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
-       IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
-       IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
-       IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-       IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
-       IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
-       IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
-       IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
-       IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
-       IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
-       IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
-       IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
-       IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
-       IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+       IWL_DECLARE_RATE_INFO(1, INV, INV, 2),   /*  1mbps */
+       IWL_DECLARE_RATE_INFO(2, INV, 1, 5),     /*  2mbps */
+       IWL_DECLARE_RATE_INFO(5, INV, 2, 11),    /*5.5mbps */
+       IWL_DECLARE_RATE_INFO(11, INV, 9, 12),   /* 11mbps */
+       IWL_DECLARE_RATE_INFO(6, 6, 5, 11),      /*  6mbps */
+       IWL_DECLARE_RATE_INFO(9, 6, 6, 11),      /*  9mbps */
+       IWL_DECLARE_RATE_INFO(12, 12, 11, 18),   /* 12mbps */
+       IWL_DECLARE_RATE_INFO(18, 18, 12, 24),   /* 18mbps */
+       IWL_DECLARE_RATE_INFO(24, 24, 18, 36),   /* 24mbps */
+       IWL_DECLARE_RATE_INFO(36, 36, 24, 48),   /* 36mbps */
+       IWL_DECLARE_RATE_INFO(48, 48, 36, 54),   /* 48mbps */
+       IWL_DECLARE_RATE_INFO(54, 54, 48, INV),  /* 54mbps */
+       IWL_DECLARE_RATE_INFO(60, 60, 48, INV),  /* 60mbps */
        /* FIXME:RS:          ^^    should be INV (legacy) */
  };
  
@@@ -134,9 -128,8 +128,8 @@@ static int iwl_hwrate_to_plcp_idx(u32 r
        if (rate_n_flags & RATE_MCS_HT_MSK) {
                idx = rs_extract_rate(rate_n_flags);
  
-               if (idx >= IWL_RATE_MIMO3_6M_PLCP)
-                       idx = idx - IWL_RATE_MIMO3_6M_PLCP;
-               else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+               WARN_ON_ONCE(idx >= IWL_RATE_MIMO3_6M_PLCP);
+               if (idx >= IWL_RATE_MIMO2_6M_PLCP)
                        idx = idx - IWL_RATE_MIMO2_6M_PLCP;
  
                idx += IWL_FIRST_OFDM_RATE;
@@@ -168,10 -161,10 +161,10 @@@ static void rs_stay_in_table(struct iwl
  
  #ifdef CONFIG_MAC80211_DEBUGFS
  static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index);
+                            u32 *rate_n_flags);
  #else
  static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index)
+                            u32 *rate_n_flags)
  {}
  #endif
  
@@@ -218,20 -211,6 +211,6 @@@ static s32 expected_tpt_mimo2_40MHz[4][
        {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
  };
  
- static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
-       {0, 0, 0, 0,  99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
-       {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
-       {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
-       {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
- };
- static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
-       {0, 0, 0, 0, 152, 0, 211, 239, 255, 279,  290,  294,  297}, /* Norm */
-       {0, 0, 0, 0, 160, 0, 219, 245, 261, 284,  294,  297,  300}, /* SGI */
-       {0, 0, 0, 0, 254, 0, 443, 584, 695, 868,  984, 1030, 1070}, /* AGG */
-       {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
- };
  /* mbps, mcs */
  static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
        {  "1", "BPSK DSSS"},
@@@ -279,7 -258,6 +258,6 @@@ static void rs_program_fix_rate(struct 
        lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
        lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
        lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
  
        IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
                       lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
@@@ -459,7 -437,7 +437,7 @@@ static u32 rate_n_flags_from_tbl(struc
                else if (is_mimo2(tbl->lq_type))
                        rate_n_flags |= iwl_rates[index].plcp_mimo2;
                else
-                       rate_n_flags |= iwl_rates[index].plcp_mimo3;
+                       WARN_ON_ONCE(1);
        } else {
                IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type);
        }
@@@ -497,7 -475,7 +475,7 @@@ static int rs_get_tbl_info_from_mcs(con
        u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
        u8 mcs;
  
-       memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
+       memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win));
        *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
  
        if (*rate_idx  == IWL_RATE_INVALID) {
                } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
                        if (num_of_ant == 2)
                                tbl->lq_type = LQ_MIMO2;
-               /* MIMO3 */
                } else {
-                       if (num_of_ant == 3) {
-                               tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-                               tbl->lq_type = LQ_MIMO3;
-                       }
+                       WARN_ON_ONCE(num_of_ant == 3);
                }
        }
        return 0;
@@@ -607,10 -581,10 +581,10 @@@ static u16 rs_get_supported_rates(struc
        } else {
                if (is_siso(rate_type))
                        return lq_sta->active_siso_rate;
-               else if (is_mimo2(rate_type))
+               else {
+                       WARN_ON_ONCE(!is_mimo2(rate_type));
                        return lq_sta->active_mimo2_rate;
-               else
-                       return lq_sta->active_mimo3_rate;
+               }
        }
  }
  
@@@ -985,7 -959,7 +959,7 @@@ static void rs_set_expected_tpt_table(s
        }
  
        /* Choose among many HT tables depending on number of streams
-        * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+        * (SISO/MIMO2), channel width (20/40), SGI, and aggregation
         * status */
        if (is_siso(tbl->lq_type) && !tbl->is_ht40)
                ht_tbl_pointer = expected_tpt_siso20MHz;
                ht_tbl_pointer = expected_tpt_siso40MHz;
        else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40)
                ht_tbl_pointer = expected_tpt_mimo2_20MHz;
-       else if (is_mimo2(tbl->lq_type))
+       else {
+               WARN_ON_ONCE(!is_mimo2(tbl->lq_type));
                ht_tbl_pointer = expected_tpt_mimo2_40MHz;
-       else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40)
-               ht_tbl_pointer = expected_tpt_mimo3_20MHz;
-       else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
-               ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+       }
  
        if (!tbl->is_SGI && !lq_sta->is_agg)            /* Normal */
                tbl->expected_tpt = ht_tbl_pointer[0];
@@@ -1169,58 -1141,6 +1141,6 @@@ static int rs_switch_to_mimo2(struct iw
        return 0;
  }
  
- /*
-  * Set up search table for MIMO3
-  */
- static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
-                            struct iwl_lq_sta *lq_sta,
-                            struct ieee80211_sta *sta,
-                            struct iwl_scale_tbl_info *tbl, int index)
- {
-       u16 rate_mask;
-       s32 rate;
-       s8 is_green = lq_sta->is_green;
-       if (!sta->ht_cap.ht_supported)
-               return -1;
-       if (sta->smps_mode == IEEE80211_SMPS_STATIC)
-               return -1;
-       /* Need both Tx chains/antennas to support MIMO */
-       if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3)
-               return -1;
-       IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n");
-       tbl->lq_type = LQ_MIMO3;
-       tbl->action = 0;
-       tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-       rate_mask = lq_sta->active_mimo3_rate;
-       if (iwl_is_ht40_tx_allowed(sta))
-               tbl->is_ht40 = 1;
-       else
-               tbl->is_ht40 = 0;
-       rs_set_expected_tpt_table(lq_sta, tbl);
-       rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
-       IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n",
-                      rate, rate_mask);
-       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-               IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
-                              rate, rate_mask);
-               return -1;
-       }
-       tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
-       IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
-                      tbl->current_rate, is_green);
-       return 0;
- }
  /*
   * Set up search table for SISO
   */
@@@ -1330,21 -1250,14 +1250,14 @@@ static int rs_move_legacy_other(struct 
                        }
  
                        break;
-               case IWL_LEGACY_SWITCH_MIMO2_AB:
-               case IWL_LEGACY_SWITCH_MIMO2_AC:
-               case IWL_LEGACY_SWITCH_MIMO2_BC:
+               case IWL_LEGACY_SWITCH_MIMO2:
                        IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n");
  
                        /* Set up search table to try MIMO */
                        memcpy(search_tbl, tbl, sz);
                        search_tbl->is_SGI = 0;
  
-                       if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
+                       search_tbl->ant_type = ANT_AB;
  
                        if (!rs_is_valid_ant(valid_tx_ant,
                                             search_tbl->ant_type))
                                goto out;
                        }
                        break;
-               case IWL_LEGACY_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n");
-                       /* Set up search table to try MIMO3 */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       search_tbl->ant_type = ANT_ABC;
-                       if (!rs_is_valid_ant(valid_tx_ant,
-                                            search_tbl->ant_type))
-                               break;
-                       ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
-                                                search_tbl, index);
-                       if (!ret) {
-                               lq_sta->action_counter = 0;
-                               goto out;
-                       }
-                       break;
+               default:
+                       WARN_ON_ONCE(1);
                }
                tbl->action++;
-               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+               if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
                        tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
  
                if (tbl->action == start_action)
  out:
        lq_sta->search_better_tbl = 1;
        tbl->action++;
-       if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+       if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
                tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
        if (update_search_tbl_counter)
                search_tbl->action = tbl->action;
@@@ -1427,7 -1321,7 +1321,7 @@@ static int rs_move_siso_to_other(struc
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
                if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
+                       tbl->action = IWL_SISO_SWITCH_MIMO2;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
                                goto out;
                        }
                        break;
-               case IWL_SISO_SWITCH_MIMO2_AB:
-               case IWL_SISO_SWITCH_MIMO2_AC:
-               case IWL_SISO_SWITCH_MIMO2_BC:
+               case IWL_SISO_SWITCH_MIMO2:
                        IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
                        memcpy(search_tbl, tbl, sz);
                        search_tbl->is_SGI = 0;
  
-                       if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
+                       search_tbl->ant_type = ANT_AB;
  
                        if (!rs_is_valid_ant(valid_tx_ant,
                                             search_tbl->ant_type))
                                                      index, is_green);
                        update_search_tbl_counter = 1;
                        goto out;
-               case IWL_SISO_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       search_tbl->ant_type = ANT_ABC;
-                       if (!rs_is_valid_ant(valid_tx_ant,
-                                            search_tbl->ant_type))
-                               break;
-                       ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
+               default:
+                       WARN_ON_ONCE(1);
                }
                tbl->action++;
-               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+               if (tbl->action > IWL_SISO_SWITCH_GI)
                        tbl->action = IWL_SISO_SWITCH_ANTENNA1;
  
                if (tbl->action == start_action)
   out:
        lq_sta->search_better_tbl = 1;
        tbl->action++;
-       if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
+       if (tbl->action > IWL_SISO_SWITCH_GI)
                tbl->action = IWL_SISO_SWITCH_ANTENNA1;
        if (update_search_tbl_counter)
                search_tbl->action = tbl->action;
@@@ -1592,8 -1466,7 +1466,7 @@@ static int rs_move_mimo2_to_other(struc
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
-                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
                        tbl->action = IWL_MIMO2_SWITCH_SISO_A;
                break;
        default:
                        break;
                case IWL_MIMO2_SWITCH_SISO_A:
                case IWL_MIMO2_SWITCH_SISO_B:
-               case IWL_MIMO2_SWITCH_SISO_C:
                        IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n");
  
                        /* Set up new search table for SISO */
  
                        if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
                                search_tbl->ant_type = ANT_A;
-                       else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+                       else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */
                                search_tbl->ant_type = ANT_B;
-                       else
-                               search_tbl->ant_type = ANT_C;
  
                        if (!rs_is_valid_ant(valid_tx_ant,
                                             search_tbl->ant_type))
                                                      index, is_green);
                        update_search_tbl_counter = 1;
                        goto out;
-               case IWL_MIMO2_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       search_tbl->ant_type = ANT_ABC;
-                       if (!rs_is_valid_ant(valid_tx_ant,
-                                            search_tbl->ant_type))
-                               break;
-                       ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
+               default:
+                       WARN_ON_ONCE(1);
                }
                tbl->action++;
-               if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+               if (tbl->action > IWL_MIMO2_SWITCH_GI)
                        tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
  
                if (tbl->action == start_action)
   out:
        lq_sta->search_better_tbl = 1;
        tbl->action++;
-       if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+       if (tbl->action > IWL_MIMO2_SWITCH_GI)
                tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
        if (update_search_tbl_counter)
                search_tbl->action = tbl->action;
        return 0;
  }
  
- /*
-  * Try to switch to new modulation mode from MIMO3
-  */
- static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
-                                struct iwl_lq_sta *lq_sta,
-                                struct ieee80211_sta *sta, int index)
- {
-       s8 is_green = lq_sta->is_green;
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-       struct iwl_rate_scale_data *window = &(tbl->win[index]);
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action;
-       u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
-       u8 tx_chains_num = num_of_ant(valid_tx_ant);
-       int ret;
-       u8 update_search_tbl_counter = 0;
-       switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               /* nothing */
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               /* avoid antenna B and MIMO */
-               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
-                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
-                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
-                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-               break;
-       default:
-               IWL_ERR(mvm, "Invalid BT load %d",
-                       BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
-               break;
-       }
-       start_action = tbl->action;
-       while (1) {
-               lq_sta->action_counter++;
-               switch (tbl->action) {
-               case IWL_MIMO3_SWITCH_ANTENNA1:
-               case IWL_MIMO3_SWITCH_ANTENNA2:
-                       IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n");
-                       if (tx_chains_num <= 3)
-                               break;
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
-                               break;
-                       memcpy(search_tbl, tbl, sz);
-                       if (rs_toggle_antenna(valid_tx_ant,
-                                             &search_tbl->current_rate,
-                                             search_tbl))
-                               goto out;
-                       break;
-               case IWL_MIMO3_SWITCH_SISO_A:
-               case IWL_MIMO3_SWITCH_SISO_B:
-               case IWL_MIMO3_SWITCH_SISO_C:
-                       IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n");
-                       /* Set up new search table for SISO */
-                       memcpy(search_tbl, tbl, sz);
-                       if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
-                               search_tbl->ant_type = ANT_A;
-                       else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
-                               search_tbl->ant_type = ANT_B;
-                       else
-                               search_tbl->ant_type = ANT_C;
-                       if (!rs_is_valid_ant(valid_tx_ant,
-                                            search_tbl->ant_type))
-                               break;
-                       ret = rs_switch_to_siso(mvm, lq_sta, sta,
-                                               search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
-               case IWL_MIMO3_SWITCH_MIMO2_AB:
-               case IWL_MIMO3_SWITCH_MIMO2_AC:
-               case IWL_MIMO3_SWITCH_MIMO2_BC:
-                       IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
-                       if (!rs_is_valid_ant(valid_tx_ant,
-                                            search_tbl->ant_type))
-                               break;
-                       ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
-               case IWL_MIMO3_SWITCH_GI:
-                       if (!tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_20))
-                               break;
-                       if (tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_40))
-                               break;
-                       IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n");
-                       /* Set up new search table for MIMO */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = !tbl->is_SGI;
-                       rs_set_expected_tpt_table(lq_sta, search_tbl);
-                       /*
-                        * If active table already uses the fastest possible
-                        * modulation (dual stream with short guard interval),
-                        * and it's working well, there's no need to look
-                        * for a better type of modulation!
-                        */
-                       if (tbl->is_SGI) {
-                               s32 tpt = lq_sta->last_tpt / 100;
-                               if (tpt >= search_tbl->expected_tpt[index])
-                                       break;
-                       }
-                       search_tbl->current_rate =
-                               rate_n_flags_from_tbl(mvm, search_tbl,
-                                                     index, is_green);
-                       update_search_tbl_counter = 1;
-                       goto out;
-               }
-               tbl->action++;
-               if (tbl->action > IWL_MIMO3_SWITCH_GI)
-                       tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-               if (tbl->action == start_action)
-                       break;
-       }
-       search_tbl->lq_type = LQ_NONE;
-       return 0;
-  out:
-       lq_sta->search_better_tbl = 1;
-       tbl->action++;
-       if (tbl->action > IWL_MIMO3_SWITCH_GI)
-               tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-       if (update_search_tbl_counter)
-               search_tbl->action = tbl->action;
-       return 0;
- }
  /*
   * Check whether we should continue using same modulation mode, or
   * begin search for a new mode, based on:
@@@ -2289,8 -1979,7 +1979,7 @@@ static void rs_rate_scale_perform(struc
                scale_action = 0;
  
        if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
-            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) {
                if (lq_sta->last_bt_traffic >
                    BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
                        /*
                BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD);
  
        if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
-            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) {
                /* search for a new modulation */
                rs_stay_in_table(lq_sta, true);
                goto lq_update;
@@@ -2368,7 -2056,7 +2056,7 @@@ lq_update
                else if (is_mimo2(tbl->lq_type))
                        rs_move_mimo2_to_other(mvm, lq_sta, sta, index);
                else
-                       rs_move_mimo3_to_other(mvm, lq_sta, sta, index);
+                       WARN_ON_ONCE(1);
  
                /* If new "search" mode was selected, set up in uCode table */
                if (lq_sta->search_better_tbl) {
@@@ -2533,11 -2221,10 +2221,10 @@@ static void rs_get_rate(void *mvm_r, st
                rate_idx -= IWL_FIRST_OFDM_RATE;
                /* 6M and 9M shared same MCS index */
                rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
+               WARN_ON_ONCE(rs_extract_rate(lq_sta->last_rate_n_flags) >=
+                            IWL_RATE_MIMO3_6M_PLCP);
                if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-                   IWL_RATE_MIMO3_6M_PLCP)
-                       rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
-               else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-                        IWL_RATE_MIMO2_6M_PLCP)
+                   IWL_RATE_MIMO2_6M_PLCP)
                        rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
                info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
                if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
@@@ -2636,16 -2323,10 +2323,10 @@@ void iwl_mvm_rs_rate_init(struct iwl_mv
        lq_sta->active_mimo2_rate &= ~((u16)0x2);
        lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
  
-       lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
-       lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
-       lq_sta->active_mimo3_rate &= ~((u16)0x2);
-       lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
        IWL_DEBUG_RATE(mvm,
-                      "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
+                      "SISO-RATE=%X MIMO2-RATE=%X\n",
                       lq_sta->active_siso_rate,
-                      lq_sta->active_mimo2_rate,
-                      lq_sta->active_mimo3_rate);
+                      lq_sta->active_mimo2_rate);
  
        /* These values will be overridden later */
        lq_sta->lq.single_stream_ant_msk =
@@@ -2689,7 -2370,7 +2370,7 @@@ static void rs_fill_link_cmd(struct iwl
        struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
  
        /* Override starting rate (index 0) if needed for debug purposes */
-       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+       rs_dbgfs_set_mcs(lq_sta, &new_rate);
  
        /* Interpret new_rate (rate_n_flags) */
        rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
                        }
  
                        /* Override next rate if needed for debug purposes */
-                       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+                       rs_dbgfs_set_mcs(lq_sta, &new_rate);
  
                        /* Fill next table entry */
                        lq_cmd->rs_table[index] =
                use_ht_possible = 0;
  
                /* Override next rate if needed for debug purposes */
-               rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+               rs_dbgfs_set_mcs(lq_sta, &new_rate);
  
                /* Fill next table entry */
                lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
@@@ -2823,7 -2504,7 +2504,7 @@@ static void rs_free_sta(void *mvm_r, st
  
  #ifdef CONFIG_MAC80211_DEBUGFS
  static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index)
+                            u32 *rate_n_flags)
  {
        struct iwl_mvm *mvm;
        u8 valid_tx_ant;
@@@ -2908,8 -2589,7 +2589,7 @@@ static ssize_t rs_sta_dbgfs_scale_table
           (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
        if (is_Ht(tbl->lq_type)) {
                desc += sprintf(buff+desc, " %s",
-                  (is_siso(tbl->lq_type)) ? "SISO" :
-                  ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+                  (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2");
                   desc += sprintf(buff+desc, " %s",
                   (tbl->is_ht40) ? "40MHz" : "20MHz");
                   desc += sprintf(buff+desc, " %s %s %s\n",
@@@ -3009,32 -2689,6 +2689,6 @@@ static const struct file_operations rs_
        .llseek = default_llseek,
  };
  
- static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
-                       char __user *user_buf, size_t count, loff_t *ppos)
- {
-       struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-       char buff[120];
-       int desc = 0;
-       if (is_Ht(tbl->lq_type))
-               desc += sprintf(buff+desc,
-                               "Bit Rate= %d Mb/s\n",
-                               tbl->expected_tpt[lq_sta->last_txrate_idx]);
-       else
-               desc += sprintf(buff+desc,
-                               "Bit Rate= %d Mb/s\n",
-                               iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
-       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
- }
- static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
-       .read = rs_sta_dbgfs_rate_scale_data_read,
-       .open = simple_open,
-       .llseek = default_llseek,
- };
  static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
  {
        struct iwl_lq_sta *lq_sta = mvm_sta;
        lq_sta->rs_sta_dbgfs_stats_table_file =
                debugfs_create_file("rate_stats_table", S_IRUSR, dir,
                                    lq_sta, &rs_sta_dbgfs_stats_table_ops);
-       lq_sta->rs_sta_dbgfs_rate_scale_data_file =
-               debugfs_create_file("rate_scale_data", S_IRUSR, dir,
-                                   lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
        lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
                debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
                                  &lq_sta->tx_agg_tid_en);
@@@ -3057,7 -2708,6 +2708,6 @@@ static void rs_remove_debugfs(void *mvm
        struct iwl_lq_sta *lq_sta = mvm_sta;
        debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
        debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
-       debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
        debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
  }
  #endif
   * station is added we ignore it.
   */
  static void rs_rate_init_stub(void *mvm_r,
 -                               struct ieee80211_supported_band *sband,
 -                               struct ieee80211_sta *sta, void *mvm_sta)
 +                            struct ieee80211_supported_band *sband,
 +                            struct cfg80211_chan_def *chandef,
 +                            struct ieee80211_sta *sta, void *mvm_sta)
  {
  }
  static struct rate_control_ops rs_mvm_ops = {
index 9f100363b17753ad711df0db9e089fffa0553ee9,7ed94a089d5e1837fa02142085254b0292734a6d..f5329d22840e91de227fd42aeb1bd8b1506327c7
@@@ -73,6 -73,7 +73,6 @@@
  #include "iwl-prph.h"
  
  /* A TimeUnit is 1024 microsecond */
 -#define TU_TO_JIFFIES(_tu)    (usecs_to_jiffies((_tu) * 1024))
  #define MSEC_TO_TU(_msec)     (_msec*1000/1024)
  
  /*
@@@ -165,7 -166,7 +165,7 @@@ static void iwl_mvm_te_handle_notif(str
        WARN_ONCE(!le32_to_cpu(notif->status),
                  "Failed to schedule time event\n");
  
-       if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
+       if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) {
                IWL_DEBUG_TE(mvm,
                             "TE ended - current time %lu, estimated end %lu\n",
                             jiffies, te_data->end_jiffies);
                }
  
                iwl_mvm_te_clear_data(mvm, te_data);
-       } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
+       } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
                te_data->running = true;
 -              te_data->end_jiffies = jiffies +
 -                      TU_TO_JIFFIES(te_data->duration);
 +              te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration);
  
                if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
@@@ -255,10 -257,67 +255,67 @@@ static bool iwl_mvm_time_event_response
        return true;
  }
  
+ /* used to convert from time event API v2 to v1 */
+ #define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\
+                            TE_V2_EVENT_SOCIOPATHIC)
+ static inline u16 te_v2_get_notify(__le16 policy)
+ {
+       return le16_to_cpu(policy) & TE_V2_NOTIF_MSK;
+ }
+ static inline u16 te_v2_get_dep_policy(__le16 policy)
+ {
+       return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >>
+               TE_V2_PLACEMENT_POS;
+ }
+ static inline u16 te_v2_get_absence(__le16 policy)
+ {
+       return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS;
+ }
+ static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2,
+                               struct iwl_time_event_cmd_v1 *cmd_v1)
+ {
+       cmd_v1->id_and_color = cmd_v2->id_and_color;
+       cmd_v1->action = cmd_v2->action;
+       cmd_v1->id = cmd_v2->id;
+       cmd_v1->apply_time = cmd_v2->apply_time;
+       cmd_v1->max_delay = cmd_v2->max_delay;
+       cmd_v1->depends_on = cmd_v2->depends_on;
+       cmd_v1->interval = cmd_v2->interval;
+       cmd_v1->duration = cmd_v2->duration;
+       if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS)
+               cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS);
+       else
+               cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat);
+       cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags);
+       cmd_v1->interval_reciprocal = 0; /* unused */
+       cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy));
+       cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy));
+       cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy));
+ }
+ static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm,
+                                      const struct iwl_time_event_cmd_v2 *cmd)
+ {
+       struct iwl_time_event_cmd_v1 cmd_v1;
+       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2)
+               return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+                                           sizeof(*cmd), cmd);
+       iwl_mvm_te_v2_to_v1(cmd, &cmd_v1);
+       return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+                                   sizeof(cmd_v1), &cmd_v1);
+ }
  static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif,
                                       struct iwl_mvm_time_event_data *te_data,
-                                      struct iwl_time_event_cmd *te_cmd)
+                                      struct iwl_time_event_cmd_v2 *te_cmd)
  {
        static const u8 time_event_response[] = { TIME_EVENT_CMD };
        struct iwl_notification_wait wait_time_event;
                                   ARRAY_SIZE(time_event_response),
                                   iwl_mvm_time_event_response, te_data);
  
-       ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
-                                  sizeof(*te_cmd), te_cmd);
+       ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd);
        if (ret) {
                IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
                iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
@@@ -322,12 -380,13 +378,12 @@@ void iwl_mvm_protect_session(struct iwl
  {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
-       struct iwl_time_event_cmd time_cmd = {};
+       struct iwl_time_event_cmd_v2 time_cmd = {};
  
        lockdep_assert_held(&mvm->mutex);
  
        if (te_data->running &&
 -          time_after(te_data->end_jiffies,
 -                     jiffies + TU_TO_JIFFIES(min_duration))) {
 +          time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
                IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
                             jiffies_to_msecs(te_data->end_jiffies - jiffies));
                return;
        time_cmd.apply_time =
                cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
  
-       time_cmd.dep_policy = TE_INDEPENDENT;
-       time_cmd.is_present = cpu_to_le32(1);
-       time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE);
+       time_cmd.max_frags = TE_V2_FRAG_NONE;
        time_cmd.max_delay = cpu_to_le32(500);
        /* TODO: why do we need to interval = bi if it is not periodic? */
        time_cmd.interval = cpu_to_le32(1);
-       time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
        time_cmd.duration = cpu_to_le32(duration);
-       time_cmd.repeat = cpu_to_le32(1);
-       time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
-                                     TE_NOTIF_HOST_EVENT_END);
+       time_cmd.repeat = 1;
+       time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
+                                     TE_V2_NOTIF_HOST_EVENT_END);
  
        iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
  }
@@@ -380,7 -436,7 +433,7 @@@ void iwl_mvm_remove_time_event(struct i
                               struct iwl_mvm_vif *mvmvif,
                               struct iwl_mvm_time_event_data *te_data)
  {
-       struct iwl_time_event_cmd time_cmd = {};
+       struct iwl_time_event_cmd_v2 time_cmd = {};
        u32 id, uid;
        int ret;
  
                cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
  
        IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
-       ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
-                                  sizeof(time_cmd), &time_cmd);
+       ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd);
        if (WARN_ON(ret))
                return;
  }
@@@ -438,7 -493,7 +490,7 @@@ int iwl_mvm_start_p2p_roc(struct iwl_mv
  {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
-       struct iwl_time_event_cmd time_cmd = {};
+       struct iwl_time_event_cmd_v2 time_cmd = {};
  
        lockdep_assert_held(&mvm->mutex);
        if (te_data->running) {
        }
  
        time_cmd.apply_time = cpu_to_le32(0);
-       time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
-       time_cmd.is_present = cpu_to_le32(1);
        time_cmd.interval = cpu_to_le32(1);
  
        /*
         * scheduled. To improve the chances of it being scheduled, allow them
         * to be fragmented, and in addition allow them to be delayed.
         */
-       time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20);
+       time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS);
        time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
        time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
-       time_cmd.repeat = cpu_to_le32(1);
-       time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
-                                     TE_NOTIF_HOST_EVENT_END);
+       time_cmd.repeat = 1;
+       time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
+                                     TE_V2_NOTIF_HOST_EVENT_END);
  
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
  }
index 158669ee4ce56fbab7b987dee2f9aa3207f8229f,567ef014c30ad8a32040447f01966054e636b46c..dc02cb9792afbbb48c23f01d748c262bee1828fd
@@@ -130,7 -130,6 +130,7 @@@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_c
        {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
 +      {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
  
        {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
@@@ -325,15 -324,15 +325,15 @@@ static int iwl_pci_probe(struct pci_de
        int ret;
  
        iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
-       if (iwl_trans == NULL)
-               return -ENOMEM;
+       if (IS_ERR(iwl_trans))
+               return PTR_ERR(iwl_trans);
  
        pci_set_drvdata(pdev, iwl_trans);
  
        trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
        trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
  
-       if (IS_ERR_OR_NULL(trans_pcie->drv)) {
+       if (IS_ERR(trans_pcie->drv)) {
                ret = PTR_ERR(trans_pcie->drv);
                goto out_free_trans;
        }
index 68837d4e9fa09f6bfa7199384e113a5cfc681ac4,3f237b42eb36d3c94cc84f94d0ba86b6a7861e41..a4c7aeb786d24fe9dfd70a9e94b95b0395203b65
   */
  static int iwl_rxq_space(const struct iwl_rxq *rxq)
  {
-       int s = rxq->read - rxq->write;
-       if (s <= 0)
-               s += RX_QUEUE_SIZE;
-       /* keep some buffer to not confuse full and empty queue */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
+       /* Make sure RX_QUEUE_SIZE is a power of 2 */
+       BUILD_BUG_ON(RX_QUEUE_SIZE & (RX_QUEUE_SIZE - 1));
+       /*
+        * There can be up to (RX_QUEUE_SIZE - 1) free slots, to avoid ambiguity
+        * between empty and completely full queues.
+        * The following is equivalent to modulo by RX_QUEUE_SIZE and is well
+        * defined for negative dividends.
+        */
+       return (rxq->read - rxq->write - 1) & (RX_QUEUE_SIZE - 1);
  }
  
  /*
@@@ -888,14 -889,6 +889,14 @@@ irqreturn_t iwl_pcie_irq_handler(int ir
  
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
 +                      /*
 +                       * Clear the interrupt in APMG if the NIC is going down.
 +                       * Note that when the NIC exits RFkill (else branch), we
 +                       * can't access prph and the NIC will be reset in
 +                       * start_hw anyway.
 +                       */
 +                      iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
 +                                     APMG_RTC_INT_STT_RFKILL);
                        set_bit(STATUS_RFKILL, &trans_pcie->status);
                        if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
                                               &trans_pcie->status))
@@@ -1128,6 -1121,7 +1129,7 @@@ static irqreturn_t iwl_pcie_isr(int irq
        struct iwl_trans *trans = data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 inta, inta_mask;
+       irqreturn_t ret = IRQ_NONE;
  
        lockdep_assert_held(&trans_pcie->irq_lock);
  
        /* the thread will service interrupts and re-enable them */
        if (likely(inta))
                return IRQ_WAKE_THREAD;
-       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-                !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-       return IRQ_HANDLED;
+       ret = IRQ_HANDLED;
  
  none:
        /* re-enable interrupts here since we don't have anything to service. */
            !trans_pcie->inta)
                iwl_enable_interrupts(trans);
  
-       return IRQ_NONE;
+       return ret;
  }
  
  /* interrupt handler using ict table, with this interrupt driver will
@@@ -1207,6 -1199,7 +1207,7 @@@ irqreturn_t iwl_pcie_isr_ict(int irq, v
        u32 val = 0;
        u32 read;
        unsigned long flags;
+       irqreturn_t ret = IRQ_NONE;
  
        if (!trans)
                return IRQ_NONE;
         * use legacy interrupt.
         */
        if (unlikely(!trans_pcie->use_ict)) {
-               irqreturn_t ret = iwl_pcie_isr(irq, data);
+               ret = iwl_pcie_isr(irq, data);
                spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
                return ret;
        }
        if (likely(inta)) {
                spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
                return IRQ_WAKE_THREAD;
-       } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-                !trans_pcie->inta) {
-               /* Allow interrupt if was disabled by this handler and
-                * no tasklet was schedules, We should not enable interrupt,
-                * tasklet will enable it.
-                */
-               iwl_enable_interrupts(trans);
        }
  
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_HANDLED;
+       ret = IRQ_HANDLED;
  
   none:
        /* re-enable interrupts here since we don't have anything to service.
                iwl_enable_interrupts(trans);
  
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_NONE;
+       return ret;
  }
index e52d1ce1501c3c580c6934c501407e17406c56e3,ff9787fac205f934e7505ace4ccb491f53cd81c1..bad95d28d50da52158ff102de3fc9855e46a662b
@@@ -670,11 -670,6 +670,11 @@@ static int iwl_trans_pcie_start_hw(stru
                return err;
        }
  
 +      /* Reset the entire device */
 +      iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 +
 +      usleep_range(10, 15);
 +
        iwl_pcie_apm_init(trans);
  
        /* From now on, the op_mode will be kept updated about RF kill state */
@@@ -1386,9 -1381,10 +1386,10 @@@ struct iwl_trans *iwl_trans_pcie_alloc(
  
        trans = kzalloc(sizeof(struct iwl_trans) +
                        sizeof(struct iwl_trans_pcie), GFP_KERNEL);
-       if (!trans)
-               return NULL;
+       if (!trans) {
+               err = -ENOMEM;
+               goto out;
+       }
  
        trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  
                                       PCIE_LINK_STATE_CLKPM);
        }
  
-       if (pci_enable_device(pdev)) {
-               err = -ENODEV;
+       err = pci_enable_device(pdev);
+       if (err)
                goto out_no_pci;
-       }
  
        pci_set_master(pdev);
  
                                  SLAB_HWCACHE_ALIGN,
                                  NULL);
  
-       if (!trans->dev_cmd_pool)
+       if (!trans->dev_cmd_pool) {
+               err = -ENOMEM;
                goto out_pci_disable_msi;
+       }
  
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
  
        if (iwl_pcie_alloc_ict(trans))
                goto out_free_cmd_pool;
  
-       if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
-                                iwl_pcie_irq_handler,
-                                IRQF_SHARED, DRV_NAME, trans)) {
+       err = request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+                                  iwl_pcie_irq_handler,
+                                  IRQF_SHARED, DRV_NAME, trans);
+       if (err) {
                IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
                goto out_free_ict;
        }
@@@ -1512,5 -1510,6 +1515,6 @@@ out_pci_disable_device
        pci_disable_device(pdev);
  out_no_pci:
        kfree(trans);
-       return NULL;
+ out:
+       return ERR_PTR(err);
  }