From: Kalle Valo Date: Tue, 6 Jan 2015 17:36:11 +0000 (+0200) Subject: Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux... X-Git-Tag: v4.0-rc1~133^2~10^2~247 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Flinux.git;a=commitdiff_plain;h=64bb1b944b554a751b518b09c3d596f6b6c0ce31;hp=dd9553988879a3ff71a86323b88409e7631c4e5d Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git./linux/kernel/git/iwlwifi/iwlwifi-next * 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 --- diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 0b7f46f0b079..de43dd7e170a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -64,22 +64,8 @@ * ******************************************************************************/ -/* - * 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) diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index acb981a0a0aa..c4736c8834c5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -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); diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index e5be2d21868f..9e76799c4750 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -92,6 +92,12 @@ #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)); diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index bf0a95cb7153..46e9c9ac6ba2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -81,12 +81,19 @@ #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, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3a4b9c7fc083..fa0bc4845e1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -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 */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index aff63c3f5bf8..7f40cf36ec0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -184,6 +184,7 @@ #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) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 850b85a47806..e766dcdf72ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -84,21 +84,8 @@ * ******************************************************************************/ -/* - * 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 diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index be4f8972241a..adf522c756e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -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 "" diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 20a8a64c9fe3..ec115bded88a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -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 @@ -82,9 +81,10 @@ * @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 diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index f2a047f6bb3e..752c72b77fba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -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, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index e6dc3b870949..ffd785cc67d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -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]; diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 71507cf490e6..2a8cf4b2445c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -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; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 06e02fcd6f7b..c74f1a4edf23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -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; diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 2df51eab1348..83ab4239082c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -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 { diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 028408a6ecba..84d8477432a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -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 *)); diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index a3bfda45d9e6..d2fd48c31d3d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -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, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index b3210cfbecc8..973f2881dd1d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -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, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 3bd93476ec1c..7cd1de820ca7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -102,5 +102,33 @@ #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 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 744de262373e..14e8fd661889 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -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); } diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 9aa2311a776c..8dc3ca9f4904 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -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", diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 33bf915cd7ea..a1b276c4dee0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -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) { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1f2acf47bfb2..2d1a81c493f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -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; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d0fa6e9ed590..534ee3123a63 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -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; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index f6d86ccce6a8..7196b4d6b7cc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -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 = diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e880f9d4717b..3756c03e752f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -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"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d24660fb4ef2..b2100b414055 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -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__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 97dfba50c682..239f033e3b93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -84,15 +84,8 @@ #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); diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 1c0d4a45c1a8..540c36bae268 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -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)); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 30ceb67ed7a7..7ba6e5dbbbd0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -42,25 +42,12 @@ #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"); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index defd70a6d9e6..f8f5bf21cc38 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -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, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index e5294d01181e..348b9c4b694a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -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); diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d86fe432e51f..ad327984b099 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -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; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 2b1e61fac34a..ba615ad2176c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -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); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4f15d9decc81..d6cdb770881a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -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 && diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index e56e77ef5d2e..f0a114102c3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -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) diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 1aea6b66c594..e5652d82d79e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -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]; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 523fe0c88dcb..9ee4ca0ba8d3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -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; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8a6c7a084aa1..c1c4c75026b2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -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);