Merge tag 'iwlwifi-next-for-john-2014-10-29' of git://git.kernel.org/pub/scm/linux...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 30 Oct 2014 19:22:06 +0000 (15:22 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 30 Oct 2014 19:22:06 +0000 (15:22 -0400)
Emmanuel Grumbach <egrumbach@gmail.com> says:

"The big new thing here is netdetect which allows the
firmware to wake up the platform when a specific network
is detected. Along with that I have fixes for d3 operation.
The usual amount of rate scaling stuff - we now support STBC.
The other commit that stands out is Johannes's work on
devcoredump. He basically starts to use the standard
infrastructure he built."

Signed-off-by: John W. Linville <linville@tuxdriver.com>
29 files changed:
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index 267e48a..139de90 100644 (file)
@@ -59,6 +59,7 @@ config IWLDVM
 
 config IWLMVM
        tristate "Intel Wireless WiFi MVM Firmware support"
+       select BACKPORT_WANT_DEV_COREDUMP
        help
          This is the driver that supports the MVM firmware which is
          currently only available for 7260 and 3160 devices.
index 2191621..02e4ede 100644 (file)
@@ -418,8 +418,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
 
 static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
 {
-       return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
-                       BT_UART_MSG_FRAME3SCOESCO_POS;
+       return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+               BT_UART_MSG_FRAME3SCOESCO_POS;
 }
 
 static void iwlagn_bt_traffic_change_work(struct work_struct *work)
index 2364a3c..cae692f 100644 (file)
@@ -1095,6 +1095,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                             u32 queues, bool drop)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       u32 scd_queues;
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -1108,18 +1109,19 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                goto done;
        }
 
-       /*
-        * mac80211 will not push any more frames for transmit
-        * until the flush is completed
-        */
-       if (drop) {
-               IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, 0)) {
-                       IWL_ERR(priv, "flush request fail\n");
-                       goto done;
-               }
+       scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1;
+       scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
+                       BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
+
+       if (vif)
+               scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
+
+       IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
+       if (iwlagn_txfifo_flush(priv, scd_queues)) {
+               IWL_ERR(priv, "flush request fail\n");
+               goto done;
        }
-       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+       IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
        iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
 done:
        mutex_unlock(&priv->mutex);
index e435148..896ea90 100644 (file)
@@ -82,7 +82,8 @@
 #define IWL8000_TX_POWER_VERSION       0xffff /* meaningless */
 
 #define IWL8000_FW_PRE "iwlwifi-8000"
-#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
+#define IWL8000_MODULE_FIRMWARE(api) \
+       IWL8000_FW_PRE "-" __stringify(api) ".ucode"
 
 #define NVM_HW_SECTION_NUM_FAMILY_8000         10
 #define DEFAULT_NVM_FILE_FAMILY_8000           "iwl_nvm_8000.bin"
@@ -103,6 +104,7 @@ static const struct iwl_base_params iwl8000_base_params = {
 };
 
 static const struct iwl_ht_params iwl8000_ht_params = {
+       .stbc = true,
        .ldpc = true,
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
index 2ef83a3..f8aa9cf 100644 (file)
@@ -87,6 +87,16 @@ enum iwl_device_family {
        IWL_DEVICE_FAMILY_8000,
 };
 
+static inline bool iwl_has_secure_boot(u32 hw_rev,
+                                      enum iwl_device_family family)
+{
+       /* return 1 only for family 8000 B0 */
+       if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC))
+               return 1;
+
+       return 0;
+}
+
 /*
  * LED mode
  *    IWL_LED_DEFAULT:  use device default
@@ -246,6 +256,7 @@ struct iwl_pwr_tx_backoff {
  * @nvm_hw_section_num: the ID of the HW NVM section
  * @pwr_tx_backoffs: translation table between power limits and backoffs
  * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
+ * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -285,6 +296,7 @@ struct iwl_cfg {
        const char *default_nvm_file;
        unsigned int max_rx_agg_size;
        bool disable_dummy_notification;
+       unsigned int max_tx_agg_size;
 };
 
 /*
index 0f1084f..d9fa8e0 100644 (file)
@@ -807,19 +807,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
                        break;
                case IWL_UCODE_TLV_SECURE_SEC_INIT:
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_INIT].is_secure = true;
                        break;
                case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
                        break;
                case IWL_UCODE_TLV_NUM_OF_CPU:
                        if (tlv_len != sizeof(u32))
index 4f6e668..6f7ae5f 100644 (file)
@@ -227,7 +227,6 @@ struct fw_desc {
 
 struct fw_img {
        struct fw_desc sec[IWL_UCODE_SECTION_MAX];
-       bool is_secure;
        bool is_dual_cpus;
 };
 
index 9eb8524..0768f83 100644 (file)
@@ -535,9 +535,7 @@ struct iwl_trans_ops {
        void (*ref)(struct iwl_trans *trans);
        void (*unref)(struct iwl_trans *trans);
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
-#endif
 };
 
 /**
@@ -563,6 +561,7 @@ enum iwl_trans_state {
  *     Set during transport allocation.
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
  * @pm_support: set to true in start_hw if link pm is supported
+ * @ltr_enabled: set to true if the LTR is enabled
  * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
  *     The user should use iwl_trans_{alloc,free}_tx_cmd.
  * @dev_cmd_headroom: room needed for the transport's private use before the
@@ -589,6 +588,7 @@ struct iwl_trans {
        u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
 
        bool pm_support;
+       bool ltr_enabled;
 
        /* The following fields are internal only */
        struct kmem_cache *dev_cmd_pool;
@@ -702,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
                trans->ops->unref(trans);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 static inline struct iwl_trans_dump_data *
 iwl_trans_dump_data(struct iwl_trans *trans)
 {
@@ -710,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans)
                return NULL;
        return trans->ops->dump_data(trans);
 }
-#endif
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
                                     struct iwl_host_cmd *cmd)
index 8df2021..508c813 100644 (file)
@@ -72,8 +72,6 @@
 #include "mvm.h"
 #include "iwl-debug.h"
 
-#define BT_ANTENNA_COUPLING_THRESHOLD          (30)
-
 const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
        [BT_KILL_MSK_DEFAULT] = 0xfffffc00,
        [BT_KILL_MSK_NEVER] = 0xffffffff,
@@ -302,11 +300,6 @@ static const __le64 iwl_ci_mask[][3] = {
        },
 };
 
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
-       cpu_to_le32(0x28412201),
-       cpu_to_le32(0x11118451),
-};
-
 struct corunning_block_luts {
        u8 range;
        __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
@@ -605,7 +598,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
 
        bt_cmd->max_kill = cpu_to_le32(5);
        bt_cmd->bt4_antenna_isolation_thr =
-                               cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD);
+               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);
@@ -638,8 +631,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
 
        memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
               sizeof(iwl_bt_prio_boost));
-       memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
-              sizeof(iwl_bt_mprio_lut));
+       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));
index 585c0ab..b571e1b 100644 (file)
@@ -102,8 +102,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
 
 #undef EVENT_PRIO_ANT
 
-#define BT_ANTENNA_COUPLING_THRESHOLD          (30)
-
 static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
 {
        if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
@@ -290,11 +288,6 @@ static const __le64 iwl_ci_mask[][3] = {
        },
 };
 
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
-       cpu_to_le32(0x28412201),
-       cpu_to_le32(0x11118451),
-};
-
 struct corunning_block_luts {
        u8 range;
        __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
@@ -593,7 +586,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
        }
 
        bt_cmd->max_kill = 5;
-       bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
+       bt_cmd->bt4_antenna_isolation_thr =
+               IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS;
        bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
        bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
        bt_cmd->bt4_tx_rx_max_freq0 = 15;
@@ -649,8 +643,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
 
        memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
               sizeof(iwl_bt_prio_boost));
-       memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
-              sizeof(iwl_bt_mprio_lut));
+       bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
+       bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
 
 send_cmd:
        memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
index d4dfbe4..5c1ea80 100644 (file)
 #define IWL_MVM_BT_COEX_SYNC2SCO               1
 #define IWL_MVM_BT_COEX_CORUNNING              0
 #define IWL_MVM_BT_COEX_MPLUT                  1
+#define IWL_MVM_BT_COEX_MPLUT_REG0             0x2e402280
+#define IWL_MVM_BT_COEX_MPLUT_REG1             0x7711a751
+#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS  30
 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL       0
+#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL       0
 #define IWL_MVM_QUOTA_THRESHOLD                        8
 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0
+#define IWL_MVM_RS_DISABLE_MIMO                        0
 
 #endif /* __MVM_CONSTANTS_H */
index c17be0f..3bbb511 100644 (file)
@@ -601,33 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
        return ret;
 }
 
-struct iwl_d3_iter_data {
-       struct iwl_mvm *mvm;
-       struct ieee80211_vif *vif;
-       bool error;
-};
-
-static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
-                                     struct ieee80211_vif *vif)
-{
-       struct iwl_d3_iter_data *data = _data;
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
-       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
-               return;
-
-       if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
-               return;
-
-       if (data->vif) {
-               IWL_ERR(data->mvm, "More than one managed interface active!\n");
-               data->error = true;
-               return;
-       }
-
-       data->vif = vif;
-}
-
 static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                struct ieee80211_sta *ap_sta)
 {
@@ -783,6 +756,35 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                IWL_ERR(mvm, "failed to set non-QoS seqno\n");
 }
 
+static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
+{
+       iwl_mvm_cancel_scan(mvm);
+
+       iwl_trans_stop_device(mvm->trans);
+
+       /*
+        * Set the HW restart bit -- this is mostly true as we're
+        * going to load new firmware and reprogram that, though
+        * the reprogramming is going to be manual to avoid adding
+        * all the MACs that aren't support.
+        * We don't have to clear up everything though because the
+        * reprogramming is manual. When we resume, we'll actually
+        * go through a proper restart sequence again to switch
+        * back to the runtime firmware image.
+        */
+       set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+       /* We reprogram keys and shouldn't allocate new key indices */
+       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
+       mvm->ptk_ivlen = 0;
+       mvm->ptk_icvlen = 0;
+       mvm->ptk_ivlen = 0;
+       mvm->ptk_icvlen = 0;
+
+       return iwl_mvm_load_d3_fw(mvm);
+}
+
 static int
 iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
                               const struct iwl_wowlan_config_cmd_v3 *cmd)
@@ -797,116 +799,52 @@ iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
                                    cmd_len, cmd);
 }
 
-static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
-                            struct cfg80211_wowlan *wowlan,
-                            bool test)
+static int
+iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
+                         struct cfg80211_wowlan *wowlan,
+                         struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+                         struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+                         struct ieee80211_sta *ap_sta)
 {
-       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct iwl_d3_iter_data suspend_iter_data = {
-               .mvm = mvm,
-       };
-       struct ieee80211_vif *vif;
-       struct iwl_mvm_vif *mvmvif;
-       struct ieee80211_sta *ap_sta;
-       struct iwl_mvm_sta *mvm_ap_sta;
-       struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
-       struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
-       struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct iwl_d3_manager_config d3_cfg_cmd_data = {
-               /*
-                * Program the minimum sleep time to 10 seconds, as many
-                * platforms have issues processing a wakeup signal while
-                * still being in the process of suspending.
-                */
-               .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
-       };
-       struct iwl_host_cmd d3_cfg_cmd = {
-               .id = D3_CONFIG_CMD,
-               .flags = CMD_WANT_SKB,
-               .data[0] = &d3_cfg_cmd_data,
-               .len[0] = sizeof(d3_cfg_cmd_data),
-       };
-       struct wowlan_key_data key_data = {
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
        int ret;
-       int len __maybe_unused;
-
-       if (!wowlan) {
-               /*
-                * mac80211 shouldn't get here, but for D3 test
-                * it doesn't warrant a warning
-                */
-               WARN_ON(!test);
-               return -EINVAL;
-       }
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc)
-               return -ENOMEM;
-
-       mutex_lock(&mvm->mutex);
-
-       /* see if there's only a single BSS vif and it's associated */
-       ieee80211_iterate_active_interfaces_atomic(
-               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-               iwl_mvm_d3_iface_iterator, &suspend_iter_data);
-
-       if (suspend_iter_data.error || !suspend_iter_data.vif) {
-               ret = 1;
-               goto out_noreset;
-       }
-
-       vif = suspend_iter_data.vif;
-       mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
-       ap_sta = rcu_dereference_protected(
-                       mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
-                       lockdep_is_held(&mvm->mutex));
-       if (IS_ERR_OR_NULL(ap_sta)) {
-               ret = -EINVAL;
-               goto out_noreset;
-       }
-
-       mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+       struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
 
-       /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */
+       /* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */
 
-       wowlan_config_cmd.common.is_11n_connection =
+       wowlan_config_cmd->common.is_11n_connection =
                                        ap_sta->ht_cap.ht_supported;
 
        /* Query the last used seqno and set it */
        ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
        if (ret < 0)
-               goto out_noreset;
-       wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret);
+               return ret;
 
-       iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common);
+       wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret);
+
+       iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common);
 
        if (wowlan->disconnect)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
                                    IWL_WOWLAN_WAKEUP_LINK_CHANGE);
        if (wowlan->magic_pkt)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
        if (wowlan->gtk_rekey_failure)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
        if (wowlan->eap_identity_req)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
        if (wowlan->four_way_handshake)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
        if (wowlan->n_patterns)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
 
        if (wowlan->rfkill_release)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
 
        if (wowlan->tcp) {
@@ -914,44 +852,39 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                 * Set the "link change" (really "link lost") flag as well
                 * since that implies losing the TCP connection.
                 */
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
                                    IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
                                    IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
                                    IWL_WOWLAN_WAKEUP_LINK_CHANGE);
        }
 
-       iwl_mvm_cancel_scan(mvm);
-
-       iwl_trans_stop_device(mvm->trans);
-
-       /*
-        * Set the HW restart bit -- this is mostly true as we're
-        * going to load new firmware and reprogram that, though
-        * the reprogramming is going to be manual to avoid adding
-        * all the MACs that aren't support.
-        * We don't have to clear up everything though because the
-        * reprogramming is manual. When we resume, we'll actually
-        * go through a proper restart sequence again to switch
-        * back to the runtime firmware image.
-        */
-       set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
-
-       /* We reprogram keys and shouldn't allocate new key indices */
-       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
-
-       mvm->ptk_ivlen = 0;
-       mvm->ptk_icvlen = 0;
-       mvm->ptk_ivlen = 0;
-       mvm->ptk_icvlen = 0;
+       return 0;
+}
 
-       ret = iwl_mvm_load_d3_fw(mvm);
-       if (ret)
-               goto out;
+static int
+iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
+                     struct cfg80211_wowlan *wowlan,
+                     struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+                     struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+                     struct ieee80211_sta *ap_sta)
+{
+       struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
+       struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct wowlan_key_data key_data = {
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret;
 
        ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
        if (ret)
-               goto out;
+               return ret;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
 
        if (!iwlwifi_mod_params.sw_crypto) {
                /*
@@ -1010,7 +943,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                }
        }
 
-       ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
+       ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd);
        if (ret)
                goto out;
 
@@ -1023,8 +956,93 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                goto out;
 
        ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
-       if (ret)
-               goto out;
+
+out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+
+static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
+                            struct cfg80211_wowlan *wowlan,
+                            bool test)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct ieee80211_vif *vif = NULL;
+       struct iwl_mvm_vif *mvmvif = NULL;
+       struct ieee80211_sta *ap_sta = NULL;
+       struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
+       struct iwl_d3_manager_config d3_cfg_cmd_data = {
+               /*
+                * Program the minimum sleep time to 10 seconds, as many
+                * platforms have issues processing a wakeup signal while
+                * still being in the process of suspending.
+                */
+               .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
+       };
+       struct iwl_host_cmd d3_cfg_cmd = {
+               .id = D3_CONFIG_CMD,
+               .flags = CMD_WANT_SKB,
+               .data[0] = &d3_cfg_cmd_data,
+               .len[0] = sizeof(d3_cfg_cmd_data),
+       };
+       int ret;
+       int len __maybe_unused;
+
+       if (!wowlan) {
+               /*
+                * mac80211 shouldn't get here, but for D3 test
+                * it doesn't warrant a warning
+                */
+               WARN_ON(!test);
+               return -EINVAL;
+       }
+
+       mutex_lock(&mvm->mutex);
+
+       vif = iwl_mvm_get_bss_vif(mvm);
+       if (IS_ERR_OR_NULL(vif)) {
+               ret = 1;
+               goto out_noreset;
+       }
+
+       mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       /* if we're associated, this is wowlan */
+       if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+               ap_sta = rcu_dereference_protected(
+                       mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+                       lockdep_is_held(&mvm->mutex));
+               if (IS_ERR_OR_NULL(ap_sta)) {
+                       ret = -EINVAL;
+                       goto out_noreset;
+               }
+
+               ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+                                               vif, mvmvif, ap_sta);
+               if (ret)
+                       goto out_noreset;
+
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       goto out;
+
+               ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+                                           vif, mvmvif, ap_sta);
+               if (ret)
+                       goto out;
+       } else if (mvm->nd_config) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       goto out;
+
+               ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config,
+                                                mvm->nd_ies);
+               if (ret)
+                       goto out;
+       } else {
+               ret = 1;
+               goto out_noreset;
+       }
 
        ret = iwl_mvm_power_update_device(mvm);
        if (ret)
@@ -1060,8 +1078,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        if (ret < 0)
                ieee80211_restart_hw(mvm->hw);
  out_noreset:
-       kfree(key_data.rsc_tsc);
-
        mutex_unlock(&mvm->mutex);
 
        return ret;
@@ -1592,9 +1608,6 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
 
 static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
-       struct iwl_d3_iter_data resume_iter_data = {
-               .mvm = mvm,
-       };
        struct ieee80211_vif *vif = NULL;
        int ret;
        enum iwl_d3_status d3_status;
@@ -1603,15 +1616,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        mutex_lock(&mvm->mutex);
 
        /* get the BSS vif pointer again */
-       ieee80211_iterate_active_interfaces_atomic(
-               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-               iwl_mvm_d3_iface_iterator, &resume_iter_data);
-
-       if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
+       vif = iwl_mvm_get_bss_vif(mvm);
+       if (IS_ERR_OR_NULL(vif))
                goto out_unlock;
 
-       vif = resume_iter_data.vif;
-
        ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
        if (ret)
                goto out_unlock;
@@ -1741,7 +1749,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        int remaining_time = 10;
 
        mvm->d3_test_active = false;
+       rtnl_lock();
        __iwl_mvm_resume(mvm, true);
+       rtnl_unlock();
        iwl_abort_notification_waits(&mvm->notif_wait);
        ieee80211_restart_hw(mvm->hw);
 
index 50527a9..51b7116 100644 (file)
@@ -121,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
        return ret;
 }
 
-static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
-{
-       struct iwl_mvm *mvm = inode->i_private;
-       int ret;
-
-       if (!mvm)
-               return -EINVAL;
-
-       mutex_lock(&mvm->mutex);
-       if (!mvm->fw_error_dump) {
-               ret = -ENODATA;
-               goto out;
-       }
-
-       file->private_data = mvm->fw_error_dump;
-       mvm->fw_error_dump = NULL;
-       ret = 0;
-
-out:
-       mutex_unlock(&mvm->mutex);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-       ssize_t bytes_read = 0;
-       ssize_t bytes_read_trans = 0;
-
-       if (*ppos < dump_ptrs->op_mode_len)
-               bytes_read +=
-                       simple_read_from_buffer(user_buf, count, ppos,
-                                               dump_ptrs->op_mode_ptr,
-                                               dump_ptrs->op_mode_len);
-
-       if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
-               return bytes_read;
-
-       if (dump_ptrs->trans_ptr) {
-               *ppos -= dump_ptrs->op_mode_len;
-               bytes_read_trans =
-                       simple_read_from_buffer(user_buf + bytes_read,
-                                               count - bytes_read, ppos,
-                                               dump_ptrs->trans_ptr->data,
-                                               dump_ptrs->trans_ptr->len);
-               *ppos += dump_ptrs->op_mode_len;
-
-               if (bytes_read_trans >= 0)
-                       bytes_read += bytes_read_trans;
-               else if (!bytes_read)
-                       /* propagate the failure */
-                       return bytes_read_trans;
-       }
-
-       return bytes_read;
-
-}
-
-static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
-                                          struct file *file)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-
-       vfree(dump_ptrs->op_mode_ptr);
-       vfree(dump_ptrs->trans_ptr);
-       kfree(dump_ptrs);
-
-       return 0;
-}
-
 static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
                                   size_t count, loff_t *ppos)
 {
@@ -1250,6 +1178,126 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
 
        return ret;
 }
+
+#define MAX_NUM_ND_MATCHSETS 10
+
+static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       const char *seps = ",\n";
+       char *buf_ptr = buf;
+       char *value_str = NULL;
+       int ret, i;
+
+       /* TODO: don't free if write is being called several times in one go */
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
+
+       mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
+       if (!mvm->nd_ies)
+               return -ENOMEM;
+
+       mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
+                                (11 * sizeof(struct ieee80211_channel *)),
+                                GFP_KERNEL);
+       if (!mvm->nd_config) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       mvm->nd_config->n_channels = 11;
+       mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20;
+       mvm->nd_config->interval = 5;
+       mvm->nd_config->min_rssi_thold = -80;
+       for (i = 0; i < mvm->nd_config->n_channels; i++)
+               mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i];
+
+       mvm->nd_config->match_sets =
+               kcalloc(MAX_NUM_ND_MATCHSETS,
+                       sizeof(*mvm->nd_config->match_sets),
+                       GFP_KERNEL);
+       if (!mvm->nd_config->match_sets) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       while ((value_str = strsep(&buf_ptr, seps)) &&
+              strlen(value_str)) {
+               struct cfg80211_match_set *set;
+
+               if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets];
+               set->ssid.ssid_len = strlen(value_str);
+
+               if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len);
+
+               mvm->nd_config->n_match_sets++;
+       }
+
+       ret = count;
+
+       if (mvm->nd_config->n_match_sets)
+               goto out;
+
+out_free:
+       if (mvm->nd_config)
+               kfree(mvm->nd_config->match_sets);
+       kfree(mvm->nd_config);
+       mvm->nd_config = NULL;
+       kfree(mvm->nd_ies);
+       mvm->nd_ies = NULL;
+out:
+       return ret;
+}
+
+static ssize_t
+iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       size_t bufsz, ret;
+       char *buf;
+       int i, n_match_sets, pos = 0;
+
+       n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0;
+
+       bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < n_match_sets; i++) {
+               if (pos +
+                   mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid,
+                      mvm->nd_config->match_sets[i].ssid.ssid_len);
+               pos += mvm->nd_config->match_sets[i].ssid.ssid_len;
+               buf[pos++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+out:
+       kfree(buf);
+       return ret;
+}
 #endif
 
 #define PRINT_MVM_REF(ref) do {                                                \
@@ -1415,12 +1463,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 
-static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
-       .open = iwl_dbgfs_fw_error_dump_open,
-       .read = iwl_dbgfs_fw_error_dump_read,
-       .release = iwl_dbgfs_fw_error_dump_release,
-};
-
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
@@ -1428,6 +1470,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
 
 #ifdef CONFIG_PM_SLEEP
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
 #endif
 
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
@@ -1446,7 +1489,6 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                             S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
-       MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
@@ -1487,6 +1529,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
                goto err;
+       MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 #endif
 
        if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
index 27dd863..2fd8ad4 100644 (file)
 
 /* Power Management Commands, Responses, Notifications */
 
+/**
+ * enum iwl_ltr_config_flags - masks for LTR config command flags
+ * @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status
+ * @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow
+ *     memory access
+ * @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR
+ *     reg change
+ * @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from
+ *     D0 to D3
+ * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register
+ * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register
+ * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD
+ */
+enum iwl_ltr_config_flags {
+       LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0),
+       LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1),
+       LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2),
+       LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3),
+       LTR_CFG_FLAG_SW_SET_SHORT = BIT(4),
+       LTR_CFG_FLAG_SW_SET_LONG = BIT(5),
+       LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6),
+};
+
+/**
+ * struct iwl_ltr_config_cmd - configures the LTR
+ * @flags: See %enum iwl_ltr_config_flags
+ */
+struct iwl_ltr_config_cmd {
+       __le32 flags;
+       __le32 static_long;
+       __le32 static_short;
+} __packed;
+
 /* Radio LP RX Energy Threshold measured in dBm */
 #define POWER_LPRX_RSSI_THRESHOLD      75
 #define POWER_LPRX_RSSI_THRESHOLD_MAX  94
 #define POWER_LPRX_RSSI_THRESHOLD_MIN  30
 
 /**
- * enum iwl_scan_flags - masks for power table command flags
+ * enum iwl_power_flags - masks for power table command flags
  * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
  *             receiver and transmitter. '0' - does not allow.
  * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
index 667a922..c62575d 100644 (file)
@@ -157,6 +157,7 @@ enum {
        /* Power - legacy power table command */
        POWER_TABLE_CMD = 0x77,
        PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
+       LTR_CONFIG = 0xee,
 
        /* Thermal Throttling*/
        REPLY_THERMAL_MNG_BACKOFF = 0x7e,
index 23fd711..e0d9f19 100644 (file)
@@ -480,6 +480,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        /* Initialize tx backoffs to the minimal possible */
        iwl_mvm_tt_tx_backoff(mvm, 0);
 
+       if (mvm->trans->ltr_enabled) {
+               struct iwl_ltr_config_cmd cmd = {
+                       .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+               };
+
+               WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+                                            sizeof(cmd), &cmd));
+       }
+
        ret = iwl_mvm_power_update_device(mvm);
        if (ret)
                goto error;
index 0c5c0b0..b8ab4a1 100644 (file)
@@ -197,8 +197,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
 /*
  * Get the mask of the queues used by the vif
  */
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-                               struct ieee80211_vif *vif)
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
 {
        u32 qmask = 0, ac;
 
@@ -227,7 +226,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        }
 
        /* Mark the queues used by the vif */
-       data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
+       data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
 
        /* Mark MAC IDs as used by clearing the available bit, and
         * (below) mark TSFs as used if their existing use is not
index c7a73c6..3276b31 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
+#include <linux/devcoredump.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/tcp.h>
@@ -526,7 +527,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
        }
 
        if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
-           !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+           !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) &&
+           !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
                goto drop;
 
        /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
@@ -678,10 +680,51 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
        memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
+static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count,
+                                    const void *data, size_t datalen)
+{
+       const struct iwl_mvm_dump_ptrs *dump_ptrs = data;
+       ssize_t bytes_read;
+       ssize_t bytes_read_trans;
+
+       if (offset < dump_ptrs->op_mode_len) {
+               bytes_read = min_t(ssize_t, count,
+                                  dump_ptrs->op_mode_len - offset);
+               memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset,
+                      bytes_read);
+               offset += bytes_read;
+               count -= bytes_read;
+
+               if (count == 0)
+                       return bytes_read;
+       } else {
+               bytes_read = 0;
+       }
+
+       if (!dump_ptrs->trans_ptr)
+               return bytes_read;
+
+       offset -= dump_ptrs->op_mode_len;
+       bytes_read_trans = min_t(ssize_t, count,
+                                dump_ptrs->trans_ptr->len - offset);
+       memcpy(buffer + bytes_read,
+              (u8 *)dump_ptrs->trans_ptr->data + offset,
+              bytes_read_trans);
+
+       return bytes_read + bytes_read_trans;
+}
+
+static void iwl_mvm_free_coredump(const void *data)
+{
+       const struct iwl_mvm_dump_ptrs *fw_error_dump = data;
+
+       vfree(fw_error_dump->op_mode_ptr);
+       vfree(fw_error_dump->trans_ptr);
+       kfree(fw_error_dump);
+}
+
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 {
-       static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
        struct iwl_fw_error_dump_file *dump_file;
        struct iwl_fw_error_dump_data *dump_data;
        struct iwl_fw_error_dump_info *dump_info;
@@ -694,10 +737,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvm->fw_error_dump)
-               return;
-
-       fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
+       fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
        if (!fw_error_dump)
                return;
 
@@ -772,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        if (fw_error_dump->trans_ptr)
                file_len += fw_error_dump->trans_ptr->len;
        dump_file->file_len = cpu_to_le32(file_len);
-       mvm->fw_error_dump = fw_error_dump;
 
-       /* notify the userspace about the error we had */
-       kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
+       dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
+                     GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
 }
-#endif
 
 static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 {
@@ -1085,7 +1123,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
 static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif)
 {
-       u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
+       u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
 
        if (tfd_msk) {
                mutex_lock(&mvm->mutex);
@@ -1381,6 +1419,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
                .cmd = cmd,
        };
 
+       if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
+               return false;
+
        memset(cmd, 0, sizeof(*cmd));
        cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
        cmd->max_macs = ARRAY_SIZE(cmd->macs);
@@ -1734,6 +1775,13 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
        if (changes & BSS_CHANGED_BEACON &&
            iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
                IWL_WARN(mvm, "Failed updating beacon data\n");
+
+       if (changes & BSS_CHANGED_TXPOWER) {
+               IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
+                               bss_conf->txpower);
+               iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
+       }
+
 }
 
 static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
@@ -2162,25 +2210,9 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
 
        mvm->scan_status = IWL_MVM_SCAN_SCHED;
 
-       if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
-               ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
-               if (ret)
-                       goto err;
-       }
-
-       ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+       ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
        if (ret)
-               goto err;
-
-       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
-               ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
-       else
-               ret = iwl_mvm_sched_scan_start(mvm, req);
-
-       if (!ret)
-               goto out;
-err:
-       mvm->scan_status = IWL_MVM_SCAN_NONE;
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
 out:
        mutex_unlock(&mvm->mutex);
        return ret;
@@ -2367,14 +2399,19 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
        /* Set the node address */
        memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
 
+       lockdep_assert_held(&mvm->mutex);
+
+       spin_lock_bh(&mvm->time_event_lock);
+
+       if (WARN_ON(te_data->id == HOT_SPOT_CMD)) {
+               spin_unlock_bh(&mvm->time_event_lock);
+               return -EIO;
+       }
+
        te_data->vif = vif;
        te_data->duration = duration;
        te_data->id = HOT_SPOT_CMD;
 
-       lockdep_assert_held(&mvm->mutex);
-
-       spin_lock_bh(&mvm->time_event_lock);
-       list_add_tail(&te_data->list, &mvm->time_event_list);
        spin_unlock_bh(&mvm->time_event_lock);
 
        /*
@@ -2430,22 +2467,23 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
                           duration, type);
 
+       mutex_lock(&mvm->mutex);
+
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                /* Use aux roc framework (HS20) */
                ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
                                               vif, duration);
-               return ret;
+               goto out_unlock;
        case NL80211_IFTYPE_P2P_DEVICE:
                /* handle below */
                break;
        default:
                IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_unlock;
        }
 
-       mutex_lock(&mvm->mutex);
-
        for (i = 0; i < NUM_PHY_CTX; i++) {
                phy_ctxt = &mvm->phy_ctxts[i];
                if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
@@ -2996,18 +3034,24 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
        mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
 
-       if (WARN_ON_ONCE(!mvmsta))
-               goto done;
+       if (WARN_ON_ONCE(!mvmsta)) {
+               mutex_unlock(&mvm->mutex);
+               return;
+       }
 
        if (drop) {
                if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
                        IWL_ERR(mvm, "flush request fail\n");
+               mutex_unlock(&mvm->mutex);
        } else {
-               iwl_trans_wait_tx_queue_empty(mvm->trans,
-                                             mvmsta->tfd_queue_msk);
+               u32 tfd_queue_msk = mvmsta->tfd_queue_msk;
+               mutex_unlock(&mvm->mutex);
+
+               /* this can take a while, and we may need/want other operations
+                * to succeed while doing this, so do it without the mutex held
+                */
+               iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk);
        }
-done:
-       mutex_unlock(&mvm->mutex);
 }
 
 const struct ieee80211_ops iwl_mvm_hw_ops = {
index b153ced..256765a 100644 (file)
@@ -648,7 +648,6 @@ struct iwl_mvm {
        /* -1 for always, 0 for never, >0 for that many times */
        s8 restart_fw;
        struct work_struct fw_error_dump_wk;
-       struct iwl_mvm_dump_ptrs *fw_error_dump;
 
 #ifdef CONFIG_IWLWIFI_LEDS
        struct led_classdev led;
@@ -659,6 +658,10 @@ struct iwl_mvm {
 #ifdef CONFIG_PM_SLEEP
        struct wiphy_wowlan_support wowlan;
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
+
+       /* sched scan settings for net detect */
+       struct cfg80211_sched_scan_request *nd_config;
+       struct ieee80211_scan_ies *nd_ies;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
        bool d3_test_active;
@@ -905,8 +908,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                             bool force_assoc_off, const u8 *bssid_override);
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-                               struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
 int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
@@ -949,6 +951,10 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
                                       struct cfg80211_sched_scan_request *req);
 int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                             struct cfg80211_sched_scan_request *req);
+int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
+                              struct ieee80211_vif *vif,
+                              struct cfg80211_sched_scan_request *req,
+                              struct ieee80211_scan_ies *ies);
 int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
 int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
                                    struct iwl_rx_cmd_buffer *rxb,
@@ -1206,11 +1212,9 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif);
 
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
+
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
-#else
-static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
-#endif
 
 #endif /* __IWL_MVM_H__ */
index 15aa298..bd52ecf 100644 (file)
@@ -336,6 +336,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(DTS_MEASUREMENT_NOTIFICATION),
        CMD(REPLY_THERMAL_MNG_BACKOFF),
        CMD(MAC_PM_POWER_TABLE),
+       CMD(LTR_CONFIG),
        CMD(BT_COEX_CI),
        CMD(BT_COEX_UPDATE_SW_BOOST),
        CMD(BT_COEX_UPDATE_CORUN_LUT),
@@ -402,6 +403,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        if (cfg->max_rx_agg_size)
                hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
 
+       if (cfg->max_tx_agg_size)
+               hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
+
        op_mode = hw->priv;
        op_mode->ops = &iwl_mvm_ops;
 
@@ -583,16 +587,18 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        ieee80211_unregister_hw(mvm->hw);
 
        kfree(mvm->scan_cmd);
-       if (mvm->fw_error_dump) {
-               vfree(mvm->fw_error_dump->op_mode_ptr);
-               vfree(mvm->fw_error_dump->trans_ptr);
-               kfree(mvm->fw_error_dump);
-       }
        kfree(mvm->mcast_filter_cmd);
        mvm->mcast_filter_cmd = NULL;
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
        kfree(mvm->d3_resume_sram);
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
 #endif
 
        iwl_trans_op_mode_leave(mvm->trans);
index 18a5399..ce88484 100644 (file)
@@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
 static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
                                const char *prefix)
 {
-       IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
+       IWL_DEBUG_RATE(mvm,
+                      "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n",
                       prefix, rs_pretty_lq_type(rate->type),
                       rate->index, rs_pretty_ant(rate->ant),
-                      rate->bw, rate->sgi, rate->ldpc);
+                      rate->bw, rate->sgi, rate->ldpc, rate->stbc);
 }
 
 static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
                IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
        }
 
+       if (is_siso(rate) && rate->stbc) {
+               /* To enable STBC we need to set both a flag and ANT_AB */
+               ucode_rate |= RATE_MCS_ANT_AB_MSK;
+               ucode_rate |= RATE_MCS_VHT_STBC_MSK;
+       }
+
        ucode_rate |= rate->bw;
        if (rate->sgi)
                ucode_rate |= RATE_MCS_SGI_MSK;
@@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
                rate->sgi = true;
        if (ucode_rate & RATE_MCS_LDPC_MSK)
                rate->ldpc = true;
+       if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
+               rate->stbc = true;
 
        rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
 
@@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
 
                if (nss == 1) {
                        rate->type = LQ_HT_SISO;
-                       WARN_ON_ONCE(num_of_ant != 1);
+                       WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
                } else if (nss == 2) {
                        rate->type = LQ_HT_MIMO2;
                        WARN_ON_ONCE(num_of_ant != 2);
@@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
 static inline bool rs_rate_match(struct rs_rate *a,
                                 struct rs_rate *b)
 {
-       return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi);
+       bool ant_match;
+
+       if (a->stbc)
+               ant_match = (b->ant == ANT_A || b->ant == ANT_B);
+       else
+               ant_match = (a->ant == b->ant);
+
+       return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi)
+               && ant_match;
 }
 
 static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
@@ -1225,7 +1242,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
 done:
        /* See if there's a better rate or modulation mode to try. */
-       if (sta && sta->supp_rates[info->band])
+       if (sta->supp_rates[info->band])
                rs_rate_scale_perform(mvm, sta, lq_sta, tid);
 }
 
@@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                else
                        rate->type = LQ_LEGACY_G;
 
+               rate->bw = RATE_MCS_CHAN_WIDTH_20;
+               rate->ldpc = false;
                rate_mask = lq_sta->active_legacy_rate;
        } else if (column->mode == RS_SISO) {
                rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
@@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                WARN_ON_ONCE("Bad column mode");
        }
 
-       rate->bw = rs_bw_from_sta_bw(sta);
-       rate->ldpc = lq_sta->ldpc;
+       if (column->mode != RS_LEGACY) {
+               rate->bw = rs_bw_from_sta_bw(sta);
+               rate->ldpc = lq_sta->ldpc;
+       }
+
        search_tbl->column = col_id;
        rs_set_expected_tpt_table(lq_sta, search_tbl);
 
@@ -1754,6 +1776,29 @@ out:
        return action;
 }
 
+static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+                         struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct ieee80211_vif *vif = mvmsta->vif;
+       bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
+                               !vif->bss_conf.ps);
+
+       /* Our chip supports Tx STBC and the peer is an HT/VHT STA which
+        * supports STBC of at least 1*SS
+        */
+       if (!lq_sta->stbc)
+               return false;
+
+       if (!mvm->ps_disabled && !sta_ps_disabled)
+               return false;
+
+       if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+               return false;
+
+       return true;
+}
+
 static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
                                int *weaker, int *stronger)
 {
@@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                if (mvm->cfg->ht_params->ldpc &&
                    (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
                        lq_sta->ldpc = true;
+
+               if (mvm->cfg->ht_params->stbc &&
+                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
+                       lq_sta->stbc = true;
        } else {
                rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
                lq_sta->is_vht = true;
@@ -2682,8 +2732,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                if (mvm->cfg->ht_params->ldpc &&
                    (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
                        lq_sta->ldpc = true;
+
+               if (mvm->cfg->ht_params->stbc &&
+                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
+                       lq_sta->stbc = true;
        }
 
+       if (IWL_MVM_RS_DISABLE_MIMO)
+               lq_sta->active_mimo2_rate = 0;
+
        lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
                                                    BITS_PER_LONG);
        lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
@@ -2692,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                                   BITS_PER_LONG);
 
        IWL_DEBUG_RATE(mvm,
-                      "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
+                      "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
                       lq_sta->active_legacy_rate,
                       lq_sta->active_siso_rate,
                       lq_sta->active_mimo2_rate,
-                      lq_sta->is_vht, lq_sta->ldpc);
+                      lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
        IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
                       lq_sta->max_legacy_rate_idx,
                       lq_sta->max_siso_rate_idx,
@@ -2820,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
  * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
  */
 static void rs_build_rates_table(struct iwl_mvm *mvm,
+                                struct ieee80211_sta *sta,
                                 struct iwl_lq_sta *lq_sta,
                                 const struct rs_rate *initial_rate)
 {
@@ -2832,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
        memcpy(&rate, initial_rate, sizeof(rate));
 
        valid_tx_ant = mvm->fw->valid_tx_ant;
+       rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
 
        if (is_siso(&rate)) {
                num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2903,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
        if (WARN_ON_ONCE(!sta || !initial_rate))
                return;
 
-       rs_build_rates_table(mvm, lq_sta, initial_rate);
+       rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
 
        if (num_of_ant(initial_rate->ant) == 1)
                lq_cmd->single_stream_ant_msk = initial_rate->ant;
index eb34c12..defd70a 100644 (file)
@@ -208,6 +208,7 @@ struct rs_rate {
        u32 bw;
        bool sgi;
        bool ldpc;
+       bool stbc;
 };
 
 
@@ -331,6 +332,7 @@ struct iwl_lq_sta {
        u64 last_tx;
        bool is_vht;
        bool ldpc;              /* LDPC Rx is supported by the STA */
+       bool stbc;              /* Tx STBC is supported by chip and Rx by STA */
        enum ieee80211_band band;
 
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
index cb85e63..5cd59a4 100644 (file)
@@ -270,7 +270,8 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        bool *global_bound = data;
 
-       if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
+           mvmvif->phy_ctxt->id < MAX_PHYS)
                *global_bound = true;
 }
 
@@ -459,7 +460,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
                                basic_ssid ? 1 : 0);
 
        cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
-                                          TX_CMD_FLG_BT_DIS);
+                                          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 =
@@ -671,6 +673,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
                mvm->scan_status = IWL_MVM_SCAN_NONE;
                ieee80211_scan_completed(mvm->hw,
                                         status == IWL_SCAN_OFFLOAD_ABORTED);
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        }
 
        mvm->last_ebs_successful = !ebs_status;
@@ -1006,6 +1009,31 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                                    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,
+                              struct ieee80211_scan_ies *ies)
+{
+       int ret;
+
+       if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
+               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 {
+               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);
+       }
+
+       return ret;
+}
+
 static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
 {
        int ret;
@@ -1080,8 +1108,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        /*
         * 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
-        * stopped from above.
+        * stopped from above. Since the rx handler won't do anything now,
+        * we have to release the scan reference here.
         */
+       if (mvm->scan_status == IWL_MVM_SCAN_OS)
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
index 1731c20..dd0dc5b 100644 (file)
@@ -609,7 +609,7 @@ int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        lockdep_assert_held(&mvm->mutex);
 
-       qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+       qmask = iwl_mvm_mac_get_queues_mask(vif);
 
        /*
         * The firmware defines the TFD queue mask to only be relevant
index b7f9e61..6dfad23 100644 (file)
@@ -305,8 +305,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
                te_data->running = false;
                te_data->vif = NULL;
                te_data->uid = 0;
+               te_data->id = TE_MAX;
        } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
-               set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
                set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
                te_data->running = true;
                ieee80211_ready_on_channel(mvm->hw); /* Start TE */
index acca44a..d4f2c29 100644 (file)
  *****************************************************************************/
 
 #include "mvm.h"
-#include "iwl-config.h"
-#include "iwl-io.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
 
 #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT        HZ
 
index 1cb793a..8d84873 100644 (file)
@@ -175,14 +175,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
 
        /*
         * for data packets, rate info comes from the table inside the fw. This
-        * table is controlled by LINK_QUALITY commands. Exclude ctrl port
-        * frames like EAPOLs which should be treated as mgmt frames. This
-        * avoids them being sent initially in high rates which increases the
-        * chances for completion of the 4-Way handshake.
+        * table is controlled by LINK_QUALITY commands
         */
 
-       if (ieee80211_is_data(fc) && sta &&
-           !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
+       if (ieee80211_is_data(fc) && sta) {
                tx_cmd->initial_rate_index = 0;
                tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
                return;
@@ -193,8 +189,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
 
        /* HT rate doesn't make sense for a non data frame */
        WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
-                 "Got an HT rate for a non data frame 0x%x\n",
-                 info->control.rates[0].flags);
+                 "Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n",
+                 info->control.rates[0].flags,
+                 info->control.rates[0].idx,
+                 le16_to_cpu(fc));
 
        rate_idx = info->control.rates[0].idx;
        /* if the rate isn't a well known legacy rate, take the lowest one */
index 8021f6e..e56e77e 100644 (file)
@@ -734,3 +734,40 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm)
 
        return idle;
 }
+
+struct iwl_bss_iter_data {
+       struct ieee80211_vif *vif;
+       bool error;
+};
+
+static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_bss_iter_data *data = _data;
+
+       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+               return;
+
+       if (data->vif) {
+               data->error = true;
+               return;
+       }
+
+       data->vif = vif;
+}
+
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
+{
+       struct iwl_bss_iter_data bss_iter_data = {};
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_bss_iface_iterator, &bss_iter_data);
+
+       if (bss_iter_data.error) {
+               IWL_ERR(mvm, "More than one managed interface active!\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       return bss_iter_data.vif;
+}
index 1393bac..40a2906 100644 (file)
@@ -133,7 +133,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
                break;
        }
 
-       if (!page)
+       if (WARN_ON_ONCE(!page))
                return;
 
        trans_pcie->fw_mon_page = page;
@@ -174,6 +174,7 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u16 lctl;
+       u16 cap;
 
        /*
         * HW bug W/A for instability in PCIe bus L0S->L1 transition.
@@ -184,16 +185,17 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
         *    power savings, even without L1.
         */
        pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
-       if (lctl & PCI_EXP_LNKCTL_ASPM_L1) {
-               /* L1-ASPM enabled; disable(!) L0S */
+       if (lctl & PCI_EXP_LNKCTL_ASPM_L1)
                iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");
-       } else {
-               /* L1-ASPM disabled; enable(!) L0S */
+       else
                iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_info(trans->dev, "L1 Disabled; Enabling L0S\n");
-       }
        trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S);
+
+       pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap);
+       trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN;
+       dev_info(trans->dev, "L1 %sabled - LTR %sabled\n",
+                (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis",
+                trans->ltr_enabled ? "En" : "Dis");
 }
 
 /*
@@ -428,7 +430,7 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
        ret = iwl_poll_bit(trans, CSR_RESET,
                           CSR_RESET_REG_FLAG_MASTER_DISABLED,
                           CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-       if (ret)
+       if (ret < 0)
                IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
 
        IWL_DEBUG_INFO(trans, "stop master\n");
@@ -544,7 +546,7 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
                msleep(25);
        }
 
-       IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter);
+       IWL_ERR(trans, "Couldn't prepare the card\n");
 
        return ret;
 }
@@ -744,15 +746,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        int ret = 0;
        int first_ucode_section;
 
-       IWL_DEBUG_FW(trans,
-                    "working with %s image\n",
-                    image->is_secure ? "Secured" : "Non Secured");
        IWL_DEBUG_FW(trans,
                     "working with %s CPU\n",
                     image->is_dual_cpus ? "Dual" : "Single");
 
        /* configure the ucode to be ready to get the secured image */
-       if (image->is_secure) {
+       if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
                /* set secure boot inspector addresses */
                iwl_write_prph(trans,
                               LMPM_SECURE_INSPECTOR_CODE_ADDR,
@@ -788,7 +787,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                               LMPM_SECURE_CPU2_HDR_MEM_SPACE);
 
                /* load to FW the binary sections of CPU2 */
-               if (image->is_secure)
+               if (iwl_has_secure_boot(trans->hw_rev,
+                                       trans->cfg->device_family))
                        ret = iwl_pcie_load_cpu_secured_sections(
                                                        trans, image, 2,
                                                        &first_ucode_section);
@@ -819,7 +819,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        else
                iwl_write32(trans, CSR_RESET, 0);
 
-       if (image->is_secure) {
+       if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
                /* wait for image verification to complete  */
                ret = iwl_poll_prph_bit(trans,
                                        LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
@@ -1021,14 +1021,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return 0;
        }
 
-       iwl_pcie_set_pwr(trans, false);
-
-       val = iwl_read32(trans, CSR_RESET);
-       if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
-               *status = IWL_D3_STATUS_RESET;
-               return 0;
-       }
-
        /*
         * Also enables interrupts - none will happen as the device doesn't
         * know we're waking it up, only when the opmode actually tells it
@@ -1043,11 +1035,13 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                           CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                           CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                           25000);
-       if (ret) {
+       if (ret < 0) {
                IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
                return ret;
        }
 
+       iwl_pcie_set_pwr(trans, false);
+
        iwl_trans_pcie_tx_reset(trans);
 
        ret = iwl_pcie_rx_init(trans);
@@ -1056,7 +1050,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return ret;
        }
 
-       *status = IWL_D3_STATUS_ALIVE;
+       val = iwl_read32(trans, CSR_RESET);
+       if (val & CSR_RESET_REG_FLAG_NEVO_RESET)
+               *status = IWL_D3_STATUS_RESET;
+       else
+               *status = IWL_D3_STATUS_ALIVE;
+
        return 0;
 }
 
@@ -1765,6 +1764,13 @@ err:
        IWL_ERR(trans, "failed to create the trans debugfs entry\n");
        return -ENOMEM;
 }
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                        struct dentry *dir)
+{
+       return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
 {
@@ -2043,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
 
        return dump_data;
 }
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                        struct dentry *dir)
-{
-       return 0;
-}
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
@@ -2086,9 +2085,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .release_nic_access = iwl_trans_pcie_release_nic_access,
        .set_bits_mask = iwl_trans_pcie_set_bits_mask,
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        .dump_data = iwl_trans_pcie_dump_data,
-#endif
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,