Merge tag 'iwlwifi-next-for-kalle-2015-05-03' of https://git.kernel.org/pub/scm/linux...
authorKalle Valo <kvalo@codeaurora.org>
Sat, 9 May 2015 13:21:49 +0000 (16:21 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Sat, 9 May 2015 13:21:49 +0000 (16:21 +0300)
* major rework of the scan code (Luca)
* some work on the thermal code (Chaya Rachel)
* some work on the firwmare debugging infrastructure

20 files changed:
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.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/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index ab019b4..99f9760 100644 (file)
@@ -21,6 +21,7 @@ config IWLWIFI
                Intel 7260 Wi-Fi Adapter
                Intel 3160 Wi-Fi Adapter
                Intel 7265 Wi-Fi Adapter
+               Intel 8260 Wi-Fi Adapter
 
 
          This driver uses the kernel's mac80211 subsystem.
@@ -53,16 +54,17 @@ config IWLDVM
        tristate "Intel Wireless WiFi DVM Firmware support"
        default IWLWIFI
        help
-         This is the driver that supports the DVM firmware which is
-         used by most existing devices (with the exception of 7260
-         and 3160).
+         This is the driver that supports the DVM firmware. The list
+         of the devices that use this firmware is available here:
+         https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
 
 config IWLMVM
        tristate "Intel Wireless WiFi MVM Firmware support"
        select WANT_DEV_COREDUMP
        help
-         This is the driver that supports the MVM firmware which is
-         currently only available for 7260 and 3160 devices.
+         This is the driver that supports the MVM firmware. The list
+         of the devices that use this firmware is available here:
+         https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
 
 # don't call it _MODULE -- will confuse Kconfig/fixdep/...
 config IWLWIFI_OPMODE_MODULAR
index 36e786f..69b2c0b 100644 (file)
@@ -128,6 +128,28 @@ static const struct iwl_base_params iwl7000_base_params = {
        .apmg_wake_up_wa = true,
 };
 
+static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
+       .ct_kill_entry = 118,
+       .ct_kill_exit = 96,
+       .ct_kill_duration = 5,
+       .dynamic_smps_entry = 114,
+       .dynamic_smps_exit = 110,
+       .tx_protection_entry = 114,
+       .tx_protection_exit = 108,
+       .tx_backoff = {
+               {.temperature = 112, .backoff = 300},
+               {.temperature = 113, .backoff = 800},
+               {.temperature = 114, .backoff = 1500},
+               {.temperature = 115, .backoff = 3000},
+               {.temperature = 116, .backoff = 5000},
+               {.temperature = 117, .backoff = 10000},
+       },
+       .support_ct_kill = true,
+       .support_dynamic_smps = true,
+       .support_tx_protection = true,
+       .support_tx_backoff = true,
+};
+
 static const struct iwl_ht_params iwl7000_ht_params = {
        .stbc = true,
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
@@ -170,6 +192,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
        .host_interrupt_operation_mode = true,
        .lp_xtal_workaround = true,
        .dccm_len = IWL7260_DCCM_LEN,
+       .thermal_params = &iwl7000_high_temp_tt_params,
 };
 
 const struct iwl_cfg iwl7260_2n_cfg = {
index 3f33f75..225b6d6 100644 (file)
@@ -194,6 +194,49 @@ struct iwl_ht_params {
        u8 ht40_bands;
 };
 
+/*
+ * Tx-backoff threshold
+ * @temperature: The threshold in Celsius
+ * @backoff: The tx-backoff in uSec
+ */
+struct iwl_tt_tx_backoff {
+       s32 temperature;
+       u32 backoff;
+};
+
+#define TT_TX_BACKOFF_SIZE 6
+
+/**
+ * struct iwl_tt_params - thermal throttling parameters
+ * @ct_kill_entry: CT Kill entry threshold
+ * @ct_kill_exit: CT Kill exit threshold
+ * @ct_kill_duration: The time  intervals (in uSec) in which the driver needs
+ *     to checks whether to exit CT Kill.
+ * @dynamic_smps_entry: Dynamic SMPS entry threshold
+ * @dynamic_smps_exit: Dynamic SMPS exit threshold
+ * @tx_protection_entry: TX protection entry threshold
+ * @tx_protection_exit: TX protection exit threshold
+ * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
+ * @support_ct_kill: Support CT Kill?
+ * @support_dynamic_smps: Support dynamic SMPS?
+ * @support_tx_protection: Support tx protection?
+ * @support_tx_backoff: Support tx-backoff?
+ */
+struct iwl_tt_params {
+       s32 ct_kill_entry;
+       s32 ct_kill_exit;
+       u32 ct_kill_duration;
+       s32 dynamic_smps_entry;
+       s32 dynamic_smps_exit;
+       s32 tx_protection_entry;
+       s32 tx_protection_exit;
+       struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
+       bool support_ct_kill;
+       bool support_dynamic_smps;
+       bool support_tx_protection;
+       bool support_tx_backoff;
+};
+
 /*
  * information on how to parse the EEPROM
  */
@@ -316,6 +359,7 @@ struct iwl_cfg {
        const u32 dccm2_len;
        const u32 smem_offset;
        const u32 smem_len;
+       const struct iwl_tt_params *thermal_params;
 };
 
 /*
index bfdf3fa..c7cfc38 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag {
  *     longer than the passive one, which is essential for fragmented scan.
  * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
  * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
+ * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power.
  * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
  *     regardless of the band or the number of the probes. FW will calculate
  *     the actual dwell time.
@@ -260,6 +261,7 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_FRAGMENTED_SCAN       = BIT(8),
        IWL_UCODE_TLV_API_WIFI_MCC_UPDATE       = BIT(9),
        IWL_UCODE_TLV_API_HDC_PHASE_0           = BIT(10),
+       IWL_UCODE_TLV_API_TX_POWER_DEV          = BIT(11),
        IWL_UCODE_TLV_API_BASIC_DWELL           = BIT(13),
        IWL_UCODE_TLV_API_SCD_CFG               = BIT(15),
        IWL_UCODE_TLV_API_SINGLE_SCAN_EBS       = BIT(16),
@@ -434,6 +436,7 @@ enum iwl_fw_dbg_monitor_mode {
  *
  * @version: version of the TLV - currently 0
  * @monitor_mode: %enum iwl_fw_dbg_monitor_mode
+ * @size_power: buffer size will be 2^(size_power + 11)
  * @base_reg: addr of the base addr register (PRPH)
  * @end_reg:  addr of the end addr register (PRPH)
  * @write_ptr_reg: the addr of the reg of the write pointer
@@ -447,7 +450,8 @@ enum iwl_fw_dbg_monitor_mode {
 struct iwl_fw_dbg_dest_tlv {
        u8 version;
        u8 monitor_mode;
-       u8 reserved[2];
+       u8 size_power;
+       u8 reserved;
        __le32 base_reg;
        __le32 end_reg;
        __le32 write_ptr_reg;
index 88a57e6..5af1c77 100644 (file)
@@ -348,6 +348,9 @@ enum secure_load_status_reg {
 #define MON_BUFF_WRPTR                 (0xa03c44)
 #define MON_BUFF_CYCLE_CNT             (0xa03c48)
 
+#define MON_DMARB_RD_CTL_ADDR          (0xa03c60)
+#define MON_DMARB_RD_DATA_ADDR         (0xa03c5c)
+
 #define DBGC_IN_SAMPLE                 (0xa03c00)
 
 /* enable the ID buf for read */
index 6dfed12..56254a8 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg {
  *
  * All the handlers MUST be implemented
  *
- * @start_hw: starts the HW- from that point on, the HW can send interrupts
- *     May sleep
+ * @start_hw: starts the HW. If low_power is true, the NIC needs to be taken
+ *     out of a low power state. From that point on, the HW can send
+ *     interrupts. May sleep.
  * @op_mode_leave: Turn off the HW RF kill indication if on
  *     May sleep
  * @start_fw: allocates and inits all the resources for the transport
@@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg {
  *     the SCD base address in SRAM, then provide it here, or 0 otherwise.
  *     May sleep
  * @stop_device: stops the whole device (embedded CPU put to reset) and stops
- *     the HW. From that point on, the HW will be in low power but will still
- *     issue interrupt if the HW RF kill is triggered. This callback must do
- *     the right thing and not crash even if start_hw() was called but not
- *     start_fw(). May sleep
+ *     the HW. If low_power is true, the NIC will be put in low power state.
+ *     From that point on, the HW will be stopped but will still issue an
+ *     interrupt if the HW RF kill switch is triggered.
+ *     This callback must do the right thing and not crash even if %start_hw()
+ *     was called but not &start_fw(). May sleep.
  * @d3_suspend: put the device into the correct mode for WoWLAN during
  *     suspend. This is optional, if not implemented WoWLAN will not be
  *     supported. This callback may sleep.
@@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg {
  */
 struct iwl_trans_ops {
 
-       int (*start_hw)(struct iwl_trans *iwl_trans);
+       int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power);
        void (*op_mode_leave)(struct iwl_trans *iwl_trans);
        int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
                        bool run_in_rfkill);
        int (*update_sf)(struct iwl_trans *trans,
                         struct iwl_sf_region *st_fwrd_space);
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
-       void (*stop_device)(struct iwl_trans *trans);
+       void (*stop_device)(struct iwl_trans *trans, bool low_power);
 
        void (*d3_suspend)(struct iwl_trans *trans, bool test);
        int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
@@ -652,11 +654,16 @@ static inline void iwl_trans_configure(struct iwl_trans *trans,
        trans->ops->configure(trans, trans_cfg);
 }
 
-static inline int iwl_trans_start_hw(struct iwl_trans *trans)
+static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power)
 {
        might_sleep();
 
-       return trans->ops->start_hw(trans);
+       return trans->ops->start_hw(trans, low_power);
+}
+
+static inline int iwl_trans_start_hw(struct iwl_trans *trans)
+{
+       return trans->ops->start_hw(trans, true);
 }
 
 static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
@@ -703,15 +710,21 @@ static inline int iwl_trans_update_sf(struct iwl_trans *trans,
        return 0;
 }
 
-static inline void iwl_trans_stop_device(struct iwl_trans *trans)
+static inline void _iwl_trans_stop_device(struct iwl_trans *trans,
+                                         bool low_power)
 {
        might_sleep();
 
-       trans->ops->stop_device(trans);
+       trans->ops->stop_device(trans, low_power);
 
        trans->state = IWL_TRANS_NO_FW;
 }
 
+static inline void iwl_trans_stop_device(struct iwl_trans *trans)
+{
+       _iwl_trans_stop_device(trans, true);
+}
+
 static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
 {
        might_sleep();
index a6c48c7..36bf6a8 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -981,7 +981,8 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
        if (ret)
                return ret;
 
-       ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies);
+       ret = iwl_mvm_sched_scan_start(mvm, vif, nd_config, &mvm->nd_ies,
+                                      IWL_MVM_SCAN_NETDETECT);
        if (ret)
                return ret;
 
@@ -1726,7 +1727,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
        results->matched_profiles = le32_to_cpu(query->matched_profiles);
        memcpy(results->matches, query->matches, sizeof(results->matches));
 
-#ifdef CPTCFG_IWLWIFI_DEBUGFS
+#ifdef CONFIG_IWLWIFI_DEBUGFS
        mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done);
 #endif
 
index 4fc0938..b1baa33 100644 (file)
@@ -297,6 +297,40 @@ struct iwl_uapsd_misbehaving_ap_notif {
        u8 reserved[3];
 } __packed;
 
+/**
+ * struct iwl_reduce_tx_power_cmd - TX power reduction command
+ * REDUCE_TX_POWER_CMD = 0x9f
+ * @flags: (reserved for future implementation)
+ * @mac_context_id: id of the mac ctx for which we are reducing TX power.
+ * @pwr_restriction: TX power restriction in dBms.
+ */
+struct iwl_reduce_tx_power_cmd {
+       u8 flags;
+       u8 mac_context_id;
+       __le16 pwr_restriction;
+} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */
+
+/**
+ * struct iwl_dev_tx_power_cmd - TX power reduction command
+ * REDUCE_TX_POWER_CMD = 0x9f
+ * @set_mode: 0 - MAC tx power, 1 - device tx power
+ * @mac_context_id: id of the mac ctx for which we are reducing TX power.
+ * @pwr_restriction: TX power restriction in 1/8 dBms.
+ * @dev_24: device TX power restriction in 1/8 dBms
+ * @dev_52_low: device TX power restriction upper band - low
+ * @dev_52_high: device TX power restriction upper band - high
+ */
+struct iwl_dev_tx_power_cmd {
+       __le32 set_mode;
+       __le32 mac_context_id;
+       __le16 pwr_restriction;
+       __le16 dev_24;
+       __le16 dev_52_low;
+       __le16 dev_52_high;
+} __packed; /* TX_REDUCED_POWER_API_S_VER_2 */
+
+#define IWL_DEV_MAX_TX_POWER 0x7FFF
+
 /**
  * struct iwl_beacon_filter_cmd
  * REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
index 4f81dcf..be1a0a1 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -122,46 +122,6 @@ enum iwl_scan_complete_status {
        SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C,
 };
 
-/**
- * struct iwl_scan_results_notif - scan results for one channel
- * ( SCAN_RESULTS_NOTIFICATION = 0x83 )
- * @channel: which channel the results are from
- * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
- * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request
- * @num_probe_not_sent: # of request that weren't sent due to not enough time
- * @duration: duration spent in channel, in usecs
- * @statistics: statistics gathered for this channel
- */
-struct iwl_scan_results_notif {
-       u8 channel;
-       u8 band;
-       u8 probe_status;
-       u8 num_probe_not_sent;
-       __le32 duration;
-       __le32 statistics[SCAN_RESULTS_STATISTICS];
-} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */
-
-/**
- * struct iwl_scan_complete_notif - notifies end of scanning (all channels)
- * ( SCAN_COMPLETE_NOTIFICATION = 0x84 )
- * @scanned_channels: number of channels scanned (and number of valid results)
- * @status: one of SCAN_COMP_STATUS_*
- * @bt_status: BT on/off status
- * @last_channel: last channel that was scanned
- * @tsf_low: TSF timer (lower half) in usecs
- * @tsf_high: TSF timer (higher half) in usecs
- * @results: array of scan results, only "scanned_channels" of them are valid
- */
-struct iwl_scan_complete_notif {
-       u8 scanned_channels;
-       u8 status;
-       u8 bt_status;
-       u8 last_channel;
-       __le32 tsf_low;
-       __le32 tsf_high;
-       struct iwl_scan_results_notif results[];
-} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */
-
 /* scan offload */
 #define IWL_SCAN_MAX_BLACKLIST_LEN     64
 #define IWL_SCAN_SHORT_BLACKLIST_LEN   16
@@ -314,50 +274,18 @@ struct iwl_scan_offload_profile_cfg {
 } __packed;
 
 /**
- * iwl_scan_offload_schedule - schedule of scan offload
+ * iwl_scan_schedule_lmac - schedule of scan offload
  * @delay:             delay between iterations, in seconds.
  * @iterations:                num of scan iterations
  * @full_scan_mul:     number of partial scans before each full scan
  */
-struct iwl_scan_offload_schedule {
+struct iwl_scan_schedule_lmac {
        __le16 delay;
        u8 iterations;
        u8 full_scan_mul;
-} __packed;
-
-/*
- * iwl_scan_offload_flags
- *
- * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
- * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE: EBS duration is 100mSec - typical
- *     beacon period. Finding channel activity in this mode is not guaranteed.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE: EBS duration is 200mSec.
- *     Assuming beacon period is 100ms finding channel activity is guaranteed.
- */
-enum iwl_scan_offload_flags {
-       IWL_SCAN_OFFLOAD_FLAG_PASS_ALL          = BIT(0),
-       IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL    = BIT(2),
-       IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE    = BIT(5),
-       IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE = BIT(6),
-};
+} __packed; /* SCAN_SCHEDULE_API_S */
 
-/**
- * iwl_scan_offload_req - scan offload request command
- * @flags:             bitmap - enum iwl_scan_offload_flags.
- * @watchdog:          maximum scan duration in TU.
- * @delay:             delay in seconds before first iteration.
- * @schedule_line:     scan offload schedule, for fast and regular scan.
- */
-struct iwl_scan_offload_req {
-       __le16 flags;
-       __le16 watchdog;
-       __le16 delay;
-       __le16 reserved;
-       struct iwl_scan_offload_schedule schedule_line[2];
-} __packed;
-
-enum iwl_scan_offload_compleate_status {
+enum iwl_scan_offload_complete_status {
        IWL_SCAN_OFFLOAD_COMPLETED      = 1,
        IWL_SCAN_OFFLOAD_ABORTED        = 2,
 };
@@ -504,7 +432,7 @@ enum iwl_scan_priority {
 };
 
 /**
- * iwl_scan_req_unified_lmac - SCAN_REQUEST_CMD_API_S_VER_1
+ * iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
  * @reserved1: for alignment and future use
  * @channel_num: num of channels to scan
  * @active-dwell: dwell time for active channels
@@ -527,7 +455,7 @@ enum iwl_scan_priority {
  * @channel_opt: channel optimization options, for full and partial scan
  * @data: channel configuration and probe request packet.
  */
-struct iwl_scan_req_unified_lmac {
+struct iwl_scan_req_lmac {
        /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */
        __le32 reserved1;
        u8 n_channels;
@@ -548,13 +476,13 @@ struct iwl_scan_req_unified_lmac {
        /* SCAN_REQ_PERIODIC_PARAMS_API_S */
        __le32 iter_num;
        __le32 delay;
-       struct iwl_scan_offload_schedule schedule[2];
+       struct iwl_scan_schedule_lmac schedule[2];
        struct iwl_scan_channel_opt channel_opt[2];
        u8 data[];
 } __packed;
 
 /**
- * struct iwl_lmac_scan_results_notif - scan results for one channel -
+ * struct iwl_scan_results_notif - scan results for one channel -
  *     SCAN_RESULT_NTF_API_S_VER_3
  * @channel: which channel the results are from
  * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
@@ -562,7 +490,7 @@ struct iwl_scan_req_unified_lmac {
  * @num_probe_not_sent: # of request that weren't sent due to not enough time
  * @duration: duration spent in channel, in usecs
  */
-struct iwl_lmac_scan_results_notif {
+struct iwl_scan_results_notif {
        u8 channel;
        u8 band;
        u8 probe_status;
@@ -622,7 +550,11 @@ struct iwl_mvm_umac_cmd_hdr {
        u8 ver;
 } __packed;
 
-#define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8
+/* The maximum of either of these cannot exceed 8, because we use an
+ * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h).
+ */
+#define IWL_MVM_MAX_UMAC_SCANS 8
+#define IWL_MVM_MAX_LMAC_SCANS 1
 
 enum scan_config_flags {
        SCAN_CONFIG_FLAG_ACTIVATE                       = BIT(0),
index aab68cb..56db2ba 100644 (file)
@@ -147,13 +147,6 @@ enum {
 
        LQ_CMD = 0x4e,
 
-       /* Calibration */
-       TEMPERATURE_NOTIFICATION = 0x62,
-       CALIBRATION_CFG_CMD = 0x65,
-       CALIBRATION_RES_NOTIFICATION = 0x66,
-       CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
-       RADIO_VERSION_NOTIFICATION = 0x68,
-
        /* Scan offload */
        SCAN_OFFLOAD_REQUEST_CMD = 0x51,
        SCAN_OFFLOAD_ABORT_CMD = 0x52,
@@ -281,19 +274,6 @@ struct iwl_tx_ant_cfg_cmd {
        __le32 valid;
 } __packed;
 
-/**
- * struct iwl_reduce_tx_power_cmd - TX power reduction command
- * REDUCE_TX_POWER_CMD = 0x9f
- * @flags: (reserved for future implementation)
- * @mac_context_id: id of the mac ctx for which we are reducing TX power.
- * @pwr_restriction: TX power restriction in dBms.
- */
-struct iwl_reduce_tx_power_cmd {
-       u8 flags;
-       u8 mac_context_id;
-       __le16 pwr_restriction;
-} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */
-
 /*
  * Calibration control struct.
  * Sent as part of the phy configuration command.
index bc5eac4..0601445 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -322,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating))
+       if (WARN_ON_ONCE(mvm->calibrating))
                return 0;
 
        iwl_init_notification_wait(&mvm->notif_wait,
@@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
         */
        ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
                        MVM_UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               mvm->init_ucode_complete = true;
 
        if (ret && iwl_mvm_is_radio_killed(mvm)) {
                IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n");
@@ -494,15 +492,6 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
 
        mvm->fw_dump_desc = desc;
 
-       /* stop recording */
-       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
-               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
-       } else {
-               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
-               /* wait before we collect the data till the DBGC stop */
-               udelay(100);
-       }
-
        queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay);
 
        return 0;
@@ -658,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
         * module loading, load init ucode now
         * (for example, if we were in RFKILL)
         */
-       if (!mvm->init_ucode_complete) {
-               ret = iwl_run_init_mvm_ucode(mvm, false);
-               if (ret && !iwlmvm_mod_params.init_dbg) {
-                       IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
-                       /* this can't happen */
-                       if (WARN_ON(ret > 0))
-                               ret = -ERFKILL;
-                       goto error;
-               }
-               if (!iwlmvm_mod_params.init_dbg) {
-                       /*
-                        * should stop and start HW since that INIT
-                        * image just loaded
-                        */
-                       iwl_trans_stop_device(mvm->trans);
-                       ret = iwl_trans_start_hw(mvm->trans);
-                       if (ret)
-                               return ret;
-               }
+       ret = iwl_run_init_mvm_ucode(mvm, false);
+       if (ret && !iwlmvm_mod_params.init_dbg) {
+               IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
+               /* this can't happen */
+               if (WARN_ON(ret > 0))
+                       ret = -ERFKILL;
+               goto error;
+       }
+       if (!iwlmvm_mod_params.init_dbg) {
+               /*
+                * Stop and start the transport without entering low power
+                * mode. This will save the state of other components on the
+                * device that are triggered by the INIT firwmare (MFUART).
+                */
+               _iwl_trans_stop_device(mvm->trans, false);
+               _iwl_trans_start_hw(mvm->trans, false);
+               if (ret)
+                       return ret;
        }
 
        if (iwlmvm_mod_params.init_dbg)
@@ -844,21 +832,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
        return 0;
 }
 
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                        struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_radio_version_notif *radio_version = (void *)pkt->data;
-
-       /* TODO: what to do with that? */
-       IWL_DEBUG_INFO(mvm,
-                      "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n",
-                      le32_to_cpu(radio_version->radio_flavor),
-                      le32_to_cpu(radio_version->radio_step),
-                      le32_to_cpu(radio_version->radio_dash));
-       return 0;
-}
-
 int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
                            struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd)
index 8455517..b56a445 100644 (file)
@@ -80,7 +80,6 @@
 #include "sta.h"
 #include "time-event.h"
 #include "iwl-eeprom-parse.h"
-#include "fw-api-scan.h"
 #include "iwl-phy-db.h"
 #include "testmode.h"
 #include "iwl-fw-error-dump.h"
@@ -506,10 +505,18 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 
        iwl_mvm_reset_phy_ctxts(mvm);
 
-       hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm, false);
+       hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
 
+       BUILD_BUG_ON(IWL_MVM_MAX_UMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK) ||
+                    IWL_MVM_MAX_LMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK));
+
+       if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
+               mvm->max_scans = IWL_MVM_MAX_UMAC_SCANS;
+       else
+               mvm->max_scans = IWL_MVM_MAX_LMAC_SCANS;
+
        if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
                hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
                        &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
@@ -532,14 +539,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        else
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
-       if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) {
-               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-               hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
-               hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
-               /* we create the 802.11 header and zero length SSID IE. */
-               hw->wiphy->max_sched_scan_ie_len =
-                       SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
-       }
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+       hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
+       hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
+       /* we create the 802.11 header and zero length SSID IE. */
+       hw->wiphy->max_sched_scan_ie_len =
+               SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
 
        hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
                               NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -1227,22 +1232,23 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 
        iwl_trans_stop_device(mvm->trans);
 
-       mvm->scan_status = IWL_MVM_SCAN_NONE;
+       mvm->scan_status = 0;
        mvm->ps_disabled = false;
        mvm->calibrating = false;
 
        /* just in case one was running */
        ieee80211_remain_on_channel_expired(mvm->hw);
 
-       ieee80211_iterate_active_interfaces_atomic(
-               mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
-               iwl_mvm_cleanup_iterator, mvm);
+       /*
+        * cleanup all interfaces, even inactive ones, as some might have
+        * gone down during the HW restart
+        */
+       ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);
 
        mvm->p2p_device_vif = NULL;
        mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
 
        iwl_mvm_reset_phy_ctxts(mvm);
-       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
        memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
        memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
        memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
@@ -1322,7 +1328,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
 
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        iwl_mvm_d0i3_enable_tx(mvm, NULL);
-       ret = iwl_mvm_update_quotas(mvm, false, NULL);
+       ret = iwl_mvm_update_quotas(mvm, true, NULL);
        if (ret)
                IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
                        ret);
@@ -1426,7 +1432,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
        if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
                int i;
 
-               for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
+               for (i = 0; i < mvm->max_scans; i++) {
                        if (WARN_ONCE(mvm->scan_uid[i],
                                      "UMAC scan UID %d was not cleaned\n",
                                      mvm->scan_uid[i]))
@@ -1471,8 +1477,8 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
        return NULL;
 }
 
-static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                               s8 tx_power)
+static int iwl_mvm_set_tx_power_old(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif, s8 tx_power)
 {
        /* FW is in charge of regulatory enforcement */
        struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
@@ -1485,6 +1491,26 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                    &reduce_txpwr_cmd);
 }
 
+static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                               s16 tx_power)
+{
+       struct iwl_dev_tx_power_cmd cmd = {
+               .set_mode = 0,
+               .mac_context_id =
+                       cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
+               .pwr_restriction = cpu_to_le16(8 * tx_power),
+       };
+
+       if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV))
+               return iwl_mvm_set_tx_power_old(mvm, vif, tx_power);
+
+       if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
+               cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
+
+       return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0,
+                                   sizeof(cmd), &cmd);
+}
+
 static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
@@ -2353,89 +2379,21 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
        iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
 }
 
-static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
-                                         enum iwl_scan_status scan_type)
-{
-       int ret;
-       bool wait_for_handlers = false;
-
-       mutex_lock(&mvm->mutex);
-
-       if (mvm->scan_status != scan_type) {
-               ret = 0;
-               /* make sure there are no pending notifications */
-               wait_for_handlers = true;
-               goto out;
-       }
-
-       switch (scan_type) {
-       case IWL_MVM_SCAN_SCHED:
-               ret = iwl_mvm_scan_offload_stop(mvm, true);
-               break;
-       case IWL_MVM_SCAN_OS:
-               ret = iwl_mvm_cancel_scan(mvm);
-               break;
-       case IWL_MVM_SCAN_NONE:
-       default:
-               WARN_ON_ONCE(1);
-               ret = -EINVAL;
-               break;
-       }
-       if (ret)
-               goto out;
-
-       wait_for_handlers = true;
-out:
-       mutex_unlock(&mvm->mutex);
-
-       /* make sure we consume the completion notification */
-       if (wait_for_handlers)
-               iwl_mvm_wait_for_async_handlers(mvm);
-
-       return ret;
-}
 static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               struct ieee80211_scan_request *hw_req)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct cfg80211_scan_request *req = &hw_req->req;
        int ret;
 
-       if (req->n_channels == 0 ||
-           req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
+       if (hw_req->req.n_channels == 0 ||
+           hw_req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
                return -EINVAL;
 
-       if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
-               ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
-               if (ret)
-                       return ret;
-       }
-
        mutex_lock(&mvm->mutex);
-
-       if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
-               IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
-
-       if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
-               ret = iwl_mvm_scan_umac(mvm, vif, hw_req);
-       else
-               ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
-
-       if (ret)
-               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-out:
+       ret = iwl_mvm_reg_scan_start(mvm, vif, &hw_req->req, &hw_req->ies);
        mutex_unlock(&mvm->mutex);
+
        return ret;
 }
 
@@ -2456,7 +2414,7 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
        /* FIXME: for now, we ignore this race for UMAC scans, since
         * they don't set the scan_status.
         */
-       if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
+       if ((mvm->scan_status & IWL_MVM_SCAN_REGULAR) ||
            (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
                iwl_mvm_cancel_scan(mvm);
 
@@ -2774,35 +2732,17 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
                                        struct ieee80211_scan_ies *ies)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       int ret;
 
-       if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
-               ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
-               if (ret)
-                       return ret;
-       }
+       int ret;
 
        mutex_lock(&mvm->mutex);
 
-       if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
-               IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
-               ret = -EBUSY;
-               goto out;
-       }
-
        if (!vif->bss_conf.idle) {
                ret = -EBUSY;
                goto out;
        }
 
-       if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
-       if (ret)
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
+       ret = iwl_mvm_sched_scan_start(mvm, vif, req, ies, IWL_MVM_SCAN_SCHED);
 
 out:
        mutex_unlock(&mvm->mutex);
@@ -2828,7 +2768,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
        /* FIXME: for now, we ignore this race for UMAC scans, since
         * they don't set the scan_status.
         */
-       if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
+       if (!(mvm->scan_status & IWL_MVM_SCAN_SCHED) &&
            !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
                mutex_unlock(&mvm->mutex);
                return 0;
@@ -2902,8 +2842,21 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                        break;
                }
 
+               /* During FW restart, in order to restore the state as it was,
+                * don't try to reprogram keys we previously failed for.
+                */
+               if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+                   key->hw_key_idx == STA_KEY_IDX_INVALID) {
+                       IWL_DEBUG_MAC80211(mvm,
+                                          "skip invalid idx key programming during restart\n");
+                       ret = 0;
+                       break;
+               }
+
                IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
-               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
+               ret = iwl_mvm_set_sta_key(mvm, vif, sta, key,
+                                         test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+                                                  &mvm->status));
                if (ret) {
                        IWL_WARN(mvm, "set key failed\n");
                        /*
@@ -2981,7 +2934,7 @@ static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
        return true;
 }
 
-#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
+#define AUX_ROC_MAX_DELAY_ON_CHANNEL 200
 static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
                                    struct ieee80211_channel *channel,
                                    struct ieee80211_vif *vif,
index d5522a1..6d33234 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,6 +76,7 @@
 #include "iwl-notif-wait.h"
 #include "iwl-eeprom-parse.h"
 #include "iwl-fw-file.h"
+#include "iwl-config.h"
 #include "sta.h"
 #include "fw-api.h"
 #include "constants.h"
@@ -446,9 +447,23 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
 extern const u8 tid_to_mac80211_ac[];
 
 enum iwl_scan_status {
-       IWL_MVM_SCAN_NONE,
-       IWL_MVM_SCAN_OS,
-       IWL_MVM_SCAN_SCHED,
+       IWL_MVM_SCAN_REGULAR            = BIT(0),
+       IWL_MVM_SCAN_SCHED              = BIT(1),
+       IWL_MVM_SCAN_NETDETECT          = BIT(2),
+
+       IWL_MVM_SCAN_STOPPING_REGULAR   = BIT(8),
+       IWL_MVM_SCAN_STOPPING_SCHED     = BIT(9),
+       IWL_MVM_SCAN_STOPPING_NETDETECT = BIT(10),
+
+       IWL_MVM_SCAN_REGULAR_MASK       = IWL_MVM_SCAN_REGULAR |
+                                         IWL_MVM_SCAN_STOPPING_REGULAR,
+       IWL_MVM_SCAN_SCHED_MASK         = IWL_MVM_SCAN_SCHED |
+                                         IWL_MVM_SCAN_STOPPING_SCHED,
+       IWL_MVM_SCAN_NETDETECT_MASK     = IWL_MVM_SCAN_NETDETECT |
+                                         IWL_MVM_SCAN_STOPPING_NETDETECT,
+
+       IWL_MVM_SCAN_STOPPING_MASK      = 0xff00,
+       IWL_MVM_SCAN_MASK               = 0x00ff,
 };
 
 /**
@@ -463,49 +478,6 @@ struct iwl_nvm_section {
        const u8 *data;
 };
 
-/*
- * Tx-backoff threshold
- * @temperature: The threshold in Celsius
- * @backoff: The tx-backoff in uSec
- */
-struct iwl_tt_tx_backoff {
-       s32 temperature;
-       u32 backoff;
-};
-
-#define TT_TX_BACKOFF_SIZE 6
-
-/**
- * struct iwl_tt_params - thermal throttling parameters
- * @ct_kill_entry: CT Kill entry threshold
- * @ct_kill_exit: CT Kill exit threshold
- * @ct_kill_duration: The time  intervals (in uSec) in which the driver needs
- *     to checks whether to exit CT Kill.
- * @dynamic_smps_entry: Dynamic SMPS entry threshold
- * @dynamic_smps_exit: Dynamic SMPS exit threshold
- * @tx_protection_entry: TX protection entry threshold
- * @tx_protection_exit: TX protection exit threshold
- * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
- * @support_ct_kill: Support CT Kill?
- * @support_dynamic_smps: Support dynamic SMPS?
- * @support_tx_protection: Support tx protection?
- * @support_tx_backoff: Support tx-backoff?
- */
-struct iwl_tt_params {
-       s32 ct_kill_entry;
-       s32 ct_kill_exit;
-       u32 ct_kill_duration;
-       s32 dynamic_smps_entry;
-       s32 dynamic_smps_exit;
-       s32 tx_protection_entry;
-       s32 tx_protection_exit;
-       struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
-       bool support_ct_kill;
-       bool support_dynamic_smps;
-       bool support_tx_protection;
-       bool support_tx_backoff;
-};
-
 /**
  * struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure
  * @ct_kill_exit: worker to exit thermal kill
@@ -520,7 +492,7 @@ struct iwl_mvm_tt_mgmt {
        bool dynamic_smps;
        u32 tx_backoff;
        u32 min_backoff;
-       const struct iwl_tt_params *params;
+       struct iwl_tt_params params;
        bool throttle;
 };
 
@@ -603,7 +575,6 @@ struct iwl_mvm {
 
        enum iwl_ucode_type cur_ucode;
        bool ucode_loaded;
-       bool init_ucode_complete;
        bool calibrating;
        u32 error_event_table;
        u32 log_event_table;
@@ -648,12 +619,15 @@ struct iwl_mvm {
        u32 rts_threshold;
 
        /* Scan status, cmd (pre-allocated) and auxiliary station */
-       enum iwl_scan_status scan_status;
+       unsigned int scan_status;
        void *scan_cmd;
        struct iwl_mcast_filter_cmd *mcast_filter_cmd;
 
+       /* max number of simultaneous scans the FW supports */
+       unsigned int max_scans;
+
        /* UMAC scan tracking */
-       u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS];
+       u32 scan_uid[IWL_MVM_MAX_UMAC_SCANS];
        u8 scan_seq_num, sched_scan_seq_num;
 
        /* rx chain antennas set through debugfs for the scan command */
@@ -1084,8 +1058,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                      struct iwl_device_cmd *cmd);
 int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                        struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                        struct iwl_device_cmd *cmd);
 int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
                                  struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd);
@@ -1094,8 +1066,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
                                struct iwl_rx_cmd_buffer *rxb,
                                struct iwl_device_cmd *cmd);
-int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                        struct iwl_device_cmd *cmd);
 int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                            struct iwl_device_cmd *cmd);
 int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm,
@@ -1147,9 +1117,12 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload,
                          struct ieee80211_vif *disabled_vif);
 
 /* Scanning */
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                          struct cfg80211_scan_request *req,
+                          struct ieee80211_scan_ies *ies);
 int iwl_mvm_scan_size(struct iwl_mvm *mvm);
 int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
 void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
 
 /* Scheduled scan */
@@ -1161,31 +1134,18 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
                                                struct iwl_device_cmd *cmd);
 int iwl_mvm_config_sched_scan_profiles(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_sched_scan_start(struct iwl_mvm *mvm,
+                            struct ieee80211_vif *vif,
+                            struct cfg80211_sched_scan_request *req,
+                            struct ieee80211_scan_ies *ies,
+                            int type);
 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,
                                    struct iwl_device_cmd *cmd);
 
-/* Unified scan */
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_scan_request *req);
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
-                                   struct ieee80211_vif *vif,
-                                   struct cfg80211_sched_scan_request *req,
-                                   struct ieee80211_scan_ies *ies);
-
 /* UMAC scan */
 int iwl_mvm_config_scan(struct iwl_mvm *mvm);
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                     struct ieee80211_scan_request *req);
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                           struct cfg80211_sched_scan_request *req,
-                           struct ieee80211_scan_ies *ies);
 int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
                                        struct iwl_rx_cmd_buffer *rxb,
                                        struct iwl_device_cmd *cmd);
index a08b03d..02028bc 100644 (file)
@@ -246,7 +246,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
                   true),
 
-       RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
        RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
 
        RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif,
@@ -280,7 +279,6 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(BINDING_CONTEXT_CMD),
        CMD(TIME_QUOTA_CMD),
        CMD(NON_QOS_TX_COUNTER_CMD),
-       CMD(RADIO_VERSION_NOTIFICATION),
        CMD(SCAN_REQUEST_CMD),
        CMD(SCAN_ABORT_CMD),
        CMD(SCAN_START_NOTIFICATION),
@@ -290,7 +288,6 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(PHY_CONFIGURATION_CMD),
        CMD(CALIB_RES_NOTIF_PHY_DB),
        CMD(SET_CALIB_DEFAULT_CMD),
-       CMD(CALIBRATION_COMPLETE_NOTIFICATION),
        CMD(ADD_STA_KEY),
        CMD(ADD_STA),
        CMD(REMOVE_STA),
@@ -865,6 +862,16 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
                return;
 
        mutex_lock(&mvm->mutex);
+
+       /* stop recording */
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+               /* wait before we collect the data till the DBGC stop */
+               udelay(100);
+       }
+
        iwl_mvm_fw_error_dump(mvm);
 
        /* start recording again if the firmware is not crashed */
@@ -1253,11 +1260,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
                ieee80211_iterate_active_interfaces(
                        mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                        iwl_mvm_d0i3_disconnect_iter, mvm);
-
-       iwl_free_resp(&get_status_cmd);
 out:
        iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
 
+       /* qos_seq might point inside resp_pkt, so free it only now */
+       if (get_status_cmd.resp_pkt)
+               iwl_free_resp(&get_status_cmd);
+
        /* the FW might have updated the regdomain */
        iwl_mvm_update_changed_regdom(mvm);
 
index f9928f2..0440142 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -2133,7 +2133,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        }
 
        /* current tx rate */
-       index = lq_sta->last_txrate_idx;
+       index = rate->index;
 
        /* rates available for this association, and for modulation mode */
        rate_mask = rs_get_supported_rates(lq_sta, rate);
@@ -2181,14 +2181,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
                 * or search for a new one? */
                rs_stay_in_table(lq_sta, false);
 
-               goto out;
-       }
-       /* Else we have enough samples; calculate estimate of
-        * actual average throughput */
-       if (window->average_tpt != ((window->success_ratio *
-                       tbl->expected_tpt[index] + 64) / 128)) {
-               window->average_tpt = ((window->success_ratio *
-                                       tbl->expected_tpt[index] + 64) / 128);
+               return;
        }
 
        /* If we are searching for better modulation mode, check success. */
@@ -2400,9 +2393,6 @@ lq_update:
                        rs_set_stay_in_table(mvm, 0, lq_sta);
                }
        }
-
-out:
-       lq_sta->last_txrate_idx = index;
 }
 
 struct rs_init_rate_info {
@@ -2545,7 +2535,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        rate = &tbl->rate;
 
        rs_get_initial_rate(mvm, lq_sta, band, rate);
-       lq_sta->last_txrate_idx = rate->index;
 
        WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
        if (rate->ant == ANT_A)
@@ -3223,9 +3212,6 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
        if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS)
                rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate);
 
-       if (num_of_ant(initial_rate->ant) == 1)
-               lq_cmd->single_stream_ant_msk = initial_rate->ant;
-
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
 
index e4aa934..2a3da31 100644 (file)
@@ -322,8 +322,6 @@ struct iwl_lq_sta {
        struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
        u8 tx_agg_tid_en;
 
-       /* used to be in sta_info */
-       int last_txrate_idx;
        /* last tx rate_n_flags */
        u32 last_rate_n_flags;
        /* packets destined for this STA are aggregated */
index 78ec7db..d6314dd 100644 (file)
@@ -478,6 +478,11 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
        if (vif->type != NL80211_IFTYPE_STATION)
                return;
 
+       if (sig == 0) {
+               IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n");
+               return;
+       }
+
        mvmvif->bf_data.ave_beacon_signal = sig;
 
        /* BT Coex */
index 74e1c86..e50fd3f 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <net/mac80211.h>
 
 #include "mvm.h"
-#include "iwl-eeprom-parse.h"
 #include "fw-api-scan.h"
 
-#define IWL_PLCP_QUIET_THRESH 1
-#define IWL_ACTIVE_QUIET_TIME 10
 #define IWL_DENSE_EBS_SCAN_RATIO 5
 #define IWL_SPARSE_EBS_SCAN_RATIO 1
 
@@ -79,18 +76,34 @@ struct iwl_mvm_scan_params {
        u32 max_out_time;
        u32 suspend_time;
        bool passive_fragmented;
+       u32 n_channels;
+       u16 delay;
+       int n_ssids;
+       struct cfg80211_ssid *ssids;
+       struct ieee80211_channel **channels;
+       u16 interval; /* interval between scans (in secs) */
+       u32 flags;
+       u8 *mac_addr;
+       u8 *mac_addr_mask;
+       bool no_cck;
+       bool pass_all;
+       int n_match_sets;
+       struct iwl_scan_probe_req preq;
+       struct cfg80211_match_set *match_sets;
        struct _dwell {
                u16 passive;
                u16 active;
                u16 fragmented;
        } dwell[IEEE80211_NUM_BANDS];
+       struct {
+               u8 iterations;
+               u8 full_scan_mul; /* not used for UMAC */
+       } schedule[2];
 };
 
 enum iwl_umac_scan_uid_type {
        IWL_UMAC_SCAN_UID_REG_SCAN      = BIT(0),
        IWL_UMAC_SCAN_UID_SCHED_SCAN    = BIT(1),
-       IWL_UMAC_SCAN_UID_ALL           = IWL_UMAC_SCAN_UID_REG_SCAN |
-                                         IWL_UMAC_SCAN_UID_SCHED_SCAN,
 };
 
 static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
@@ -142,28 +155,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
                return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant);
 }
 
-/*
- * We insert the SSIDs in an inverted order, because the FW will
- * invert it back. The most prioritized SSID, which is first in the
- * request list, is not copied here, but inserted directly to the probe
- * request.
- */
-static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
-                                   struct cfg80211_ssid *ssids,
-                                   int n_ssids, int first)
-{
-       int fw_idx, req_idx;
-
-       for (req_idx = n_ssids - 1, fw_idx = 0; req_idx >= first;
-            req_idx--, fw_idx++) {
-               cmd_ssid[fw_idx].id = WLAN_EID_SSID;
-               cmd_ssid[fw_idx].len = ssids[req_idx].ssid_len;
-               memcpy(cmd_ssid[fw_idx].ssid,
-                      ssids[req_idx].ssid,
-                      ssids[req_idx].ssid_len);
-       }
-}
-
 /*
  * If req->n_ssids > 0, it means we should do an active scan.
  * In case of active scan w/o directed scan, we receive a zero-length SSID
@@ -203,10 +194,9 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
                *global_cnt += 1;
 }
 
-static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
-                                    struct ieee80211_vif *vif,
-                                    int n_ssids, u32 flags,
-                                    struct iwl_mvm_scan_params *params)
+static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif,
+                                   struct iwl_mvm_scan_params *params)
 {
        int global_cnt = 0;
        enum ieee80211_band band;
@@ -216,7 +206,6 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_scan_condition_iterator,
                                            &global_cnt);
-
        if (!global_cnt)
                goto not_bound;
 
@@ -257,7 +246,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
                }
        }
 
-       if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
+       if ((params->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+           (params->max_out_time > 200))
                params->max_out_time = 200;
 
 not_bound:
@@ -268,9 +258,24 @@ not_bound:
 
                params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm,
                                                                        band);
-               params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
-                                                                     n_ssids);
+               params->dwell[band].active =
+                       iwl_mvm_get_active_dwell(mvm, band, params->n_ssids);
        }
+
+       IWL_DEBUG_SCAN(mvm,
+                      "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n",
+                      params->max_out_time, params->suspend_time,
+                      params->passive_fragmented);
+       IWL_DEBUG_SCAN(mvm,
+                      "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n",
+                      params->dwell[IEEE80211_BAND_2GHZ].passive,
+                      params->dwell[IEEE80211_BAND_2GHZ].active,
+                      params->dwell[IEEE80211_BAND_2GHZ].fragmented);
+       IWL_DEBUG_SCAN(mvm,
+                      "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n",
+                      params->dwell[IEEE80211_BAND_5GHZ].passive,
+                      params->dwell[IEEE80211_BAND_5GHZ].active,
+                      params->dwell[IEEE80211_BAND_5GHZ].fragmented);
 }
 
 static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
@@ -280,8 +285,7 @@ static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
               IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT;
 }
 
-static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
-                                          bool is_sched_scan)
+static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm)
 {
        int max_probe_len;
 
@@ -297,9 +301,9 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
        return max_probe_len;
 }
 
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
 {
-       int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);
+       int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm);
 
        /* TODO: [BUG] This function should return the maximum allowed size of
         * scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
@@ -319,7 +323,7 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
                                                struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+       struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data;
 
        IWL_DEBUG_SCAN(mvm,
                       "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
@@ -342,36 +346,58 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
                                           struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_periodic_scan_complete *scan_notif;
-
-       scan_notif = (void *)pkt->data;
+       struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data;
+       bool aborted = (scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
+       bool ebs_successful = (scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS);
 
        /* scan status must be locked for proper checking */
        lockdep_assert_held(&mvm->mutex);
 
-       IWL_DEBUG_SCAN(mvm,
-                      "%s completed, status %s, EBS status %s\n",
-                      mvm->scan_status == IWL_MVM_SCAN_SCHED ?
-                               "Scheduled scan" : "Scan",
-                      scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
-                               "completed" : "aborted",
-                      scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
-                               "success" : "failed");
+       /* We first check if we were stopping a scan, in which case we
+        * just clear the stopping flag.  Then we check if it was a
+        * firmware initiated stop, in which case we need to inform
+        * mac80211.
+        * Note that we can have a stopping and a running scan
+        * simultaneously, but we can't have two different types of
+        * scans stopping or running at the same time (since LMAC
+        * doesn't support it).
+        */
 
+       if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) {
+               WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR);
 
-       /* only call mac80211 completion if the stop was initiated by FW */
-       if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
+               IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n",
+                              aborted ? "aborted" : "completed",
+                              ebs_successful ? "successful" : "failed");
+
+               mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED;
+       } else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) {
+               IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s\n",
+                              aborted ? "aborted" : "completed",
+                              ebs_successful ? "successful" : "failed");
+
+               mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_REGULAR;
+       } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) {
+               WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR);
+
+               IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s (FW)\n",
+                              aborted ? "aborted" : "completed",
+                              ebs_successful ? "successful" : "failed");
+
+               mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
                ieee80211_sched_scan_stopped(mvm->hw);
-       } else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
+       } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
+               IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
+                              aborted ? "aborted" : "completed",
+                              ebs_successful ? "successful" : "failed");
+
+               mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
                ieee80211_scan_completed(mvm->hw,
                                scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        }
 
-       if (scan_notif->ebs_status)
-               mvm->last_ebs_successful = false;
+       mvm->last_ebs_successful = ebs_successful;
 
        return 0;
 }
@@ -390,9 +416,12 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
        return -1;
 }
 
-static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
-                                       struct iwl_ssid_ie *direct_scan,
-                                       u32 *ssid_bitmap, bool basic_ssid)
+/* We insert the SSIDs in an inverted order, because the FW will
+ * invert it back.
+ */
+static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params,
+                                struct iwl_ssid_ie *ssids,
+                                u32 *ssid_bitmap)
 {
        int i, j;
        int index;
@@ -402,33 +431,34 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
         * iwl_config_sched_scan_profiles() uses the order of these ssids to
         * config match list.
         */
-       for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
+       for (i = 0, j = params->n_match_sets - 1;
+            j >= 0 && i < PROBE_OPTION_MAX;
+            i++, j--) {
                /* skip empty SSID matchsets */
-               if (!req->match_sets[i].ssid.ssid_len)
+               if (!params->match_sets[j].ssid.ssid_len)
                        continue;
-               direct_scan[i].id = WLAN_EID_SSID;
-               direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
-               memcpy(direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
-                      direct_scan[i].len);
+               ssids[i].id = WLAN_EID_SSID;
+               ssids[i].len = params->match_sets[j].ssid.ssid_len;
+               memcpy(ssids[i].ssid, params->match_sets[j].ssid.ssid,
+                      ssids[i].len);
        }
 
        /* add SSIDs from scan SSID list */
        *ssid_bitmap = 0;
-       for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
-               index = iwl_ssid_exist(req->ssids[j].ssid,
-                                      req->ssids[j].ssid_len,
-                                      direct_scan);
+       for (j = params->n_ssids - 1;
+            j >= 0 && i < PROBE_OPTION_MAX;
+            i++, j--) {
+               index = iwl_ssid_exist(params->ssids[j].ssid,
+                                      params->ssids[j].ssid_len,
+                                      ssids);
                if (index < 0) {
-                       if (!req->ssids[j].ssid_len && basic_ssid)
-                               continue;
-                       direct_scan[i].id = WLAN_EID_SSID;
-                       direct_scan[i].len = req->ssids[j].ssid_len;
-                       memcpy(direct_scan[i].ssid, req->ssids[j].ssid,
-                              direct_scan[i].len);
-                       *ssid_bitmap |= BIT(i + 1);
-                       i++;
+                       ssids[i].id = WLAN_EID_SSID;
+                       ssids[i].len = params->ssids[j].ssid_len;
+                       memcpy(ssids[i].ssid, params->ssids[j].ssid,
+                              ssids[i].len);
+                       *ssid_bitmap |= BIT(i);
                } else {
-                       *ssid_bitmap |= BIT(index + 1);
+                       *ssid_bitmap |= BIT(index);
                }
        }
 }
@@ -515,29 +545,6 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
        return true;
 }
 
-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.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
-               ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
-               if (ret)
-                       return ret;
-               ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
-       } else {
-               mvm->scan_status = IWL_MVM_SCAN_SCHED;
-               ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
-               if (ret)
-                       return ret;
-               ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
-       }
-
-       return ret;
-}
-
 static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
 {
        int ret;
@@ -549,7 +556,7 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
        /* Exit instantly with error when device is not ready
         * to receive scan abort command or it does not perform
         * scheduled scan currently */
-       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+       if (!mvm->scan_status)
                return -EIO;
 
        ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
@@ -576,7 +583,7 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        int ret;
        struct iwl_notification_wait wait_scan_done;
        static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
-       bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED;
+       bool sched = !!(mvm->scan_status & IWL_MVM_SCAN_SCHED);
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -584,7 +591,11 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN,
                                          notify);
 
-       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+       /* FIXME: For now we only check if no scan is set here, since
+        * we only support LMAC in this flow and it doesn't support
+        * multiple scans.
+        */
+       if (!mvm->scan_status)
                return 0;
 
        if (iwl_mvm_is_radio_killed(mvm)) {
@@ -606,34 +617,37 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        }
 
        IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
-                      sched ? "offloaded " : "");
+                      sched ? "scheduled " : "");
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
 out:
-       /*
-        * Clear the scan status so the next scan requests will succeed. This
-        * also ensures the Rx handler doesn't do anything, as the scan was
-        * stopped from above. Since the rx handler won't do anything now,
-        * we have to release the scan reference here.
+       /* Clear the scan status so the next scan requests will
+        * succeed and mark the scan as stopping, so that the Rx
+        * handler doesn't do anything, as the scan was 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)
+       if (mvm->scan_status == IWL_MVM_SCAN_REGULAR)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-       mvm->scan_status = IWL_MVM_SCAN_NONE;
-
-       if (notify) {
-               if (sched)
+       if (sched) {
+               mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
+               mvm->scan_status |= IWL_MVM_SCAN_STOPPING_SCHED;
+               if (notify)
                        ieee80211_sched_scan_stopped(mvm->hw);
-               else
+       } else {
+               mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
+               mvm->scan_status |= IWL_MVM_SCAN_STOPPING_REGULAR;
+               if (notify)
                        ieee80211_scan_completed(mvm->hw, true);
        }
 
        return ret;
 }
 
-static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
-                                            struct iwl_scan_req_tx_cmd *tx_cmd,
-                                            bool no_cck)
+static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm,
+                                    struct iwl_scan_req_tx_cmd *tx_cmd,
+                                    bool no_cck)
 {
        tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
                                         TX_CMD_FLG_BT_DIS);
@@ -654,7 +668,7 @@ static void
 iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm,
                               struct ieee80211_channel **channels,
                               int n_channels, u32 ssid_bitmap,
-                              struct iwl_scan_req_unified_lmac *cmd)
+                              struct iwl_scan_req_lmac *cmd)
 {
        struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data;
        int i;
@@ -707,13 +721,14 @@ static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies,
 }
 
 static void
-iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                                struct ieee80211_scan_ies *ies,
-                                struct iwl_scan_probe_req *preq,
-                                const u8 *mac_addr, const u8 *mac_addr_mask)
+iwl_mvm_build_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                        struct ieee80211_scan_ies *ies,
+                        struct iwl_mvm_scan_params *params)
 {
-       struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf;
+       struct ieee80211_mgmt *frame = (void *)params->preq.buf;
        u8 *pos, *newpos;
+       const u8 *mac_addr = params->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
+               params->mac_addr : NULL;
 
        /*
         * Unfortunately, right now the offload scan doesn't support randomising
@@ -722,7 +737,8 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
         * random, only when it's restarted, but at least that helps a bit.
         */
        if (mac_addr)
-               get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask);
+               get_random_mask_addr(frame->sa, mac_addr,
+                                    params->mac_addr_mask);
        else
                memcpy(frame->sa, vif->addr, ETH_ALEN);
 
@@ -735,245 +751,147 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        *pos++ = WLAN_EID_SSID;
        *pos++ = 0;
 
-       preq->mac_header.offset = 0;
-       preq->mac_header.len = cpu_to_le16(24 + 2);
+       params->preq.mac_header.offset = 0;
+       params->preq.mac_header.len = cpu_to_le16(24 + 2);
 
        /* Insert ds parameter set element on 2.4 GHz band */
        newpos = iwl_mvm_copy_and_insert_ds_elem(mvm,
                                                 ies->ies[IEEE80211_BAND_2GHZ],
                                                 ies->len[IEEE80211_BAND_2GHZ],
                                                 pos);
-       preq->band_data[0].offset = cpu_to_le16(pos - preq->buf);
-       preq->band_data[0].len = cpu_to_le16(newpos - pos);
+       params->preq.band_data[0].offset = cpu_to_le16(pos - params->preq.buf);
+       params->preq.band_data[0].len = cpu_to_le16(newpos - pos);
        pos = newpos;
 
        memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ],
               ies->len[IEEE80211_BAND_5GHZ]);
-       preq->band_data[1].offset = cpu_to_le16(pos - preq->buf);
-       preq->band_data[1].len = cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
+       params->preq.band_data[1].offset = cpu_to_le16(pos - params->preq.buf);
+       params->preq.band_data[1].len =
+               cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
        pos += ies->len[IEEE80211_BAND_5GHZ];
 
        memcpy(pos, ies->common_ies, ies->common_ie_len);
-       preq->common_data.offset = cpu_to_le16(pos - preq->buf);
-       preq->common_data.len = cpu_to_le16(ies->common_ie_len);
+       params->preq.common_data.offset = cpu_to_le16(pos - params->preq.buf);
+       params->preq.common_data.len = cpu_to_le16(ies->common_ie_len);
 }
 
-static void
-iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
-                                      struct iwl_scan_req_unified_lmac *cmd,
-                                      struct iwl_mvm_scan_params *params)
+static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
+                                   struct iwl_scan_req_lmac *cmd,
+                                   struct iwl_mvm_scan_params *params)
 {
-       memset(cmd, 0, ksize(cmd));
        cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
        cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
        if (params->passive_fragmented)
                cmd->fragmented_dwell =
                                params->dwell[IEEE80211_BAND_2GHZ].fragmented;
-       cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
        cmd->max_out_time = cpu_to_le32(params->max_out_time);
        cmd->suspend_time = cpu_to_le32(params->suspend_time);
        cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
-       cmd->iter_num = cpu_to_le32(1);
-
-       if (iwl_mvm_rrm_scan_needed(mvm))
-               cmd->scan_flags |=
-                       cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
 }
 
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_scan_request *req)
+static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
+                                    struct ieee80211_scan_ies *ies,
+                                    int n_channels)
 {
-       struct iwl_host_cmd hcmd = {
-               .id = SCAN_OFFLOAD_REQUEST_CMD,
-               .len = { sizeof(struct iwl_scan_req_unified_lmac) +
-                        sizeof(struct iwl_scan_channel_cfg_lmac) *
-                               mvm->fw->ucode_capa.n_scan_channels +
-                        sizeof(struct iwl_scan_probe_req), },
-               .data = { mvm->scan_cmd, },
-               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
-       };
-       struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
-       struct iwl_scan_probe_req *preq;
-       struct iwl_mvm_scan_params params = {};
-       u32 flags;
-       u32 ssid_bitmap = 0;
-       int ret, i;
-
-       lockdep_assert_held(&mvm->mutex);
-
-       /* we should have failed registration if scan_cmd was NULL */
-       if (WARN_ON(mvm->scan_cmd == NULL))
-               return -ENOMEM;
-
-       if (req->req.n_ssids > PROBE_OPTION_MAX ||
-           req->ies.common_ie_len + req->ies.len[NL80211_BAND_2GHZ] +
-           req->ies.len[NL80211_BAND_5GHZ] >
-               iwl_mvm_max_scan_ie_fw_cmd_room(mvm, false) ||
-           req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
-               return -ENOBUFS;
+       return ((n_ssids <= PROBE_OPTION_MAX) &&
+               (n_channels <= mvm->fw->ucode_capa.n_scan_channels) &
+               (ies->common_ie_len +
+                ies->len[NL80211_BAND_2GHZ] +
+                ies->len[NL80211_BAND_5GHZ] <=
+                iwl_mvm_max_scan_ie_fw_cmd_room(mvm)));
+}
 
-       mvm->scan_status = IWL_MVM_SCAN_OS;
+static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, int n_iterations)
+{
+       const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;
 
-       iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
-                                &params);
+       /* We can only use EBS if:
+        *      1. the feature is supported;
+        *      2. the last EBS was successful;
+        *      3. if only single scan, the single scan EBS API is supported.
+        */
+       return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
+               mvm->last_ebs_successful &&
+               (n_iterations > 1 ||
+                (capa->api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS)));
+}
 
-       iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
+static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)
+{
+       return params->schedule[0].iterations + params->schedule[1].iterations;
+}
 
-       cmd->n_channels = (u8)req->req.n_channels;
+static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
+                                  struct iwl_mvm_scan_params *params)
+{
+       int flags = 0;
 
-       flags = IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+       if (params->n_ssids == 0)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
 
-       if (req->req.n_ssids == 1 && req->req.ssids[0].ssid_len != 0)
+       if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
                flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
 
-       if (params.passive_fragmented)
+       if (params->passive_fragmented)
                flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
 
-       if (req->req.n_ssids == 0)
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
-
-       cmd->scan_flags |= cpu_to_le32(flags);
-
-       cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band);
-       cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
-                                       MAC_FILTER_IN_BEACON);
-       iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, req->req.no_cck);
-       iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->req.ssids,
-                               req->req.n_ssids, 0);
-
-       cmd->schedule[0].delay = 0;
-       cmd->schedule[0].iterations = 1;
-       cmd->schedule[0].full_scan_mul = 0;
-       cmd->schedule[1].delay = 0;
-       cmd->schedule[1].iterations = 0;
-       cmd->schedule[1].full_scan_mul = 0;
-
-       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
-           mvm->last_ebs_successful) {
-               cmd->channel_opt[0].flags =
-                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
-                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
-                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
-               cmd->channel_opt[0].non_ebs_ratio =
-                       cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
-               cmd->channel_opt[1].flags =
-                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
-                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
-                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
-               cmd->channel_opt[1].non_ebs_ratio =
-                       cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
-       }
-
-       for (i = 1; i <= req->req.n_ssids; i++)
-               ssid_bitmap |= BIT(i);
-
-       iwl_mvm_lmac_scan_cfg_channels(mvm, req->req.channels,
-                                      req->req.n_channels, ssid_bitmap,
-                                      cmd);
+       if (iwl_mvm_rrm_scan_needed(mvm))
+               flags |= IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED;
 
-       preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
-                       mvm->fw->ucode_capa.n_scan_channels);
+       if (params->pass_all)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+       else
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
 
-       iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq,
-               req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
-                       req->req.mac_addr : NULL,
-               req->req.mac_addr_mask);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (mvm->scan_iter_notif_enabled)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+#endif
 
-       ret = iwl_mvm_send_cmd(mvm, &hcmd);
-       if (!ret) {
-               IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
-       } else {
-               /*
-                * If the scan failed, it usually means that the FW was unable
-                * to allocate the time events. Warn on it, but maybe we
-                * should try to send the command again with different params.
-                */
-               IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
-               ret = -EIO;
-       }
-       return ret;
+       return flags;
 }
 
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
-                                   struct ieee80211_vif *vif,
-                                   struct cfg80211_sched_scan_request *req,
-                                   struct ieee80211_scan_ies *ies)
+static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                            struct iwl_mvm_scan_params *params)
 {
-       struct iwl_host_cmd hcmd = {
-               .id = SCAN_OFFLOAD_REQUEST_CMD,
-               .len = { sizeof(struct iwl_scan_req_unified_lmac) +
-                        sizeof(struct iwl_scan_channel_cfg_lmac) *
-                               mvm->fw->ucode_capa.n_scan_channels +
-                        sizeof(struct iwl_scan_probe_req), },
-               .data = { mvm->scan_cmd, },
-               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
-       };
-       struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
-       struct iwl_scan_probe_req *preq;
-       struct iwl_mvm_scan_params params = {};
-       int ret;
-       u32 flags = 0, ssid_bitmap = 0;
+       struct iwl_scan_req_lmac *cmd = mvm->scan_cmd;
+       struct iwl_scan_probe_req *preq =
+               (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
+                        mvm->fw->ucode_capa.n_scan_channels);
+       u32 ssid_bitmap = 0;
+       int n_iterations = iwl_mvm_scan_total_iterations(params);
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* we should have failed registration if scan_cmd was NULL */
-       if (WARN_ON(mvm->scan_cmd == NULL))
-               return -ENOMEM;
-
-       if (req->n_ssids > PROBE_OPTION_MAX ||
-           ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
-           ies->len[NL80211_BAND_5GHZ] >
-               iwl_mvm_max_scan_ie_fw_cmd_room(mvm, true) ||
-           req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
-               return -ENOBUFS;
-
-       iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
-
-       iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
-
-       cmd->n_channels = (u8)req->n_channels;
-
-       cmd->delay = cpu_to_le32(req->delay);
-
-       if (iwl_mvm_scan_pass_all(mvm, req))
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
-       else
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
-
-       if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
+       memset(cmd, 0, ksize(cmd));
 
-       if (params.passive_fragmented)
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
+       iwl_mvm_scan_lmac_dwell(mvm, cmd, params);
 
-       if (req->n_ssids == 0)
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
+       cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
+       cmd->iter_num = cpu_to_le32(1);
+       cmd->n_channels = (u8)params->n_channels;
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       if (mvm->scan_iter_notif_enabled)
-               flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
-#endif
+       cmd->delay = cpu_to_le32(params->delay);
 
-       cmd->scan_flags |= cpu_to_le32(flags);
+       cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params));
 
-       cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
+       cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band);
        cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
                                        MAC_FILTER_IN_BEACON);
-       iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false);
-       iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false);
+       iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck);
+       iwl_scan_build_ssids(params, cmd->direct_scan, &ssid_bitmap);
 
-       cmd->schedule[0].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
-       cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
-       cmd->schedule[0].full_scan_mul = 1;
+       /* this API uses bits 1-20 instead of 0-19 */
+       ssid_bitmap <<= 1;
 
-       cmd->schedule[1].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
-       cmd->schedule[1].iterations = 0xff;
-       cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+       cmd->schedule[0].delay = cpu_to_le16(params->interval);
+       cmd->schedule[0].iterations = params->schedule[0].iterations;
+       cmd->schedule[0].full_scan_mul = params->schedule[0].full_scan_mul;
+       cmd->schedule[1].delay = cpu_to_le16(params->interval);
+       cmd->schedule[1].iterations = params->schedule[1].iterations;
+       cmd->schedule[1].full_scan_mul = params->schedule[1].iterations;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
-           mvm->last_ebs_successful) {
+       if (iwl_mvm_scan_use_ebs(mvm, n_iterations)) {
                cmd->channel_opt[0].flags =
                        cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
                                    IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
@@ -988,48 +906,27 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
                        cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
        }
 
-       iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
-                                      ssid_bitmap, cmd);
+       iwl_mvm_lmac_scan_cfg_channels(mvm, params->channels,
+                                      params->n_channels, ssid_bitmap, cmd);
 
-       preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
-                       mvm->fw->ucode_capa.n_scan_channels);
+       *preq = params->preq;
 
-       iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq,
-               req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
-                       req->mac_addr : NULL,
-               req->mac_addr_mask);
-
-       ret = iwl_mvm_send_cmd(mvm, &hcmd);
-       if (!ret) {
-               IWL_DEBUG_SCAN(mvm,
-                              "Sched scan request was sent successfully\n");
-       } else {
-               /*
-                * If the scan failed, it usually means that the FW was unable
-                * to allocate the time events. Warn on it, but maybe we
-                * should try to send the command again with different params.
-                */
-               IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
-               ret = -EIO;
-       }
-       return ret;
+       return 0;
 }
 
-
 int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
 {
        if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
                return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN,
                                          true);
 
-       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+       if (!(mvm->scan_status & IWL_MVM_SCAN_REGULAR))
                return 0;
 
        if (iwl_mvm_is_radio_killed(mvm)) {
                ieee80211_scan_completed(mvm->hw, true);
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
+               mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
                return 0;
        }
 
@@ -1155,7 +1052,7 @@ static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid)
 {
        int i;
 
-       for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
+       for (i = 0; i < mvm->max_scans; i++)
                if (mvm->scan_uid[i] == uid)
                        return i;
 
@@ -1172,7 +1069,7 @@ static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm,
 {
        int i;
 
-       for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
+       for (i = 0; i < mvm->max_scans; i++)
                if (mvm->scan_uid[i] & type)
                        return true;
 
@@ -1184,7 +1081,7 @@ static int iwl_mvm_find_first_scan(struct iwl_mvm *mvm,
 {
        int i;
 
-       for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
+       for (i = 0; i < mvm->max_scans; i++)
                if (mvm->scan_uid[i] & type)
                        return i;
 
@@ -1208,22 +1105,17 @@ static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm,
                uid = type | (mvm->scan_seq_num <<
                              IWL_UMAC_SCAN_UID_SEQ_OFFSET);
                mvm->scan_seq_num++;
-       } while (iwl_mvm_find_scan_uid(mvm, uid) <
-                IWL_MVM_MAX_SIMULTANEOUS_SCANS);
+       } while (iwl_mvm_find_scan_uid(mvm, uid) < mvm->max_scans);
 
        IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid);
 
        return uid;
 }
 
-static void
-iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
+static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
                                    struct iwl_scan_req_umac *cmd,
                                    struct iwl_mvm_scan_params *params)
 {
-       memset(cmd, 0, ksize(cmd));
-       cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
-                                   sizeof(struct iwl_mvm_umac_cmd_hdr));
        cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
        cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
        if (params->passive_fragmented)
@@ -1232,6 +1124,11 @@ iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
        cmd->max_out_time = cpu_to_le32(params->max_out_time);
        cmd->suspend_time = cpu_to_le32(params->suspend_time);
        cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+
+       if (iwl_mvm_scan_total_iterations(params) == 0)
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+       else
+               cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
 }
 
 static void
@@ -1251,230 +1148,326 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
        }
 }
 
-static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids,
-                                         struct cfg80211_ssid *ssids,
-                                         int fragmented)
+static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
+                                  struct iwl_mvm_scan_params *params)
 {
        int flags = 0;
 
-       if (n_ssids == 0)
+       if (params->n_ssids == 0)
                flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
 
-       if (n_ssids == 1 && ssids[0].ssid_len != 0)
+       if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
 
-       if (fragmented)
+       if (params->passive_fragmented)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;
 
        if (iwl_mvm_rrm_scan_needed(mvm))
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
 
+       if (params->pass_all)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
+       else
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+
+       if (iwl_mvm_scan_total_iterations(params) > 1)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+
        return flags;
 }
 
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                     struct ieee80211_scan_request *req)
+static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                            struct iwl_mvm_scan_params *params)
 {
-       struct iwl_host_cmd hcmd = {
-               .id = SCAN_REQ_UMAC,
-               .len = { iwl_mvm_scan_size(mvm), },
-               .data = { mvm->scan_cmd, },
-               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
-       };
        struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
        struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
                sizeof(struct iwl_scan_channel_cfg_umac) *
                        mvm->fw->ucode_capa.n_scan_channels;
-       struct iwl_mvm_scan_params params = {};
-       u32 uid, flags;
+       u32 uid;
        u32 ssid_bitmap = 0;
-       int ret, i, uid_idx;
+       int n_iterations = iwl_mvm_scan_total_iterations(params);
+       int uid_idx;
 
        lockdep_assert_held(&mvm->mutex);
 
        uid_idx = iwl_mvm_find_free_scan_uid(mvm);
-       if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+       if (uid_idx >= mvm->max_scans)
                return -EBUSY;
 
-       /* we should have failed registration if scan_cmd was NULL */
-       if (WARN_ON(mvm->scan_cmd == NULL))
-               return -ENOMEM;
-
-       if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX ||
-                   req->ies.common_ie_len +
-                   req->ies.len[NL80211_BAND_2GHZ] +
-                   req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 >
-                   SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels >
-                   mvm->fw->ucode_capa.n_scan_channels))
-               return -ENOBUFS;
+       memset(cmd, 0, ksize(cmd));
+       cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
+                                   sizeof(struct iwl_mvm_umac_cmd_hdr));
 
-       iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
-                                &params);
+       iwl_mvm_scan_umac_dwell(mvm, cmd, params);
 
-       iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
+       if (n_iterations == 1)
+               uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
+       else
+               uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN);
 
-       uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
        mvm->scan_uid[uid_idx] = uid;
        cmd->uid = cpu_to_le32(uid);
 
-       cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
-
-       flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids,
-                                              req->req.ssids,
-                                              params.passive_fragmented);
-
-       flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
+       cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
 
-       cmd->general_flags = cpu_to_le32(flags);
-
-       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
-           mvm->last_ebs_successful)
+       if (iwl_mvm_scan_use_ebs(mvm, n_iterations))
                cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
                                     IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
                                     IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
 
-       cmd->n_channels = req->req.n_channels;
+       cmd->n_channels = params->n_channels;
 
-       for (i = 0; i < req->req.n_ssids; i++)
-               ssid_bitmap |= BIT(i);
+       iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap);
 
-       iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels,
-                                      req->req.n_channels, ssid_bitmap, cmd);
+       iwl_mvm_umac_scan_cfg_channels(mvm, params->channels,
+                                      params->n_channels, ssid_bitmap, cmd);
 
-       sec_part->schedule[0].iter_count = 1;
-       sec_part->delay = 0;
+       /* With UMAC we can have only one schedule, so use the sum of
+        * the iterations (with a a maximum of 255).
+        */
+       sec_part->schedule[0].iter_count =
+               (n_iterations > 255) ? 255 : n_iterations;
+       sec_part->schedule[0].interval = cpu_to_le16(params->interval);
 
-       iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq,
-               req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
-                       req->req.mac_addr : NULL,
-               req->req.mac_addr_mask);
+       sec_part->delay = cpu_to_le16(params->delay);
+       sec_part->preq = params->preq;
 
-       iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids,
-                               req->req.n_ssids, 0);
+       return 0;
+}
 
-       ret = iwl_mvm_send_cmd(mvm, &hcmd);
-       if (!ret) {
-               IWL_DEBUG_SCAN(mvm,
-                              "Scan request was sent successfully\n");
-       } else {
-               /*
-                * If the scan failed, it usually means that the FW was unable
-                * to allocate the time events. Warn on it, but maybe we
-                * should try to send the command again with different params.
-                */
-               IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
-       }
-       return ret;
+static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
+{
+       return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK);
 }
 
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                           struct cfg80211_sched_scan_request *req,
-                           struct ieee80211_scan_ies *ies)
+static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
 {
+       /* This looks a bit arbitrary, but the idea is that if we run
+        * out of possible simultaneous scans and the userspace is
+        * trying to run a scan type that is already running, we
+        * return -EBUSY.  But if the userspace wants to start a
+        * different type of scan, we stop the opposite type to make
+        * space for the new request.  The reason is backwards
+        * compatibility with old wpa_supplicant that wouldn't stop a
+        * scheduled scan before starting a normal scan.
+        */
+
+       if (iwl_mvm_num_scans(mvm) < mvm->max_scans)
+               return 0;
+
+       /* Use a switch, even though this is a bitmask, so that more
+        * than one bits set will fall in default and we will warn.
+        */
+       switch (type) {
+       case IWL_MVM_SCAN_REGULAR:
+               if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK)
+                       return -EBUSY;
+               return iwl_mvm_scan_offload_stop(mvm, true);
+       case IWL_MVM_SCAN_SCHED:
+               if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
+                       return -EBUSY;
+               return iwl_mvm_cancel_scan(mvm);
+       case IWL_MVM_SCAN_NETDETECT:
+               /* No need to stop anything for net-detect since the
+                * firmware is restarted anyway.  This way, any sched
+                * scans that were running will be restarted when we
+                * resume.
+               */
+               return 0;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return -EIO;
+}
 
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                          struct cfg80211_scan_request *req,
+                          struct ieee80211_scan_ies *ies)
+{
        struct iwl_host_cmd hcmd = {
-               .id = SCAN_REQ_UMAC,
                .len = { iwl_mvm_scan_size(mvm), },
                .data = { mvm->scan_cmd, },
                .dataflags = { IWL_HCMD_DFL_NOCOPY, },
        };
-       struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
-       struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
-               sizeof(struct iwl_scan_channel_cfg_umac) *
-                       mvm->fw->ucode_capa.n_scan_channels;
        struct iwl_mvm_scan_params params = {};
-       u32 uid, flags;
-       u32 ssid_bitmap = 0;
-       int ret, uid_idx;
+       int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
-       uid_idx = iwl_mvm_find_free_scan_uid(mvm);
-       if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+       if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+               IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
                return -EBUSY;
+       }
+
+       ret = iwl_mvm_check_running_scans(mvm, IWL_MVM_SCAN_REGULAR);
+       if (ret)
+               return ret;
+
+       iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
 
        /* we should have failed registration if scan_cmd was NULL */
-       if (WARN_ON(mvm->scan_cmd == NULL))
+       if (WARN_ON(!mvm->scan_cmd))
                return -ENOMEM;
 
-       if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX ||
-                   ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
-                   ies->len[NL80211_BAND_5GHZ] + 24 + 2 >
-                   SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels >
-                   mvm->fw->ucode_capa.n_scan_channels))
+       if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
                return -ENOBUFS;
 
-       iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags,
-                                        &params);
-
-       iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
+       params.n_ssids = req->n_ssids;
+       params.flags = req->flags;
+       params.n_channels = req->n_channels;
+       params.delay = 0;
+       params.interval = 0;
+       params.ssids = req->ssids;
+       params.channels = req->channels;
+       params.mac_addr = req->mac_addr;
+       params.mac_addr_mask = req->mac_addr_mask;
+       params.no_cck = req->no_cck;
+       params.pass_all = true;
+       params.n_match_sets = 0;
+       params.match_sets = NULL;
+
+       params.schedule[0].iterations = 1;
+       params.schedule[0].full_scan_mul = 0;
+       params.schedule[1].iterations = 0;
+       params.schedule[1].full_scan_mul = 0;
+
+       iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+       iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
 
-       cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
-
-       uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN);
-       mvm->scan_uid[uid_idx] = uid;
-       cmd->uid = cpu_to_le32(uid);
+       if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+               hcmd.id = SCAN_REQ_UMAC;
+               ret = iwl_mvm_scan_umac(mvm, vif, &params);
+       } else {
+               hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+               ret = iwl_mvm_scan_lmac(mvm, vif, &params);
+       }
 
-       cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
+       if (ret)
+               return ret;
 
-       flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids,
-                                              params.passive_fragmented);
+       ret = iwl_mvm_send_cmd(mvm, &hcmd);
+       if (!ret) {
+               IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+               mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
+       } else {
+               /* If the scan failed, it usually means that the FW was unable
+                * to allocate the time events. Warn on it, but maybe we
+                * should try to send the command again with different params.
+                */
+               IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+       }
 
-       flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+       if (ret)
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
-       if (iwl_mvm_scan_pass_all(mvm, req))
-               flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
-       else
-               flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+       return ret;
+}
 
-       cmd->general_flags = cpu_to_le32(flags);
+int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
+                            struct ieee80211_vif *vif,
+                            struct cfg80211_sched_scan_request *req,
+                            struct ieee80211_scan_ies *ies,
+                            int type)
+{
+       struct iwl_host_cmd hcmd = {
+               .len = { iwl_mvm_scan_size(mvm), },
+               .data = { mvm->scan_cmd, },
+               .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+       };
+       struct iwl_mvm_scan_params params = {};
+       int ret;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
-           mvm->last_ebs_successful)
-               cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
-                                    IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
-                                    IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+       lockdep_assert_held(&mvm->mutex);
 
-       cmd->n_channels = req->n_channels;
+       if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+               IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
+               return -EBUSY;
+       }
 
-       iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap,
-                                   false);
+       ret = iwl_mvm_check_running_scans(mvm, type);
+       if (ret)
+               return ret;
 
-       /* This API uses bits 0-19 instead of 1-20. */
-       ssid_bitmap = ssid_bitmap >> 1;
+       /* we should have failed registration if scan_cmd was NULL */
+       if (WARN_ON(!mvm->scan_cmd))
+               return -ENOMEM;
 
-       iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels,
-                                      ssid_bitmap, cmd);
+       if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
+               return -ENOBUFS;
 
-       sec_part->schedule[0].interval =
-                               cpu_to_le16(req->interval / MSEC_PER_SEC);
-       sec_part->schedule[0].iter_count = 0xff;
+       params.n_ssids = req->n_ssids;
+       params.flags = req->flags;
+       params.n_channels = req->n_channels;
+       params.ssids = req->ssids;
+       params.channels = req->channels;
+       params.mac_addr = req->mac_addr;
+       params.mac_addr_mask = req->mac_addr_mask;
+       params.no_cck = false;
+       params.pass_all =  iwl_mvm_scan_pass_all(mvm, req);
+       params.n_match_sets = req->n_match_sets;
+       params.match_sets = req->match_sets;
+
+       params.schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
+       params.schedule[0].full_scan_mul = 1;
+       params.schedule[1].iterations = 0xff;
+       params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+
+       if (req->interval > U16_MAX) {
+               IWL_DEBUG_SCAN(mvm,
+                              "interval value is > 16-bits, set to max possible\n");
+               params.interval = U16_MAX;
+       } else {
+               params.interval = req->interval / MSEC_PER_SEC;
+       }
 
+       /* In theory, LMAC scans can handle a 32-bit delay, but since
+        * waiting for over 18 hours to start the scan is a bit silly
+        * and to keep it aligned with UMAC scans (which only support
+        * 16-bit delays), trim it down to 16-bits.
+        */
        if (req->delay > U16_MAX) {
                IWL_DEBUG_SCAN(mvm,
                               "delay value is > 16-bits, set to max possible\n");
-               sec_part->delay = cpu_to_le16(U16_MAX);
+               params.delay = U16_MAX;
        } else {
-               sec_part->delay = cpu_to_le16(req->delay);
+               params.delay = req->delay;
        }
 
-       iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq,
-               req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
-                       req->mac_addr : NULL,
-               req->mac_addr_mask);
+       iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+       ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+       if (ret)
+               return ret;
+
+       iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
+
+       if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+               hcmd.id = SCAN_REQ_UMAC;
+               ret = iwl_mvm_scan_umac(mvm, vif, &params);
+       } else {
+               hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+               ret = iwl_mvm_scan_lmac(mvm, vif, &params);
+       }
+
+       if (ret)
+               return ret;
 
        ret = iwl_mvm_send_cmd(mvm, &hcmd);
        if (!ret) {
                IWL_DEBUG_SCAN(mvm,
                               "Sched scan request was sent successfully\n");
+               mvm->scan_status |= type;
        } else {
-               /*
-                * If the scan failed, it usually means that the FW was unable
+               /* If the scan failed, it usually means that the FW was unable
                 * to allocate the time events. Warn on it, but maybe we
                 * should try to send the command again with different params.
                 */
                IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
        }
+
        return ret;
 }
 
@@ -1491,7 +1484,7 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
        /*
         * Scan uid may be set to zero in case of scan abort request from above.
         */
-       if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+       if (uid_idx >= mvm->max_scans)
                return 0;
 
        IWL_DEBUG_SCAN(mvm,
@@ -1532,7 +1525,7 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
        if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC))
                return false;
 
-       if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+       if (uid_idx >= scan_done->mvm->max_scans)
                return false;
 
        /*
@@ -1581,7 +1574,7 @@ static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
 
        IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
 
-       for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
+       for (i = 0; i < mvm->max_scans; i++) {
                if (mvm->scan_uid[i] & type) {
                        int err;
 
@@ -1628,7 +1621,7 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
                                mvm->fw->ucode_capa.n_scan_channels +
                        sizeof(struct iwl_scan_req_umac_tail);
 
-       return sizeof(struct iwl_scan_req_unified_lmac) +
+       return sizeof(struct iwl_scan_req_lmac) +
                sizeof(struct iwl_scan_channel_cfg_lmac) *
                mvm->fw->ucode_capa.n_scan_channels +
                sizeof(struct iwl_scan_probe_req);
@@ -1644,13 +1637,13 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                u32 uid, i;
 
                uid = iwl_mvm_find_first_scan(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
-               if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS) {
+               if (uid < mvm->max_scans) {
                        ieee80211_scan_completed(mvm->hw, true);
                        mvm->scan_uid[uid] = 0;
                }
                uid = iwl_mvm_find_first_scan(mvm,
                                              IWL_UMAC_SCAN_UID_SCHED_SCAN);
-               if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS && !mvm->restart_fw) {
+               if (uid < mvm->max_scans && !mvm->restart_fw) {
                        ieee80211_sched_scan_stopped(mvm->hw);
                        mvm->scan_uid[uid] = 0;
                }
@@ -1659,28 +1652,21 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                 * UIDs to make sure there's nothing left there and warn if
                 * any is found.
                 */
-               for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
+               for (i = 0; i < mvm->max_scans; i++) {
                        if (WARN_ONCE(mvm->scan_uid[i],
                                      "UMAC scan UID %d was not cleaned\n",
                                      mvm->scan_uid[i]))
                                mvm->scan_uid[i] = 0;
                }
        } else {
-               switch (mvm->scan_status) {
-               case IWL_MVM_SCAN_NONE:
-                       break;
-               case IWL_MVM_SCAN_OS:
+               if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
                        ieee80211_scan_completed(mvm->hw, true);
-                       break;
-               case IWL_MVM_SCAN_SCHED:
-                       /*
-                        * Sched scan will be restarted by mac80211 in
-                        * restart_hw, so do not report if FW is about to be
-                        * restarted.
-                        */
-                       if (!mvm->restart_fw)
-                               ieee80211_sched_scan_stopped(mvm->hw);
-                       break;
-               }
+
+               /* Sched scan will be restarted by mac80211 in
+                * restart_hw, so do not report if FW is about to be
+                * restarted.
+                */
+               if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw)
+                       ieee80211_sched_scan_stopped(mvm->hw);
        }
 }
index ba615ad..80d07db 100644 (file)
@@ -70,7 +70,7 @@
 static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
 {
        struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
-       u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
+       u32 duration = tt->params.ct_kill_duration;
 
        if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
                return;
@@ -223,7 +223,7 @@ static void check_exit_ctkill(struct work_struct *work)
        tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
        mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
 
-       duration = tt->params->ct_kill_duration;
+       duration = tt->params.ct_kill_duration;
 
        mutex_lock(&mvm->mutex);
 
@@ -247,7 +247,7 @@ static void check_exit_ctkill(struct work_struct *work)
 
        IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
 
-       if (temp <= tt->params->ct_kill_exit) {
+       if (temp <= tt->params.ct_kill_exit) {
                mutex_unlock(&mvm->mutex);
                iwl_mvm_exit_ctkill(mvm);
                return;
@@ -325,7 +325,7 @@ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
 
 void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
 {
-       const struct iwl_tt_params *params = mvm->thermal_throttle.params;
+       struct iwl_tt_params *params = &mvm->thermal_throttle.params;
        struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
        s32 temperature = mvm->temperature;
        bool throttle_enable = false;
@@ -340,7 +340,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
        }
 
        if (params->support_ct_kill &&
-           temperature <= tt->params->ct_kill_exit) {
+           temperature <= params->ct_kill_exit) {
                iwl_mvm_exit_ctkill(mvm);
                return;
        }
@@ -400,7 +400,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
        }
 }
 
-static const struct iwl_tt_params iwl7000_tt_params = {
+static const struct iwl_tt_params iwl_mvm_default_tt_params = {
        .ct_kill_entry = 118,
        .ct_kill_exit = 96,
        .ct_kill_duration = 5,
@@ -422,38 +422,16 @@ static const struct iwl_tt_params iwl7000_tt_params = {
        .support_tx_backoff = true,
 };
 
-static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
-       .ct_kill_entry = 118,
-       .ct_kill_exit = 96,
-       .ct_kill_duration = 5,
-       .dynamic_smps_entry = 114,
-       .dynamic_smps_exit = 110,
-       .tx_protection_entry = 114,
-       .tx_protection_exit = 108,
-       .tx_backoff = {
-               {.temperature = 112, .backoff = 300},
-               {.temperature = 113, .backoff = 800},
-               {.temperature = 114, .backoff = 1500},
-               {.temperature = 115, .backoff = 3000},
-               {.temperature = 116, .backoff = 5000},
-               {.temperature = 117, .backoff = 10000},
-       },
-       .support_ct_kill = true,
-       .support_dynamic_smps = true,
-       .support_tx_protection = true,
-       .support_tx_backoff = true,
-};
-
 void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
 {
        struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
 
        IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
 
-       if (mvm->cfg->high_temp)
-               tt->params = &iwl7000_high_temp_tt_params;
+       if (mvm->cfg->thermal_params)
+               tt->params = *mvm->cfg->thermal_params;
        else
-               tt->params = &iwl7000_tt_params;
+               tt->params = iwl_mvm_default_tt_params;
 
        tt->throttle = false;
        tt->dynamic_smps = false;
index 2de8fbf..4526336 100644 (file)
@@ -5,8 +5,8 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,8 +31,8 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -101,14 +101,26 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
        trans_pcie->fw_mon_size = 0;
 }
 
-static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
+static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct page *page;
+       struct page *page = NULL;
        dma_addr_t phys;
-       u32 size;
+       u32 size = 0;
        u8 power;
 
+       if (!max_power) {
+               /* default max_power is maximum */
+               max_power = 26;
+       } else {
+               max_power += 11;
+       }
+
+       if (WARN(max_power > 26,
+                "External buffer size for monitor is too big %d, check the FW TLV\n",
+                max_power))
+               return;
+
        if (trans_pcie->fw_mon_page) {
                dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys,
                                           trans_pcie->fw_mon_size,
@@ -117,7 +129,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
        }
 
        phys = 0;
-       for (power = 26; power >= 11; power--) {
+       for (power = max_power; power >= 11; power--) {
                int order;
 
                size = BIT(power);
@@ -131,6 +143,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
                                    DMA_FROM_DEVICE);
                if (dma_mapping_error(trans->dev, phys)) {
                        __free_pages(page, order);
+                       page = NULL;
                        continue;
                }
                IWL_INFO(trans,
@@ -142,6 +155,12 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
        if (WARN_ON_ONCE(!page))
                return;
 
+       if (power != max_power)
+               IWL_ERR(trans,
+                       "Sorry - debug buffer is only %luK while you requested %luK\n",
+                       (unsigned long)BIT(power - 10),
+                       (unsigned long)BIT(max_power - 10));
+
        trans_pcie->fw_mon_page = page;
        trans_pcie->fw_mon_phys = phys;
        trans_pcie->fw_mon_size = size;
@@ -833,7 +852,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)
                 get_fw_dbg_mode_string(dest->monitor_mode));
 
        if (dest->monitor_mode == EXTERNAL_MODE)
-               iwl_pcie_alloc_fw_monitor(trans);
+               iwl_pcie_alloc_fw_monitor(trans, dest->size_power);
        else
                IWL_WARN(trans, "PCI should have external buffer debug\n");
 
@@ -907,7 +926,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        /* supported for 7000 only for the moment */
        if (iwlwifi_mod_params.fw_monitor &&
            trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
-               iwl_pcie_alloc_fw_monitor(trans);
+               iwl_pcie_alloc_fw_monitor(trans, 0);
 
                if (trans_pcie->fw_mon_size) {
                        iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
@@ -1020,7 +1039,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
        iwl_pcie_tx_start(trans, scd_addr);
 }
 
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill, was_hw_rfkill;
@@ -1115,7 +1134,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
 {
        if (iwl_op_mode_hw_rf_kill(trans->op_mode, state))
-               iwl_trans_pcie_stop_device(trans);
+               iwl_trans_pcie_stop_device(trans, true);
 }
 
 static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -1200,7 +1219,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
        return 0;
 }
 
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
 {
        bool hw_rfkill;
        int err;
@@ -2197,6 +2216,29 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans,
        return sizeof(**data) + fh_regs_len;
 }
 
+static u32
+iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,
+                                struct iwl_fw_error_dump_fw_mon *fw_mon_data,
+                                u32 monitor_len)
+{
+       u32 buf_size_in_dwords = (monitor_len >> 2);
+       u32 *buffer = (u32 *)fw_mon_data->data;
+       unsigned long flags;
+       u32 i;
+
+       if (!iwl_trans_grab_nic_access(trans, false, &flags))
+               return 0;
+
+       __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x1);
+       for (i = 0; i < buf_size_in_dwords; i++)
+               buffer[i] = __iwl_read_prph(trans, MON_DMARB_RD_DATA_ADDR);
+       __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x0);
+
+       iwl_trans_release_nic_access(trans, &flags);
+
+       return monitor_len;
+}
+
 static
 struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
 {
@@ -2249,7 +2291,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
                      trans->dbg_dest_tlv->end_shift;
 
                /* Make "end" point to the actual end */
-               if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 ||
+                   trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
                        end += (1 << trans->dbg_dest_tlv->end_shift);
                monitor_len = end - base;
                len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
@@ -2325,9 +2368,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
 
                len += sizeof(*data) + sizeof(*fw_mon_data);
                if (trans_pcie->fw_mon_page) {
-                       data->len = cpu_to_le32(trans_pcie->fw_mon_size +
-                                               sizeof(*fw_mon_data));
-
                        /*
                         * The firmware is now asserted, it won't write anything
                         * to the buffer. CPU can take ownership to fetch the
@@ -2342,10 +2382,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
                               page_address(trans_pcie->fw_mon_page),
                               trans_pcie->fw_mon_size);
 
-                       len += trans_pcie->fw_mon_size;
-               } else {
-                       /* If we are here then the buffer is internal */
-
+                       monitor_len = trans_pcie->fw_mon_size;
+               } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
                        /*
                         * Update pointers to reflect actual values after
                         * shifting
@@ -2354,10 +2392,18 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
                               trans->dbg_dest_tlv->base_shift;
                        iwl_trans_read_mem(trans, base, fw_mon_data->data,
                                           monitor_len / sizeof(u32));
-                       data->len = cpu_to_le32(sizeof(*fw_mon_data) +
-                                               monitor_len);
-                       len += monitor_len;
+               } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
+                       monitor_len =
+                               iwl_trans_pci_dump_marbh_monitor(trans,
+                                                                fw_mon_data,
+                                                                monitor_len);
+               } else {
+                       /* Didn't match anything - output no monitor data */
+                       monitor_len = 0;
                }
+
+               len += monitor_len;
+               data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data));
        }
 
        dump_data->len = len;