Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
authorKalle Valo <kvalo@codeaurora.org>
Tue, 6 Jan 2015 17:36:11 +0000 (19:36 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 6 Jan 2015 17:36:11 +0000 (19:36 +0200)
* more work on d0i3 power state
* enhancements to the firmware debugging infrastructure
* support for 2 concurrent channel contexts
* fixes / cleanups in the rate control
* general cleanups

38 files changed:
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/tt.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c

index 0b7f46f..de43dd7 100644 (file)
  *
  ******************************************************************************/
 
-/*
- * module name, copyright, version, etc.
- */
 #define DRV_DESCRIPTION        "Intel(R) Wireless WiFi Link AGN driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION     IWLWIFI_VERSION VD
-
-
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
@@ -1011,13 +997,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        if (priv->lib->bt_params)
                iwlagn_bt_setup_deferred_work(priv);
 
-       init_timer(&priv->statistics_periodic);
-       priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+       setup_timer(&priv->statistics_periodic, iwl_bg_statistics_periodic,
+                   (unsigned long)priv);
 
-       init_timer(&priv->ucode_trace);
-       priv->ucode_trace.data = (unsigned long)priv;
-       priv->ucode_trace.function = iwl_bg_ucode_trace;
+       setup_timer(&priv->ucode_trace, iwl_bg_ucode_trace,
+                   (unsigned long)priv);
 }
 
 void iwl_cancel_deferred_work(struct iwl_priv *priv)
index acb981a..c4736c8 100644 (file)
@@ -612,15 +612,10 @@ void iwl_tt_initialize(struct iwl_priv *priv)
        memset(tt, 0, sizeof(struct iwl_tt_mgmt));
 
        tt->state = IWL_TI_0;
-       init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
-       priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
-       priv->thermal_throttle.ct_kill_exit_tm.function =
-               iwl_tt_check_exit_ct_kill;
-       init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
-       priv->thermal_throttle.ct_kill_waiting_tm.data =
-               (unsigned long)priv;
-       priv->thermal_throttle.ct_kill_waiting_tm.function =
-               iwl_tt_ready_for_ct_kill;
+       setup_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+                   iwl_tt_check_exit_ct_kill, (unsigned long)priv);
+       setup_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+                   iwl_tt_ready_for_ct_kill, (unsigned long)priv);
        /* setup deferred ct kill work */
        INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
        INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
index e5be2d2..9e76799 100644 (file)
 #define IWL7265D_NVM_VERSION           0x0c11
 #define IWL7265_TX_POWER_VERSION       0xffff /* meaningless */
 
+/* DCCM offsets and lengths */
+#define IWL7000_DCCM_OFFSET            0x800000
+#define IWL7260_DCCM_LEN               0x14000
+#define IWL3160_DCCM_LEN               0x10000
+#define IWL7265_DCCM_LEN               0x17A00
+
 #define IWL7260_FW_PRE "iwlwifi-7260-"
 #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
 
@@ -138,7 +144,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .led_mode = IWL_LED_RF_STATE,                           \
        .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000,   \
        .non_shared_ant = ANT_A,                                \
-       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,    \
+       .dccm_offset = IWL7000_DCCM_OFFSET
 
 const struct iwl_cfg iwl7260_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7260",
@@ -149,6 +156,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = {
        .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
        .lp_xtal_workaround = true,
+       .dccm_len = IWL7260_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
@@ -161,6 +169,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
        .high_temp = true,
        .host_interrupt_operation_mode = true,
        .lp_xtal_workaround = true,
+       .dccm_len = IWL7260_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7260_2n_cfg = {
@@ -172,6 +181,7 @@ const struct iwl_cfg iwl7260_2n_cfg = {
        .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
        .lp_xtal_workaround = true,
+       .dccm_len = IWL7260_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7260_n_cfg = {
@@ -183,6 +193,7 @@ const struct iwl_cfg iwl7260_n_cfg = {
        .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
        .lp_xtal_workaround = true,
+       .dccm_len = IWL7260_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl3160_2ac_cfg = {
@@ -193,6 +204,7 @@ const struct iwl_cfg iwl3160_2ac_cfg = {
        .nvm_ver = IWL3160_NVM_VERSION,
        .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
+       .dccm_len = IWL3160_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl3160_2n_cfg = {
@@ -203,6 +215,7 @@ const struct iwl_cfg iwl3160_2n_cfg = {
        .nvm_ver = IWL3160_NVM_VERSION,
        .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
+       .dccm_len = IWL3160_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl3160_n_cfg = {
@@ -213,6 +226,7 @@ const struct iwl_cfg iwl3160_n_cfg = {
        .nvm_ver = IWL3160_NVM_VERSION,
        .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
        .host_interrupt_operation_mode = true,
+       .dccm_len = IWL3160_DCCM_LEN,
 };
 
 static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
@@ -240,6 +254,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
        .nvm_ver = IWL3165_NVM_VERSION,
        .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265_2ac_cfg = {
@@ -250,6 +265,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265_2n_cfg = {
@@ -260,6 +276,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265_n_cfg = {
@@ -270,6 +287,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265d_2ac_cfg = {
@@ -280,6 +298,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265d_2n_cfg = {
@@ -290,6 +309,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 const struct iwl_cfg iwl7265d_n_cfg = {
@@ -300,6 +320,7 @@ const struct iwl_cfg iwl7265d_n_cfg = {
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
        .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+       .dccm_len = IWL7265_DCCM_LEN,
 };
 
 MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
index bf0a95c..46e9c9a 100644 (file)
 #define IWL8000_NVM_VERSION            0x0a1d
 #define IWL8000_TX_POWER_VERSION       0xffff /* meaningless */
 
+/* Memory offsets and lengths */
+#define IWL8260_DCCM_OFFSET            0x800000
+#define IWL8260_DCCM_LEN               0x18000
+#define IWL8260_SMEM_OFFSET            0x400000
+#define IWL8260_SMEM_LEN               0x68000
+
 #define IWL8000_FW_PRE "iwlwifi-8000"
 #define IWL8000_MODULE_FIRMWARE(api) \
        IWL8000_FW_PRE "-" __stringify(api) ".ucode"
 
 #define NVM_HW_SECTION_NUM_FAMILY_8000         10
-#define DEFAULT_NVM_FILE_FAMILY_8000           "iwl_nvm_8000.bin"
+#define DEFAULT_NVM_FILE_FAMILY_8000A          "iwl_nvm_8000.bin"
+#define DEFAULT_NVM_FILE_FAMILY_8000           "iwl_nvm_8000B.bin"
 
 /* Max SDIO RX aggregation size of the ADDBA request/response */
 #define MAX_RX_AGG_SIZE_8260_SDIO      28
@@ -124,7 +131,11 @@ static const struct iwl_ht_params iwl8000_ht_params = {
        .led_mode = IWL_LED_RF_STATE,                           \
        .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000,   \
        .d0i3 = true,                                           \
-       .non_shared_ant = ANT_A
+       .non_shared_ant = ANT_A,                                \
+       .dccm_offset = IWL8260_DCCM_OFFSET,                     \
+       .dccm_len = IWL8260_DCCM_LEN,                           \
+       .smem_offset = IWL8260_SMEM_OFFSET,                     \
+       .smem_len = IWL8260_SMEM_LEN
 
 const struct iwl_cfg iwl8260_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 8260",
@@ -153,6 +164,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
        .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
+       .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A,
        .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
        .disable_dummy_notification = true,
        .max_ht_ampdu_exponent  = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
@@ -167,6 +179,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
        .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
+       .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A,
        .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
        .bt_shared_single_ant = true,
        .disable_dummy_notification = true,
index 3a4b9c7..fa0bc48 100644 (file)
@@ -261,6 +261,10 @@ struct iwl_pwr_tx_backoff {
  *     station can receive in HT
  * @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the
  *     station can receive in VHT
+ * @dccm_offset: offset from which DCCM begins
+ * @dccm_len: length of DCCM (including runtime stack CCM)
+ * @smem_offset: offset from which the SMEM begins
+ * @smem_len: the length of SMEM
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -298,11 +302,16 @@ struct iwl_cfg {
        const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
        bool no_power_up_nic_in_init;
        const char *default_nvm_file;
+       const char *default_nvm_file_8000A;
        unsigned int max_rx_agg_size;
        bool disable_dummy_notification;
        unsigned int max_tx_agg_size;
        unsigned int max_ht_ampdu_exponent;
        unsigned int max_vht_ampdu_exponent;
+       const u32 dccm_offset;
+       const u32 dccm_len;
+       const u32 smem_offset;
+       const u32 smem_len;
 };
 
 /*
@@ -370,7 +379,6 @@ extern const struct iwl_cfg iwl7265d_n_cfg;
 extern const struct iwl_cfg iwl8260_2n_cfg;
 extern const struct iwl_cfg iwl8260_2ac_cfg;
 extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
-extern const struct iwl_cfg iwl4265_2ac_sdio_cfg;
 extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
 #endif /* CONFIG_IWLMVM */
 
index aff63c3..7f40cf3 100644 (file)
 #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY     (0x00400000) /* PCI_OWN_SEM */
 #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
 #define CSR_HW_IF_CONFIG_REG_PREPARE             (0x08000000) /* WAKE_ME */
+#define CSR_HW_IF_CONFIG_REG_ENABLE_PME                  (0x10000000)
 #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE        (0x40000000) /* PERSISTENCE */
 
 #define CSR_MBOX_SET_REG_OS_ALIVE              BIT(5)
index 850b85a..e766dcd 100644 (file)
  *
  ******************************************************************************/
 
-/*
- * module name, copyright, version, etc.
- */
 #define DRV_DESCRIPTION        "Intel(R) Wireless WiFi driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION     IWLWIFI_VERSION VD
-
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
@@ -250,9 +237,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
        /*
         * Starting 8000B - FW name format has changed. This overwrites the
         * previous name and uses the new format.
-        *
-        * TODO:
-        * Once there is only one supported step for 8000 family - delete this!
         */
        if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
                char rev_step[2] = {
@@ -263,13 +247,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
                if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP)
                        rev_step[0] = 0;
 
-               /*
-                * If hw_rev wasn't set yet - default as B-step. If it IS A-step
-                * we'll reload that FW later instead.
-                */
-               if (drv->trans->hw_rev == 0)
-                       rev_step[0] = 'B';
-
                snprintf(drv->firmware_name, sizeof(drv->firmware_name),
                         "%s%s-%s.ucode", name_pre, rev_step, tag);
        }
@@ -926,6 +903,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                                            IWL_UCODE_REGULAR_USNIFFER,
                                            tlv_len);
                        break;
+               case IWL_UCODE_TLV_SDIO_ADMA_ADDR:
+                       if (tlv_len != sizeof(u32))
+                               goto invalid_tlv_len;
+                       drv->fw.sdio_adma_addr =
+                               le32_to_cpup((__le32 *)tlv_data);
+                       break;
                default:
                        IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
                        break;
@@ -1082,7 +1065,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        u32 api_ver;
        int i;
        bool load_module = false;
-       u32 hw_rev = drv->trans->hw_rev;
 
        fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH;
        fw->ucode_capa.standard_phy_calibration_size =
@@ -1275,50 +1257,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                op->name, err);
 #endif
        }
-
-       /*
-        * We may have loaded the wrong FW file in 8000 HW family if it is an
-        * A-step card, and if drv->trans->hw_rev wasn't properly read when
-        * the FW file had been loaded. (This might happen in SDIO.) In such a
-        * case - unload and reload the correct file.
-        *
-        * TODO:
-        * Once there is only one supported step for 8000 family - delete this!
-        */
-       if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
-           CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP &&
-           drv->trans->hw_rev != hw_rev) {
-               char firmware_name[32];
-
-               /* Free previous FW resources */
-               if (drv->op_mode)
-                       _iwl_op_mode_stop(drv);
-               iwl_dealloc_ucode(drv);
-
-               /* Build name of correct-step FW */
-               snprintf(firmware_name, sizeof(firmware_name),
-                        strrchr(drv->firmware_name, '-'));
-               snprintf(drv->firmware_name, sizeof(drv->firmware_name),
-                        "%s%s", drv->cfg->fw_name_pre, firmware_name);
-
-               /* Clear data before loading correct FW */
-               list_del(&drv->list);
-
-               /* Request correct FW file this time */
-               IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n",
-                              drv->firmware_name);
-               err = request_firmware(&ucode_raw, drv->firmware_name,
-                                      drv->trans->dev);
-               if (err) {
-                       IWL_ERR(drv, "Failed swapping FW!\n");
-                       goto out_unbind;
-               }
-
-               /* Redo callback function - this time with right FW */
-               iwl_req_fw_callback(ucode_raw, context);
-       }
-
-       kfree(pieces);
        return;
 
  try_again:
@@ -1430,6 +1368,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
        .bt_coex_active = true,
        .power_level = IWL_POWER_INDEX_1,
        .wd_disable = true,
+       .d0i3_disable = true,
 #ifndef CONFIG_IWLWIFI_UAPSD
        .uapsd_disable = true,
 #endif /* CONFIG_IWLWIFI_UAPSD */
@@ -1492,7 +1431,7 @@ static int __init iwl_drv_init(void)
        for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
                INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
 
-       pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+       pr_info(DRV_DESCRIPTION "\n");
        pr_info(DRV_COPYRIGHT "\n");
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1546,6 +1485,10 @@ MODULE_PARM_DESC(wd_disable,
 module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
 MODULE_PARM_DESC(nvm_file, "NVM file name");
 
+module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
+                  bool, S_IRUGO);
+MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
+
 module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
                   bool, S_IRUGO);
 #ifdef CONFIG_IWLWIFI_UAPSD
index be4f897..adf522c 100644 (file)
@@ -68,7 +68,6 @@
 
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
-#define IWLWIFI_VERSION "in-tree:"
 #define DRV_COPYRIGHT  "Copyright(c) 2003- 2014 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
index 20a8a64..ec115bd 100644 (file)
@@ -71,7 +71,6 @@
 
 /**
  * enum iwl_fw_error_dump_type - types of data in the dump file
- * @IWL_FW_ERROR_DUMP_SRAM:
  * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0
  * @IWL_FW_ERROR_DUMP_RXF:
  * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
  * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several
  *     sections like this in a single file.
  * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers
+ * @IWL_FW_ERROR_DUMP_MEM: chunk of memory
  */
 enum iwl_fw_error_dump_type {
-       IWL_FW_ERROR_DUMP_SRAM = 0,
+       /* 0 is deprecated */
        IWL_FW_ERROR_DUMP_CSR = 1,
        IWL_FW_ERROR_DUMP_RXF = 2,
        IWL_FW_ERROR_DUMP_TXCMD = 3,
@@ -93,6 +93,7 @@ enum iwl_fw_error_dump_type {
        IWL_FW_ERROR_DUMP_PRPH = 6,
        IWL_FW_ERROR_DUMP_TXF = 7,
        IWL_FW_ERROR_DUMP_FH_REGS = 8,
+       IWL_FW_ERROR_DUMP_MEM = 9,
 
        IWL_FW_ERROR_DUMP_MAX,
 };
@@ -180,6 +181,23 @@ struct iwl_fw_error_dump_prph {
        __le32 data[];
 };
 
+enum iwl_fw_error_dump_mem_type {
+       IWL_FW_ERROR_DUMP_MEM_SRAM,
+       IWL_FW_ERROR_DUMP_MEM_SMEM,
+};
+
+/**
+ * struct iwl_fw_error_dump_mem - chunk of memory
+ * @type: %enum iwl_fw_error_dump_mem_type
+ * @offset: the offset from which the memory was read
+ * @data: the content of the memory
+ */
+struct iwl_fw_error_dump_mem {
+       __le32 type;
+       __le32 offset;
+       u8 data[];
+};
+
 /**
  * iwl_fw_error_next_data - advance fw error dump data pointer
  * @data: previous data block
index f2a047f..752c72b 100644 (file)
@@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_ENABLED_CAPABILITIES      = 30,
        IWL_UCODE_TLV_N_SCAN_CHANNELS           = 31,
        IWL_UCODE_TLV_SEC_RT_USNIFFER   = 34,
+       IWL_UCODE_TLV_SDIO_ADMA_ADDR    = 35,
        IWL_UCODE_TLV_FW_DBG_DEST       = 38,
        IWL_UCODE_TLV_FW_DBG_CONF       = 39,
 };
index e6dc3b8..ffd785c 100644 (file)
@@ -152,6 +152,8 @@ struct iwl_fw_cscheme_list {
  * @mvm_fw: indicates this is MVM firmware
  * @cipher_scheme: optional external cipher scheme.
  * @human_readable: human readable version
+ * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
+ *     we get the ALIVE from the uCode
  * @dbg_dest_tlv: points to the destination TLV for debug
  * @dbg_conf_tlv: array of pointers to configuration TLVs for debug
  * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries
@@ -181,6 +183,8 @@ struct iwl_fw {
        struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
        u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
 
+       u32 sdio_adma_addr;
+
        struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
        struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
        size_t dbg_conf_tlv_len[FW_DBG_MAX];
index 71507cf..2a8cf4b 100644 (file)
@@ -103,6 +103,7 @@ enum iwl_disable_11n {
  * @power_level: power level, default = 1
  * @debug_level: levels are IWL_DL_*
  * @ant_coupling: antenna coupling in dB, default = 0
+ * @d0i3_disable: disable d0i3, default = 1,
  * @fw_monitor: allow to use firmware monitor
  */
 struct iwl_mod_params {
@@ -121,6 +122,7 @@ struct iwl_mod_params {
        int ant_coupling;
        char *nvm_file;
        bool uapsd_disable;
+       bool d0i3_disable;
        bool fw_monitor;
 };
 
index 06e02fc..c74f1a4 100644 (file)
@@ -468,6 +468,8 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
        data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
        data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
        data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
+       data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg);
+       data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
 }
 
 static void iwl_set_hw_address(const struct iwl_cfg *cfg,
@@ -592,6 +594,10 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 
        radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
        iwl_set_radio_cfg(cfg, data, radio_cfg);
+       if (data->valid_tx_ant)
+               tx_chains &= data->valid_tx_ant;
+       if (data->valid_rx_ant)
+               rx_chains &= data->valid_rx_ant;
 
        sku = iwl_get_sku(cfg, nvm_sw);
        data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
index 2df51ea..83ab423 100644 (file)
@@ -99,6 +99,7 @@
 
 #define APMG_PCIDEV_STT_VAL_PERSIST_DIS        (0x00000200)
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+#define APMG_PCIDEV_STT_VAL_WAKE_ME    (0x00004000)
 
 #define APMG_RTC_INT_STT_RFKILL                (0x10000000)
 
@@ -365,11 +366,15 @@ enum secure_load_status_reg {
 #define RXF_FIFO_RD_FENCE_ADDR         (0xa00c0c)
 
 /* FW monitor */
+#define MON_BUFF_SAMPLE_CTL            (0xa03c00)
 #define MON_BUFF_BASE_ADDR             (0xa03c3c)
 #define MON_BUFF_END_ADDR              (0xa03c40)
 #define MON_BUFF_WRPTR                 (0xa03c44)
 #define MON_BUFF_CYCLE_CNT             (0xa03c48)
 
+#define DBGC_IN_SAMPLE                 (0xa03c00)
+#define DBGC_OUT_CTRL                  (0xa03c0c)
+
 /* FW chicken bits */
 #define LMPM_CHICK                     0xA01FF8
 enum {
index 028408a..84d8477 100644 (file)
@@ -382,6 +382,8 @@ enum iwl_trans_status {
  *     are considered stuck and will trigger device restart
  * @command_names: array of command names, must be 256 entries
  *     (one for each command); for debugging only
+ * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
+ *     we get the ALIVE from the uCode
  */
 struct iwl_trans_config {
        struct iwl_op_mode *op_mode;
@@ -396,6 +398,8 @@ struct iwl_trans_config {
        bool scd_set_active;
        unsigned int queue_watchdog_timeout;
        const char *const *command_names;
+
+       u32 sdio_adma_addr;
 };
 
 struct iwl_trans_dump_data {
@@ -551,6 +555,21 @@ enum iwl_trans_state {
        IWL_TRANS_FW_ALIVE      = 1,
 };
 
+/**
+ * enum iwl_d0i3_mode - d0i3 mode
+ *
+ * @IWL_D0I3_MODE_OFF - d0i3 is disabled
+ * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle
+ *     (e.g. no active references)
+ * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend
+ *     (in case of 'any' trigger)
+ */
+enum iwl_d0i3_mode {
+       IWL_D0I3_MODE_OFF = 0,
+       IWL_D0I3_MODE_ON_IDLE,
+       IWL_D0I3_MODE_ON_SUSPEND,
+};
+
 /**
  * struct iwl_trans - transport common data
  *
@@ -612,6 +631,8 @@ struct iwl_trans {
        const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
        u8 dbg_dest_reg_num;
 
+       enum iwl_d0i3_mode d0i3_mode;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __aligned(sizeof(void *));
index a3bfda4..d2fd48c 100644 (file)
@@ -989,7 +989,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
 static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
                                   struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data *data = _data;
        struct iwl_mvm *mvm = data->mvm;
 
@@ -1025,7 +1025,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
 void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                           enum ieee80211_rssi_event rssi_event)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data data = {
                .mvm = mvm,
        };
index b3210cf..973f288 100644 (file)
@@ -1034,7 +1034,7 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,
 static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
                                     struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data *data = _data;
        struct iwl_mvm *mvm = data->mvm;
 
@@ -1070,7 +1070,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
 void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                               enum ieee80211_rssi_event rssi_event)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data data = {
                .mvm = mvm,
        };
index 3bd9347..7cd1de8 100644 (file)
 #define IWL_MVM_QUOTA_THRESHOLD                        8
 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0
 #define IWL_MVM_RS_DISABLE_MIMO                        0
+#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE    1
+#define IWL_MVM_RS_LEGACY_RETRIES_PER_RATE      1
+#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE      2
+#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW   1
+#define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES       3
+#define IWL_MVM_RS_INITIAL_SISO_NUM_RATES       3
+#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES     16
+#define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES   16
+#define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES     3
+#define IWL_MVM_RS_SECONDARY_SISO_RETRIES       1
+#define IWL_MVM_RS_RATE_MIN_FAILURE_TH         3
+#define IWL_MVM_RS_RATE_MIN_SUCCESS_TH         8
+#define IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT      5       /* Seconds */
+#define IWL_MVM_RS_IDLE_TIMEOUT                        5       /* Seconds */
+#define IWL_MVM_RS_MISSED_RATE_MAX             15
+#define IWL_MVM_RS_LEGACY_FAILURE_LIMIT                160
+#define IWL_MVM_RS_LEGACY_SUCCESS_LIMIT                480
+#define IWL_MVM_RS_LEGACY_TABLE_COUNT          160
+#define IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT    400
+#define IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT    4500
+#define IWL_MVM_RS_NON_LEGACY_TABLE_COUNT      1500
+#define IWL_MVM_RS_SR_FORCE_DECREASE           15      /* percent */
+#define IWL_MVM_RS_SR_NO_DECREASE              85      /* percent */
+#define IWL_MVM_RS_AGG_TIME_LIMIT              4000    /* 4 msecs. valid 100-8000 */
+#define IWL_MVM_RS_AGG_DISABLE_START           3
+#define IWL_MVM_RS_TPC_SR_FORCE_INCREASE       75      /* percent */
+#define IWL_MVM_RS_TPC_SR_NO_INCREASE          85      /* percent */
+#define IWL_MVM_RS_TPC_TX_POWER_STEP           3
 
 #endif /* __MVM_CONSTANTS_H */
index 744de26..14e8fd6 100644 (file)
@@ -793,7 +793,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
                          struct ieee80211_sta *ap_sta)
 {
        int ret;
-       struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+       struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
 
        /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */
 
@@ -1137,12 +1137,43 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        return ret;
 }
 
+static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm)
+{
+       struct iwl_notification_wait wait_d3;
+       static const u8 d3_notif[] = { D3_CONFIG_CMD };
+       int ret;
+
+       iwl_init_notification_wait(&mvm->notif_wait, &wait_d3,
+                                  d3_notif, ARRAY_SIZE(d3_notif),
+                                  NULL, NULL);
+
+       ret = iwl_mvm_enter_d0i3(mvm->hw->priv);
+       if (ret)
+               goto remove_notif;
+
+       ret = iwl_wait_notification(&mvm->notif_wait, &wait_d3, HZ);
+       WARN_ON_ONCE(ret);
+       return ret;
+
+remove_notif:
+       iwl_remove_notification(&mvm->notif_wait, &wait_d3);
+       return ret;
+}
+
 int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 
        iwl_trans_suspend(mvm->trans);
-       if (iwl_mvm_is_d0i3_supported(mvm)) {
+       if (wowlan->any) {
+               /* 'any' trigger means d0i3 usage */
+               if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+                       int ret = iwl_mvm_enter_d0i3_sync(mvm);
+
+                       if (ret)
+                               return ret;
+               }
+
                mutex_lock(&mvm->d0i3_suspend_mutex);
                __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
                mutex_unlock(&mvm->d0i3_suspend_mutex);
@@ -1626,7 +1657,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
        if (IS_ERR_OR_NULL(ap_sta))
                goto out_free;
 
-       mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+       mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
        for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
                u16 seq = status.qos_seq_ctr[i];
                /* firmware stores last-used value, we store next value */
@@ -1876,8 +1907,20 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
 
        iwl_trans_resume(mvm->trans);
 
-       if (iwl_mvm_is_d0i3_supported(mvm))
+       if (mvm->hw->wiphy->wowlan_config->any) {
+               /* 'any' trigger means d0i3 usage */
+               if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+                       int ret = iwl_mvm_exit_d0i3(hw->priv);
+
+                       if (ret)
+                               return ret;
+                       /*
+                        * d0i3 exit will be deferred until reconfig_complete.
+                        * make sure there we are out of d0i3.
+                        */
+               }
                return 0;
+       }
 
        return __iwl_mvm_resume(mvm, false);
 }
index 9aa2311..8dc3ca9 100644 (file)
@@ -268,7 +268,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
                sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
                                                lockdep_is_held(&mvm->mutex));
                if (!IS_ERR_OR_NULL(sta)) {
-                       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+                       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
                        pos += scnprintf(buf+pos, bufsz-pos,
                                         "ap_sta_id %d - reduced Tx power %d\n",
index 33bf915..a1b276c 100644 (file)
@@ -933,7 +933,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
                return -EINVAL;
        if (scan_rx_ant > ANT_ABC)
                return -EINVAL;
-       if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
+       if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm)))
                return -EINVAL;
 
        if (mvm->scan_rx_ant != scan_rx_ant) {
@@ -945,6 +945,56 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
        return count;
 }
 
+static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       enum iwl_fw_dbg_conf conf;
+       char buf[8];
+       const size_t bufsz = sizeof(buf);
+       int pos = 0;
+
+       mutex_lock(&mvm->mutex);
+       conf = mvm->fw_dbg_conf;
+       mutex_unlock(&mvm->mutex);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
+                                          char *buf, size_t count,
+                                          loff_t *ppos)
+{
+       int ret, conf_id;
+
+       ret = kstrtoint(buf, 0, &conf_id);
+       if (ret)
+               return ret;
+
+       if (WARN_ON(conf_id >= FW_DBG_MAX))
+               return -EINVAL;
+
+       mutex_lock(&mvm->mutex);
+       ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
+                                             char *buf, size_t count,
+                                             loff_t *ppos)
+{
+       mutex_lock(&mvm->mutex);
+       iwl_mvm_fw_dbg_collect(mvm);
+       mutex_unlock(&mvm->mutex);
+
+       return count;
+}
+
 #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@@ -1459,6 +1509,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
 MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1500,6 +1552,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                             S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
index 1f2acf4..2d1a81c 100644 (file)
@@ -653,8 +653,11 @@ enum iwl_scan_channel_flags {
 };
 
 /* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
- * @flags: enum iwl_scan_channel_flgs
- * @non_ebs_ratio: how many regular scan iteration before EBS
+ * @flags: enum iwl_scan_channel_flags
+ * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is
+ *     involved.
+ *     1 - EBS is disabled.
+ *     2 - every second scan will be full scan(and so on).
  */
 struct iwl_scan_channel_opt {
        __le16 flags;
index d0fa6e9..534ee31 100644 (file)
@@ -70,6 +70,7 @@
 #include "iwl-debug.h"
 #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
 #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-prph.h"
 #include "iwl-eeprom-parse.h"
 
 #include "mvm.h"
@@ -269,7 +270,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
        enum iwl_ucode_type ucode_type = mvm->cur_ucode;
 
        /* Set parameters */
-       phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);
+       phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm));
        phy_cfg_cmd.calib_control.event_trigger =
                mvm->fw->default_calib[ucode_type].event_trigger;
        phy_cfg_cmd.calib_control.flow_trigger =
@@ -346,7 +347,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
        mvm->calibrating = true;
 
        /* Send TX valid antennas before triggering calibrations */
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
@@ -399,8 +400,26 @@ out:
        return ret;
 }
 
-static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm,
-                                    enum iwl_fw_dbg_conf conf_id)
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+{
+       lockdep_assert_held(&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);
+               iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+       }
+
+       iwl_mvm_fw_error_dump(mvm);
+
+       /* start recording again */
+       WARN_ON_ONCE(mvm->fw->dbg_dest_tlv &&
+                    iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+}
+
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
 {
        u8 *ptr;
        int ret;
@@ -489,7 +508,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        mvm->fw_dbg_conf = FW_DBG_INVALID;
        iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM);
 
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
@@ -584,7 +603,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
                goto error;
        }
 
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
index f6d86cc..7196b4d 100644 (file)
@@ -975,7 +975,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
        beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
 
        mvm->mgmt_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+               iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
                                     mvm->mgmt_last_antenna_idx);
 
        beacon_cmd.tx.rate_n_flags =
index e880f9d..3756c03 100644 (file)
@@ -85,6 +85,7 @@
 #include "testmode.h"
 #include "iwl-fw-error-dump.h"
 #include "iwl-prph.h"
+#include "iwl-csr.h"
 
 static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
        {
@@ -105,7 +106,7 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
 
 static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
        {
-               .num_different_channels = 1,
+               .num_different_channels = 2,
                .max_interfaces = 3,
                .limits = iwl_mvm_limits,
                .n_limits = ARRAY_SIZE(iwl_mvm_limits),
@@ -377,6 +378,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 
        hw->wiphy->max_remain_on_channel_duration = 10000;
        hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+       /* we can compensate an offset of up to 3 channels = 15 MHz */
+       hw->wiphy->max_adj_channel_rssi_comp = 3 * 5;
 
        /* Extract MAC address */
        memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
@@ -459,15 +462,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
            device_can_wakeup(mvm->trans->dev)) {
                mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
                hw->wiphy->wowlan = &mvm->wowlan;
-       } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+       }
+
+       if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
            mvm->trans->ops->d3_suspend &&
            mvm->trans->ops->d3_resume &&
            device_can_wakeup(mvm->trans->dev)) {
-               mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                   WIPHY_WOWLAN_DISCONNECT |
-                                   WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                   WIPHY_WOWLAN_RFKILL_RELEASE |
-                                   WIPHY_WOWLAN_NET_DETECT;
+               mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |
+                                    WIPHY_WOWLAN_DISCONNECT |
+                                    WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                    WIPHY_WOWLAN_RFKILL_RELEASE |
+                                    WIPHY_WOWLAN_NET_DETECT;
                if (!iwlwifi_mod_params.sw_crypto)
                        mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
                                             WIPHY_WOWLAN_GTK_REKEY_FAILURE |
@@ -766,22 +771,37 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        struct iwl_fw_error_dump_file *dump_file;
        struct iwl_fw_error_dump_data *dump_data;
        struct iwl_fw_error_dump_info *dump_info;
+       struct iwl_fw_error_dump_mem *dump_mem;
        struct iwl_mvm_dump_ptrs *fw_error_dump;
-       const struct fw_img *img;
        u32 sram_len, sram_ofs;
        u32 file_len, rxf_len;
        unsigned long flags;
        int reg_val;
+       u32 smem_len = mvm->cfg->smem_len;
 
        lockdep_assert_held(&mvm->mutex);
 
+       /* W/A for 8000 HW family A-step */
+       if (mvm->cfg->smem_len &&
+           mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
+           CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
+               smem_len = 0x38000;
+
        fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
        if (!fw_error_dump)
                return;
 
-       img = &mvm->fw->img[mvm->cur_ucode];
-       sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
-       sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+       /* SRAM - include stack CCM if driver knows the values for it */
+       if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) {
+               const struct fw_img *img;
+
+               img = &mvm->fw->img[mvm->cur_ucode];
+               sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
+               sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+       } else {
+               sram_ofs = mvm->cfg->dccm_offset;
+               sram_len = mvm->cfg->dccm_len;
+       }
 
        /* reading buffer size */
        reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR);
@@ -792,10 +812,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        file_len = sizeof(*dump_file) +
                   sizeof(*dump_data) * 3 +
-                  sram_len +
+                  sram_len + sizeof(*dump_mem) +
                   rxf_len +
                   sizeof(*dump_info);
 
+       /* Make room for the SMEM, if it exists */
+       if (smem_len)
+               file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
+
        dump_file = vzalloc(file_len);
        if (!dump_file) {
                kfree(fw_error_dump);
@@ -814,6 +838,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ?
                        cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) :
                        cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8);
+       dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev));
        memcpy(dump_info->fw_human_readable, mvm->fw->human_readable,
               sizeof(dump_info->fw_human_readable));
        strncpy(dump_info->dev_human_readable, mvm->cfg->name,
@@ -840,11 +865,25 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        }
 
        dump_data = iwl_fw_error_next_data(dump_data);
-       dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM);
-       dump_data->len = cpu_to_le32(sram_len);
-       iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data,
+       dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+       dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
+       dump_mem = (void *)dump_data->data;
+       dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
+       dump_mem->offset = cpu_to_le32(sram_ofs);
+       iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data,
                                 sram_len);
 
+       if (smem_len) {
+               dump_data = iwl_fw_error_next_data(dump_data);
+               dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+               dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
+               dump_mem = (void *)dump_data->data;
+               dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM);
+               dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset);
+               iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset,
+                                        dump_mem->data, smem_len);
+       }
+
        fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
        fw_error_dump->op_mode_len = file_len;
        if (fw_error_dump->trans_ptr)
@@ -864,6 +903,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status))
                iwl_mvm_fw_error_dump(mvm);
 
+       /* cleanup all stale references (scan, roc), but keep the
+        * ucode_down ref until reconfig is complete
+        */
+       iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
+
        iwl_trans_stop_device(mvm->trans);
 
        mvm->scan_status = IWL_MVM_SCAN_NONE;
@@ -893,10 +937,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 
        ieee80211_wake_queues(mvm->hw);
 
-       /* cleanup all stale references (scan, roc), but keep the
-        * ucode_down ref until reconfig is complete */
-       iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
-
        /* clear any stale d0i3 state */
        clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
 
@@ -933,6 +973,19 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
 
+       /* Some hw restart cleanups must not hold the mutex */
+       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+               /*
+                * Make sure we are out of d0i3. This is needed
+                * to make sure the reference accounting is correct
+                * (and there is no stale d0i3_exit_work).
+                */
+               wait_event_timeout(mvm->d0i3_exit_waitq,
+                                  !test_bit(IWL_MVM_STATUS_IN_D0I3,
+                                            &mvm->status),
+                                  HZ);
+       }
+
        mutex_lock(&mvm->mutex);
        ret = __iwl_mvm_mac_start(mvm);
        mutex_unlock(&mvm->mutex);
@@ -982,6 +1035,13 @@ static void iwl_mvm_resume_complete(struct iwl_mvm *mvm)
                IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n");
                _iwl_mvm_exit_d0i3(mvm);
        }
+
+       if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND)
+               if (!wait_event_timeout(mvm->d0i3_exit_waitq,
+                                       !test_bit(IWL_MVM_STATUS_IN_D0I3,
+                                                 &mvm->status),
+                                       HZ))
+                       WARN_ONCE(1, "D0i3 exit on resume timed out\n");
 }
 
 static void
@@ -2088,7 +2148,7 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
                                       struct ieee80211_sta *sta)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
        /*
         * This is called before mac80211 does RCU synchronisation,
@@ -3103,7 +3163,7 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
                           bool set)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
        if (!mvm_sta || !mvm_sta->vif) {
                IWL_ERR(mvm, "Station is not associated to a vif\n");
index d24660f..b2100b4 100644 (file)
@@ -850,6 +850,8 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id)
 static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
 {
        return mvm->trans->cfg->d0i3 &&
+              mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF &&
+              !iwlwifi_mod_params.d0i3_disable &&
               (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
 }
 
@@ -937,6 +939,33 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
 int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
 int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
 
+static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm)
+{
+       return mvm->nvm_data && mvm->nvm_data->valid_tx_ant ?
+              mvm->fw->valid_tx_ant & mvm->nvm_data->valid_tx_ant :
+              mvm->fw->valid_tx_ant;
+}
+
+static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm)
+{
+       return mvm->nvm_data && mvm->nvm_data->valid_rx_ant ?
+              mvm->fw->valid_rx_ant & mvm->nvm_data->valid_rx_ant :
+              mvm->fw->valid_rx_ant;
+}
+
+static inline u32 iwl_mvm_get_phy_config(struct iwl_mvm *mvm)
+{
+       u32 phy_config = ~(FW_PHY_CFG_TX_CHAIN |
+                          FW_PHY_CFG_RX_CHAIN);
+       u32 valid_rx_ant = iwl_mvm_get_valid_rx_ant(mvm);
+       u32 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
+
+       phy_config |= valid_tx_ant << FW_PHY_CFG_TX_CHAIN_POS |
+                     valid_rx_ant << FW_PHY_CFG_RX_CHAIN_POS;
+
+       return mvm->fw->phy_config & phy_config;
+}
+
 int iwl_mvm_up(struct iwl_mvm *mvm);
 int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
 
@@ -1159,6 +1188,8 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
 int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
 bool iwl_mvm_ref_taken(struct iwl_mvm *mvm);
 void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
+int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode);
+int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode);
 int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
 
 /* BT Coex */
@@ -1344,4 +1375,7 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
 
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id);
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm);
+
 #endif /* __IWL_MVM_H__ */
index 97dfba5..239f033 100644 (file)
 #include "time-event.h"
 #include "iwl-fw-error-dump.h"
 
-/*
- * module name, copyright, version, etc.
- */
 #define DRV_DESCRIPTION        "The new Intel(R) wireless AGN driver for Linux"
-
-#define DRV_VERSION     IWLWIFI_VERSION
-
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
@@ -146,13 +139,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
        u32 reg_val = 0;
+       u32 phy_config = iwl_mvm_get_phy_config(mvm);
 
-       radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >>
-                         FW_PHY_CFG_RADIO_TYPE_POS;
-       radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >>
-                         FW_PHY_CFG_RADIO_STEP_POS;
-       radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >>
-                         FW_PHY_CFG_RADIO_DASH_POS;
+       radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >>
+                        FW_PHY_CFG_RADIO_TYPE_POS;
+       radio_cfg_step = (phy_config & FW_PHY_CFG_RADIO_STEP) >>
+                        FW_PHY_CFG_RADIO_STEP_POS;
+       radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >>
+                        FW_PHY_CFG_RADIO_DASH_POS;
 
        /* SKU control */
        reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
@@ -487,6 +481,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
        trans_cfg.scd_set_active = true;
 
+       trans_cfg.sdio_adma_addr = fw->sdio_adma_addr;
+
        snprintf(mvm->hw->wiphy->fw_version,
                 sizeof(mvm->hw->wiphy->fw_version),
                 "%s", fw->fw_version);
@@ -517,10 +513,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        min_backoff = calc_min_backoff(trans, cfg);
        iwl_mvm_tt_initialize(mvm, min_backoff);
        /* set the nvm_file_name according to priority */
-       if (iwlwifi_mod_params.nvm_file)
+       if (iwlwifi_mod_params.nvm_file) {
                mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
-       else
-               mvm->nvm_file_name = mvm->cfg->default_nvm_file;
+       } else {
+               if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) &&
+                   (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
+                       mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A;
+               else
+                       mvm->nvm_file_name = mvm->cfg->default_nvm_file;
+       }
 
        if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name,
                 "not allowing power-up and not having nvm_file\n"))
@@ -1031,7 +1032,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
 out:
        rcu_read_unlock();
 }
-static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
+
+int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE;
@@ -1047,6 +1049,7 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
        };
        struct iwl_d3_manager_config d3_cfg_cmd = {
                .min_sleep_time = cpu_to_le32(1000),
+               .wakeup_flags = cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR),
        };
 
        IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n");
@@ -1146,7 +1149,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
 
        if (mvm->d0i3_offloading && qos_seq) {
                /* update qos seq numbers if offloading was enabled */
-               mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+               mvm_ap_sta = iwl_mvm_sta_from_mac80211(sta);
                for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
                        u16 seq = le16_to_cpu(qos_seq[i]);
                        /* firmware stores last-used one, we store next one */
@@ -1245,7 +1248,7 @@ out:
        return ret;
 }
 
-static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
+int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
index 1c0d4a4..540c36b 100644 (file)
@@ -176,7 +176,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
        cmd->rxchain_info |= cpu_to_le32(active_cnt <<
                                         PHY_RX_CHAIN_MIMO_CNT_POS);
 
-       cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant);
+       cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
 }
 
 /*
index 30ceb67..7ba6e5d 100644 (file)
 
 #define RS_NAME "iwl-mvm-rs"
 
-#define NUM_TRY_BEFORE_ANT_TOGGLE       1
-#define RS_LEGACY_RETRIES_PER_RATE      1
-#define RS_HT_VHT_RETRIES_PER_RATE      2
-#define RS_HT_VHT_RETRIES_PER_RATE_TW   1
-#define RS_INITIAL_MIMO_NUM_RATES       3
-#define RS_INITIAL_SISO_NUM_RATES       3
-#define RS_INITIAL_LEGACY_NUM_RATES     LINK_QUAL_MAX_RETRY_NUM
-#define RS_SECONDARY_LEGACY_NUM_RATES   LINK_QUAL_MAX_RETRY_NUM
-#define RS_SECONDARY_SISO_NUM_RATES     3
-#define RS_SECONDARY_SISO_RETRIES       1
-
 #define IWL_RATE_MAX_WINDOW            62      /* # tx in history window */
-#define IWL_RATE_MIN_FAILURE_TH                3       /* min failures to calc tpt */
-#define IWL_RATE_MIN_SUCCESS_TH                8       /* min successes to calc tpt */
 
-/* max allowed rate miss before sync LQ cmd */
-#define IWL_MISSED_RATE_MAX            15
-#define RS_STAY_IN_COLUMN_TIMEOUT       (5*HZ)
-#define RS_IDLE_TIMEOUT                 (5*HZ)
+/* Calculations of success ratio are done in fixed point where 12800 is 100%.
+ * Use this macro when dealing with thresholds consts set as a percentage
+ */
+#define RS_PERCENT(x) (128 * x)
 
 static u8 rs_ht_to_legacy[] = {
        [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX,
@@ -173,7 +160,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (sta->smps_mode == IEEE80211_SMPS_STATIC)
                return false;
 
-       if (num_of_ant(mvm->fw->valid_tx_ant) < 2)
+       if (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) < 2)
                return false;
 
        if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -613,7 +600,8 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
  * at this rate.  window->data contains the bitmask of successful
  * packets.
  */
-static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+static int _rs_collect_tx_data(struct iwl_mvm *mvm,
+                              struct iwl_scale_tbl_info *tbl,
                               int scale_index, int attempts, int successes,
                               struct iwl_rate_scale_data *window)
 {
@@ -668,8 +656,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
        fail_count = window->counter - window->success_counter;
 
        /* Calculate average throughput, if we have enough history. */
-       if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
-           (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+       if ((fail_count >= IWL_MVM_RS_RATE_MIN_FAILURE_TH) ||
+           (window->success_counter >= IWL_MVM_RS_RATE_MIN_SUCCESS_TH))
                window->average_tpt = (window->success_ratio * tpt + 64) / 128;
        else
                window->average_tpt = IWL_INVALID_VALUE;
@@ -677,7 +665,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
        return 0;
 }
 
-static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
+static int rs_collect_tx_data(struct iwl_mvm *mvm,
+                             struct iwl_lq_sta *lq_sta,
                              struct iwl_scale_tbl_info *tbl,
                              int scale_index, int attempts, int successes,
                              u8 reduced_txp)
@@ -698,7 +687,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
        /* Select window for current tx bit rate */
        window = &(tbl->win[scale_index]);
 
-       ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+       ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
                                  window);
        if (ret)
                return ret;
@@ -707,7 +696,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
                return -EINVAL;
 
        window = &tbl->tpc_win[reduced_txp];
-       return _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+       return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
                                   window);
 }
 
@@ -1004,7 +993,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
        }
 
        if (num_of_ant(rate->ant) > 1)
-               rate->ant = first_antenna(mvm->fw->valid_tx_ant);
+               rate->ant = first_antenna(iwl_mvm_get_valid_tx_ant(mvm));
 
        /* Relevant in both switching to SISO or Legacy */
        rate->sgi = false;
@@ -1125,7 +1114,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        }
 
        if (time_after(jiffies,
-                      (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) {
+                      (unsigned long)(lq_sta->last_tx +
+                                      (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
                int t;
 
                IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
@@ -1158,7 +1148,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                 * ... driver.
                 */
                lq_sta->missed_rate_counter++;
-               if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
+               if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
                        lq_sta->missed_rate_counter = 0;
                        IWL_DEBUG_RATE(mvm,
                                       "Too many rates mismatch. Send sync LQ. rs_state %d\n",
@@ -1213,7 +1203,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
                ucode_rate = le32_to_cpu(table->rs_table[0]);
                rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
-               rs_collect_tx_data(lq_sta, curr_tbl, rate.index,
+               rs_collect_tx_data(mvm, lq_sta, curr_tbl, rate.index,
                                   info->status.ampdu_len,
                                   info->status.ampdu_ack_len,
                                   reduced_txp);
@@ -1249,7 +1239,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                        else
                                continue;
 
-                       rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1,
+                       rs_collect_tx_data(mvm, lq_sta, tmp_tbl, rate.index, 1,
                                           i < retries ? 0 : legacy_success,
                                           reduced_txp);
                }
@@ -1303,13 +1293,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
        IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n");
        lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN;
        if (is_legacy) {
-               lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
-               lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
-               lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+               lq_sta->table_count_limit = IWL_MVM_RS_LEGACY_TABLE_COUNT;
+               lq_sta->max_failure_limit = IWL_MVM_RS_LEGACY_FAILURE_LIMIT;
+               lq_sta->max_success_limit = IWL_MVM_RS_LEGACY_SUCCESS_LIMIT;
        } else {
-               lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
-               lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
-               lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+               lq_sta->table_count_limit = IWL_MVM_RS_NON_LEGACY_TABLE_COUNT;
+               lq_sta->max_failure_limit = IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT;
+               lq_sta->max_success_limit = IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT;
        }
        lq_sta->table_count = 0;
        lq_sta->total_failed = 0;
@@ -1318,6 +1308,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
        lq_sta->visited_columns = 0;
 }
 
+static inline int rs_get_max_rate_from_mask(unsigned long rate_mask)
+{
+       if (rate_mask)
+               return find_last_bit(&rate_mask, BITS_PER_LONG);
+       return IWL_RATE_INVALID;
+}
+
 static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta,
                                   const struct rs_tx_column *column)
 {
@@ -1420,7 +1417,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
        u32 target_tpt;
        int rate_idx;
 
-       if (success_ratio > RS_SR_NO_DECREASE) {
+       if (success_ratio > IWL_MVM_RS_SR_NO_DECREASE) {
                target_tpt = 100 * expected_current_tpt;
                IWL_DEBUG_RATE(mvm,
                               "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n",
@@ -1488,7 +1485,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
                        flush_interval_passed =
                                time_after(jiffies,
                                           (unsigned long)(lq_sta->flush_timer +
-                                               RS_STAY_IN_COLUMN_TIMEOUT));
+                                                          (IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT * HZ)));
 
                /*
                 * Check if we should allow search for new modulation mode.
@@ -1567,7 +1564,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
        const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
        const struct rs_tx_column *next_col;
        allow_column_func_t allow_func;
-       u8 valid_ants = mvm->fw->valid_tx_ant;
+       u8 valid_ants = iwl_mvm_get_valid_tx_ant(mvm);
        const u16 *expected_tpt_tbl;
        u16 tpt, max_expected_tpt;
 
@@ -1613,8 +1610,12 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
                        continue;
 
                max_rate = rs_get_max_allowed_rate(lq_sta, next_col);
-               if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID))
+               if (max_rate == IWL_RATE_INVALID) {
+                       IWL_DEBUG_RATE(mvm,
+                                      "Skip column %d: no rate is allowed in this column\n",
+                                      next_col_id);
                        continue;
+               }
 
                max_expected_tpt = expected_tpt_tbl[max_rate];
                if (tpt >= max_expected_tpt) {
@@ -1724,7 +1725,8 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
 {
        enum rs_action action = RS_ACTION_STAY;
 
-       if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
+       if ((sr <= RS_PERCENT(IWL_MVM_RS_SR_FORCE_DECREASE)) ||
+           (current_tpt == 0)) {
                IWL_DEBUG_RATE(mvm,
                               "Decrease rate because of low SR\n");
                return RS_ACTION_DOWNSCALE;
@@ -1783,7 +1785,7 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
 
 out:
        if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) {
-               if (sr >= RS_SR_NO_DECREASE) {
+               if (sr >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) {
                        IWL_DEBUG_RATE(mvm,
                                       "SR is above NO DECREASE. Avoid downscale\n");
                        action = RS_ACTION_STAY;
@@ -1825,11 +1827,11 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
                                int *weaker, int *stronger)
 {
-       *weaker = index + TPC_TX_POWER_STEP;
+       *weaker = index + IWL_MVM_RS_TPC_TX_POWER_STEP;
        if (*weaker > TPC_MAX_REDUCTION)
                *weaker = TPC_INVALID;
 
-       *stronger = index - TPC_TX_POWER_STEP;
+       *stronger = index - IWL_MVM_RS_TPC_TX_POWER_STEP;
        if (*stronger < 0)
                *stronger = TPC_INVALID;
 }
@@ -1885,7 +1887,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
        }
 
        /* Too many failures, increase txp */
-       if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) {
+       if (sr <= RS_PERCENT(IWL_MVM_RS_TPC_SR_FORCE_INCREASE) ||
+           current_tpt == 0) {
                IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n");
                return TPC_ACTION_NO_RESTIRCTION;
        }
@@ -1908,7 +1911,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
        }
 
        /* next, increase if needed */
-       if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) {
+       if (sr < RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) &&
+           strong != TPC_INVALID) {
                if (weak_tpt == IWL_INVALID_VALUE &&
                    strong_tpt != IWL_INVALID_VALUE &&
                    current_tpt < strong_tpt) {
@@ -1935,7 +1939,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm,
                           struct iwl_lq_sta *lq_sta,
                           struct iwl_scale_tbl_info *tbl)
 {
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct ieee80211_vif *vif = mvm_sta->vif;
        struct ieee80211_chanctx_conf *chanctx_conf;
        enum ieee80211_band band;
@@ -2044,7 +2048,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
        u16 high_low;
        s32 sr;
        u8 prev_agg = lq_sta->is_agg;
-       struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_tid_data *tid_data;
        struct rs_rate *rate;
 
@@ -2106,8 +2110,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
         * in current association (use new rate found above).
         */
        fail_count = window->counter - window->success_counter;
-       if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
-           (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+       if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) &&
+           (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) {
                IWL_DEBUG_RATE(mvm,
                               "(%s: %d): Test Window: succ %d total %d\n",
                               rs_pretty_lq_type(rate->type),
@@ -2385,7 +2389,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
        int i, nentries;
        s8 best_rssi = S8_MIN;
        u8 best_ant = ANT_NONE;
-       u8 valid_tx_ant = mvm->fw->valid_tx_ant;
+       u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
        const struct rs_init_rate_info *initial_rates;
 
        for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
@@ -2530,7 +2534,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
 static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
                          gfp_t gfp)
 {
-       struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+       struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate;
        struct iwl_mvm *mvm  = IWL_OP_MODE_GET_MVM(op_mode);
        struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta;
@@ -2683,14 +2687,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        struct ieee80211_hw *hw = mvm->hw;
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
        struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
-       struct iwl_mvm_sta *sta_priv;
-       struct iwl_lq_sta *lq_sta;
+       struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
+       struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta;
        struct ieee80211_supported_band *sband;
        unsigned long supp; /* must be unsigned long for for_each_set_bit */
 
-       sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
-       lq_sta = &sta_priv->lq_sta;
-
        /* clear all non-persistent lq data */
        memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
 
@@ -2712,7 +2713,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
         * previous packets? Need to have IEEE 802.1X auth succeed immediately
         * after assoc.. */
 
-       lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+       lq_sta->missed_rate_counter = IWL_MVM_RS_MISSED_RATE_MAX;
        lq_sta->band = sband->band;
        /*
         * active legacy rates as per supported rates bitmap
@@ -2745,7 +2746,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                        lq_sta->ldpc = true;
 
                if (mvm->cfg->ht_params->stbc &&
-                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
                    (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
                        lq_sta->stbc = true;
        } else {
@@ -2757,7 +2758,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                        lq_sta->ldpc = true;
 
                if (mvm->cfg->ht_params->stbc &&
-                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
                    (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
                        lq_sta->stbc = true;
        }
@@ -2765,12 +2766,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (IWL_MVM_RS_DISABLE_MIMO)
                lq_sta->active_mimo2_rate = 0;
 
-       lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
-                                                   BITS_PER_LONG);
-       lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
-                                                 BITS_PER_LONG);
-       lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
-                                                  BITS_PER_LONG);
+       lq_sta->max_legacy_rate_idx =
+               rs_get_max_rate_from_mask(lq_sta->active_legacy_rate);
+       lq_sta->max_siso_rate_idx =
+               rs_get_max_rate_from_mask(lq_sta->active_siso_rate);
+       lq_sta->max_mimo2_rate_idx =
+               rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate);
 
        IWL_DEBUG_RATE(mvm,
                       "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
@@ -2785,7 +2786,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        /* These values will be overridden later */
        lq_sta->lq.single_stream_ant_msk =
-               first_antenna(mvm->fw->valid_tx_ant);
+               first_antenna(iwl_mvm_get_valid_tx_ant(mvm));
        lq_sta->lq.dual_stream_ant_msk = ANT_AB;
 
        /* as default allow aggregation for all tids */
@@ -2913,18 +2914,18 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
 
        memcpy(&rate, initial_rate, sizeof(rate));
 
-       valid_tx_ant = mvm->fw->valid_tx_ant;
+       valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
        rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
 
        if (is_siso(&rate)) {
-               num_rates = RS_INITIAL_SISO_NUM_RATES;
-               num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+               num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES;
+               num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE;
        } else if (is_mimo(&rate)) {
-               num_rates = RS_INITIAL_MIMO_NUM_RATES;
-               num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+               num_rates = IWL_MVM_RS_INITIAL_MIMO_NUM_RATES;
+               num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE;
        } else {
-               num_rates = RS_INITIAL_LEGACY_NUM_RATES;
-               num_retries = RS_LEGACY_RETRIES_PER_RATE;
+               num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES;
+               num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
                toggle_ant = true;
        }
 
@@ -2935,12 +2936,12 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
        rs_get_lower_rate_down_column(lq_sta, &rate);
 
        if (is_siso(&rate)) {
-               num_rates = RS_SECONDARY_SISO_NUM_RATES;
-               num_retries = RS_SECONDARY_SISO_RETRIES;
+               num_rates = IWL_MVM_RS_SECONDARY_SISO_NUM_RATES;
+               num_retries = IWL_MVM_RS_SECONDARY_SISO_RETRIES;
                lq_cmd->mimo_delim = index;
        } else if (is_legacy(&rate)) {
-               num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
-               num_retries = RS_LEGACY_RETRIES_PER_RATE;
+               num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
+               num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
        } else {
                WARN_ON_ONCE(1);
        }
@@ -2953,8 +2954,8 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
 
        rs_get_lower_rate_down_column(lq_sta, &rate);
 
-       num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
-       num_retries = RS_LEGACY_RETRIES_PER_RATE;
+       num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
+       num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
 
        rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
                                 num_rates, num_retries, valid_tx_ant,
@@ -2971,9 +2972,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
        struct iwl_mvm_sta *mvmsta;
        struct iwl_mvm_vif *mvmvif;
 
-       lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       lq_cmd->agg_disable_start_th = IWL_MVM_RS_AGG_DISABLE_START;
        lq_cmd->agg_time_limit =
-               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+               cpu_to_le16(IWL_MVM_RS_AGG_TIME_LIMIT);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        if (lq_sta->pers.dbg_fixed_rate) {
@@ -3167,9 +3168,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
                        lq_sta->pers.dbg_fixed_rate);
        desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
-           (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "",
-           (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "",
-           (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+           (iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "",
+           (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "",
+           (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : "");
        desc += sprintf(buff+desc, "lq type %s\n",
                        (is_legacy(rate)) ? "legacy" :
                        is_vht(rate) ? "VHT" : "HT");
index defd70a..f8f5bf2 100644 (file)
@@ -137,42 +137,10 @@ enum {
 
 #define IWL_INVALID_VALUE    -1
 
-#define IWL_MIN_RSSI_VAL                 -100
-#define IWL_MAX_RSSI_VAL                    0
-
-/* These values specify how many Tx frame attempts before
- * searching for a new modulation mode */
-#define IWL_LEGACY_FAILURE_LIMIT       160
-#define IWL_LEGACY_SUCCESS_LIMIT       480
-#define IWL_LEGACY_TABLE_COUNT         160
-
-#define IWL_NONE_LEGACY_FAILURE_LIMIT  400
-#define IWL_NONE_LEGACY_SUCCESS_LIMIT  4500
-#define IWL_NONE_LEGACY_TABLE_COUNT    1500
-
-/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
-#define IWL_RS_GOOD_RATIO              12800   /* 100% */
-#define IWL_RATE_SCALE_SWITCH          10880   /*  85% */
-#define IWL_RATE_HIGH_TH               10880   /*  85% */
-#define IWL_RATE_INCREASE_TH           6400    /*  50% */
-#define RS_SR_FORCE_DECREASE           1920    /*  15% */
-#define RS_SR_NO_DECREASE              10880   /*  85% */
-
-#define TPC_SR_FORCE_INCREASE          9600    /* 75% */
-#define TPC_SR_NO_INCREASE             10880   /* 85% */
-#define TPC_TX_POWER_STEP              3
 #define TPC_MAX_REDUCTION              15
 #define TPC_NO_REDUCTION               0
 #define TPC_INVALID                    0xff
 
-#define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (8000)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (100)
-
-#define LINK_QUAL_AGG_DISABLE_START_DEF        (3)
-#define LINK_QUAL_AGG_DISABLE_START_MAX        (255)
-#define LINK_QUAL_AGG_DISABLE_START_MIN        (0)
-
 #define LINK_QUAL_AGG_FRAME_LIMIT_DEF  (63)
 #define LINK_QUAL_AGG_FRAME_LIMIT_MAX  (63)
 #define LINK_QUAL_AGG_FRAME_LIMIT_MIN  (0)
@@ -181,14 +149,7 @@ enum {
 
 /* load per tid defines for A-MPDU activation */
 #define IWL_AGG_TPT_THREHOLD   0
-#define IWL_AGG_LOAD_THRESHOLD 10
 #define IWL_AGG_ALL_TID                0xff
-#define TID_QUEUE_CELL_SPACING 50      /*mS */
-#define TID_QUEUE_MAX_SIZE     20
-#define TID_ROUND_VALUE                5       /* mS */
-
-#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
-#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
 
 enum iwl_table_type {
        LQ_NONE,
index e5294d0..348b9c4 100644 (file)
@@ -72,6 +72,8 @@
 
 #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
 
 struct iwl_mvm_scan_params {
        u32 max_out_time;
@@ -97,7 +99,7 @@ static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
 {
        if (mvm->scan_rx_ant != ANT_NONE)
                return mvm->scan_rx_ant;
-       return mvm->fw->valid_rx_ant;
+       return iwl_mvm_get_valid_rx_ant(mvm);
 }
 
 static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
@@ -128,7 +130,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
        u32 tx_ant;
 
        mvm->scan_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+               iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
                                     mvm->scan_last_antenna_idx);
        tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
 
@@ -282,11 +284,11 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
                                            struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       bool *global_bound = data;
+       int *global_cnt = data;
 
        if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
            mvmvif->phy_ctxt->id < MAX_PHYS)
-               *global_bound = true;
+               *global_cnt += 1;
 }
 
 static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
@@ -294,16 +296,16 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
                                     int n_ssids, u32 flags,
                                     struct iwl_mvm_scan_params *params)
 {
-       bool global_bound = false;
+       int global_cnt = 0;
        enum ieee80211_band band;
        u8 frag_passive_dwell = 0;
 
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_scan_condition_iterator,
-                                           &global_bound);
+                                           &global_cnt);
 
-       if (!global_bound)
+       if (!global_cnt)
                goto not_bound;
 
        params->suspend_time = 30;
@@ -314,7 +316,11 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
                    IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
                        params->suspend_time = 105;
                        params->max_out_time = 70;
-                       frag_passive_dwell = 20;
+                       /*
+                        * If there is more than one active interface make
+                        * passive scan more fragmented.
+                        */
+                       frag_passive_dwell = (global_cnt < 2) ? 40 : 20;
                } else {
                        params->suspend_time = 120;
                        params->max_out_time = 120;
@@ -1296,10 +1302,14 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
                        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);
        }
 
        if (iwl_mvm_rrm_scan_needed(mvm))
@@ -1603,7 +1613,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
                                         SCAN_CONFIG_FLAG_SET_MAC_ADDR |
                                         SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
                                         SCAN_CONFIG_N_CHANNELS(num_channels));
-       scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant);
+       scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
        scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm));
        scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm);
        scan_config->out_of_channel_time = cpu_to_le32(170);
index d86fe43..ad32798 100644 (file)
@@ -99,7 +99,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
 int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                           bool update)
 {
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_add_sta_cmd add_sta_cmd = {
                .sta_id = mvm_sta->sta_id,
                .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color),
@@ -259,7 +259,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
                    struct ieee80211_sta *sta)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        int i, ret, sta_id;
 
        lockdep_assert_held(&mvm->mutex);
@@ -481,7 +481,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
                   struct ieee80211_sta *sta)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
@@ -774,7 +774,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_add_sta_cmd cmd = {};
        int ret;
        u32 status;
@@ -834,7 +834,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                              int tid, u8 queue, bool start)
 {
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_add_sta_cmd cmd = {};
        int ret;
        u32 status;
@@ -1144,10 +1144,10 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
 static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
        if (sta) {
-               struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+               struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
                return mvm_sta->sta_id;
        }
@@ -1280,7 +1280,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_sta *sta)
 {
-       struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
        if (sta)
                return sta->addr;
index 2b1e61f..ba615ad 100644 (file)
@@ -69,6 +69,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;
 
        if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
@@ -77,12 +78,15 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
        IWL_ERR(mvm, "Enter CT Kill\n");
        iwl_mvm_set_hw_ctkill_state(mvm, true);
 
+       tt->throttle = false;
+       tt->dynamic_smps = false;
+
        /* Don't schedule an exit work if we're in test mode, since
         * the temperature will not change unless we manually set it
         * again (or disable testing).
         */
        if (!mvm->temperature_test)
-               schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
+               schedule_delayed_work(&tt->ct_kill_exit,
                                      round_jiffies_relative(duration * HZ));
 }
 
@@ -452,6 +456,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
                tt->params = &iwl7000_tt_params;
 
        tt->throttle = false;
+       tt->dynamic_smps = false;
        tt->min_backoff = min_backoff;
        INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
 }
index 4f15d9d..d6cdb77 100644 (file)
@@ -209,7 +209,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
        rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
 
        mvm->mgmt_last_antenna_idx =
-               iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+               iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
                                     mvm->mgmt_last_antenna_idx);
 
        if (info->band == IEEE80211_BAND_2GHZ &&
index e56e77e..f0a1141 100644 (file)
@@ -620,7 +620,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        lockdep_assert_held(&mvm->mutex);
 
        /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
-       if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
+       if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
                return;
 
        if (vif->type == NL80211_IFTYPE_AP)
@@ -662,7 +662,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
+       if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
                return false;
 
        if (!mvm->cfg->rx_with_siso_diversity)
index 1aea6b6..e5652d8 100644 (file)
@@ -318,6 +318,11 @@ struct iwl_trans_pcie {
        /*protect hw register */
        spinlock_t reg_lock;
        bool cmd_in_flight;
+       bool ref_cmd_in_flight;
+
+       /* protect ref counter */
+       spinlock_t ref_lock;
+       u32 ref_count;
 
        dma_addr_t fw_mon_phys;
        struct page *fw_mon_page;
@@ -381,6 +386,9 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
                            struct sk_buff_head *skbs);
 void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
 
+void iwl_trans_pcie_ref(struct iwl_trans *trans);
+void iwl_trans_pcie_unref(struct iwl_trans *trans);
+
 static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
 {
        struct iwl_tfd_tb *tb = &tfd->tbs[idx];
index 523fe0c..9ee4ca0 100644 (file)
@@ -443,10 +443,25 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
        return ret;
 }
 
-static void iwl_pcie_apm_stop(struct iwl_trans *trans)
+static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
 {
        IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
 
+       if (op_mode_leave) {
+               if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+                       iwl_pcie_apm_init(trans);
+
+               /* inform ME that we are leaving */
+               if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+                       iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
+                                         APMG_PCIDEV_STT_VAL_WAKE_ME);
+               else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+                       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+                                   CSR_HW_IF_CONFIG_REG_PREPARE |
+                                   CSR_HW_IF_CONFIG_REG_ENABLE_PME);
+               mdelay(5);
+       }
+
        clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
 
        /* Stop device's DMA activity */
@@ -893,6 +908,9 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
        if (ret)
                return ret;
 
+       if (trans->dbg_dest_tlv)
+               iwl_pcie_apply_destination(trans);
+
        /* Notify FW loading is done */
        iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
 
@@ -916,6 +934,7 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
 static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                                   const struct fw_img *fw, bool run_in_rfkill)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
        bool hw_rfkill;
 
@@ -945,6 +964,9 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                return ret;
        }
 
+       /* init ref_count to 1 (should be cleared when ucode is loaded) */
+       trans_pcie->ref_count = 1;
+
        /* make sure rfkill handshake bits are cleared */
        iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
        iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
@@ -1010,7 +1032,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
                      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 
        /* Stop the device, and put it in low power state */
-       iwl_pcie_apm_stop(trans);
+       iwl_pcie_apm_stop(trans, false);
 
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
@@ -1192,7 +1214,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
        iwl_disable_interrupts(trans);
        spin_unlock(&trans_pcie->irq_lock);
 
-       iwl_pcie_apm_stop(trans);
+       iwl_pcie_apm_stop(trans, true);
 
        spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
@@ -1540,6 +1562,38 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
        spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
 }
 
+void iwl_trans_pcie_ref(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       if (iwlwifi_mod_params.d0i3_disable)
+               return;
+
+       spin_lock_irqsave(&trans_pcie->ref_lock, flags);
+       IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
+       trans_pcie->ref_count++;
+       spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+}
+
+void iwl_trans_pcie_unref(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       if (iwlwifi_mod_params.d0i3_disable)
+               return;
+
+       spin_lock_irqsave(&trans_pcie->ref_lock, flags);
+       IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
+       if (WARN_ON_ONCE(trans_pcie->ref_count == 0)) {
+               spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+               return;
+       }
+       trans_pcie->ref_count--;
+       spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+}
+
 static const char *get_csr_string(int cmd)
 {
 #define IWL_CMD(x) case x: return #x
@@ -2264,6 +2318,9 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .release_nic_access = iwl_trans_pcie_release_nic_access,
        .set_bits_mask = iwl_trans_pcie_set_bits_mask,
 
+       .ref = iwl_trans_pcie_ref,
+       .unref = iwl_trans_pcie_unref,
+
        .dump_data = iwl_trans_pcie_dump_data,
 };
 
@@ -2404,6 +2461,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        }
 
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
+       trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND;
 
        return trans;
 
index 8a6c7a0..c1c4c75 100644 (file)
@@ -985,17 +985,31 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
 
        if (iwl_queue_space(&txq->q) > txq->q.low_mark)
                iwl_wake_queue(trans, txq);
+
+       if (q->read_ptr == q->write_ptr) {
+               IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
+               iwl_trans_pcie_unref(trans);
+       }
+
 out:
        spin_unlock_bh(&txq->lock);
 }
 
-static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans)
+static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
+                                     const struct iwl_host_cmd *cmd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
 
        lockdep_assert_held(&trans_pcie->reg_lock);
 
+       if (!(cmd->flags & CMD_SEND_IN_IDLE) &&
+           !trans_pcie->ref_cmd_in_flight) {
+               trans_pcie->ref_cmd_in_flight = true;
+               IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n");
+               iwl_trans_pcie_ref(trans);
+       }
+
        if (trans_pcie->cmd_in_flight)
                return 0;
 
@@ -1036,6 +1050,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
 
        lockdep_assert_held(&trans_pcie->reg_lock);
 
+       if (trans_pcie->ref_cmd_in_flight) {
+               trans_pcie->ref_cmd_in_flight = false;
+               IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n");
+               iwl_trans_pcie_unref(trans);
+       }
+
        if (WARN_ON(!trans_pcie->cmd_in_flight))
                return 0;
 
@@ -1473,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
                mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
 
        spin_lock_irqsave(&trans_pcie->reg_lock, flags);
-       ret = iwl_pcie_set_cmd_in_flight(trans);
+       ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
        if (ret < 0) {
                idx = ret;
                spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
@@ -1819,9 +1839,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        wait_write_ptr = ieee80211_has_morefrags(fc);
 
        /* start timer if queue currently empty */
-       if (txq->need_update && q->read_ptr == q->write_ptr &&
-           trans_pcie->wd_timeout)
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+       if (q->read_ptr == q->write_ptr) {
+               if (txq->need_update && trans_pcie->wd_timeout)
+                       mod_timer(&txq->stuck_timer,
+                                 jiffies + trans_pcie->wd_timeout);
+               IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
+               iwl_trans_pcie_ref(trans);
+       }
 
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr);