diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-09-15 22:37:07 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-09-15 22:37:07 +0400 |
commit | eb2eacf77ec4828c9a2e451b06bc6fc44266f4c0 (patch) | |
tree | 32d6aff5b5c67649e3ca81e0aa9322f206224aaf /drivers | |
parent | 167bf96dd87d2a8360cb9e9783006876dac4f579 (diff) | |
parent | f991e17ba2584e2be66476cc468f19769efd55cc (diff) | |
download | linux-eb2eacf77ec4828c9a2e451b06bc6fc44266f4c0.tar.xz |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Diffstat (limited to 'drivers')
41 files changed, 634 insertions, 521 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c index 760c45c34ef3..1513dbc79c14 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/iwlwifi/dvm/power.c @@ -40,7 +40,7 @@ #include "commands.h" #include "power.h" -static bool force_cam; +static bool force_cam = true; module_param(force_cam, bool, 0644); MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)"); diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 7e26d0dbfcf7..b04b8858c690 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -85,6 +85,8 @@ #define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL3160_NVM_VERSION 0x709 #define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL3165_NVM_VERSION 0x709 +#define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL7265_NVM_VERSION 0x0a1d #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ @@ -94,6 +96,9 @@ #define IWL3160_FW_PRE "iwlwifi-3160-" #define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" +#define IWL3165_FW_PRE "iwlwifi-3165-" +#define IWL3165_MODULE_FIRMWARE(api) IWL3165_FW_PRE __stringify(api) ".ucode" + #define IWL7265_FW_PRE "iwlwifi-7265-" #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" @@ -126,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl7000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ + .non_shared_ant = ANT_A const struct iwl_cfg iwl7260_2ac_cfg = { @@ -215,11 +221,27 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { {0}, }; +static const struct iwl_ht_params iwl7265_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), +}; + +const struct iwl_cfg iwl3165_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 3165", + .fw_name_pre = IWL3165_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3165_NVM_VERSION, + .nvm_calib_ver = IWL3165_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, +}; + const struct iwl_cfg iwl7265_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -229,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -239,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .name = "Intel(R) Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -247,4 +269,5 @@ const struct iwl_cfg iwl7265_n_cfg = { MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); +MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); MODULE_FIRMWARE(IWL7265_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 23a67bfc086f..4ae8ba6ccfff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = { }; static const struct iwl_ht_params iwl8000_ht_params = { + .ldpc = true, .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), }; @@ -115,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl8000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ + .non_shared_ant = ANT_A + +const struct iwl_cfg iwl8260_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; const struct iwl_cfg iwl8260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 8260", @@ -135,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .disable_dummy_notification = true, }; MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 8da596db9abe..2ef83a39ff10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -120,6 +120,8 @@ enum iwl_led_mode { #define IWL_LONG_WD_TIMEOUT 10000 #define IWL_MAX_WD_TIMEOUT 120000 +#define IWL_DEFAULT_MAX_TX_POWER 22 + /* Antenna presence definitions */ #define ANT_NONE 0x0 #define ANT_A BIT(0) @@ -169,6 +171,7 @@ struct iwl_base_params { /* * @stbc: support Tx STBC and 1*SS Rx STBC + * @ldpc: support Tx/Rx with LDPC * @use_rts_for_aggregation: use rts/cts protection for HT traffic * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 */ @@ -176,6 +179,7 @@ struct iwl_ht_params { enum ieee80211_smps_mode smps_mode; const bool ht_greenfield_support; /* if used set to true */ const bool stbc; + const bool ldpc; bool use_rts_for_aggregation; u8 ht40_bands; }; @@ -226,6 +230,7 @@ struct iwl_pwr_tx_backoff { * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna + * @non_shared_ant: the antenna that is for WiFi only * @nvm_ver: NVM version * @nvm_calib_ver: NVM calibration version * @lib: pointer to the lib ops @@ -258,6 +263,7 @@ struct iwl_cfg { const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; + u8 non_shared_ant; bool bt_shared_single_ant; u16 nvm_ver; u16 nvm_calib_ver; @@ -278,6 +284,7 @@ struct iwl_cfg { bool no_power_up_nic_in_init; const char *default_nvm_file; unsigned int max_rx_agg_size; + bool disable_dummy_notification; }; /* @@ -335,9 +342,11 @@ extern const struct iwl_cfg iwl7260_n_cfg; extern const struct iwl_cfg iwl3160_2ac_cfg; extern const struct iwl_cfg iwl3160_2n_cfg; extern const struct iwl_cfg iwl3160_n_cfg; +extern const struct iwl_cfg iwl3165_2ac_cfg; extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_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; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 23d059af6476..3f6f015285e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -295,6 +295,16 @@ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) + +/** + * hw_rev values + */ +enum { + SILICON_A_STEP = 0, + SILICON_B_STEP, +}; + + #define CSR_HW_REV_TYPE_MSK (0x000FFF0) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index aefd94cb6e91..ed673baedfd7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1363,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)") module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (defualt: 0 dB)"); + "specify antenna coupling in dB (default: 0 dB)"); module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 07ff7e0028ee..74b796dc4242 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; } + if (cfg->ht_params->ldpc) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + if (iwlwifi_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f68cba4e0444..62c46eb8b99c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -127,6 +127,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. + * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. */ @@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), + IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), }; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5eef4ae7333b..7a2cbf6f90db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans) * DEVICE_SET_NMI_8000B_REG - is used. */ if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - ((trans->hw_rev & 0xc) == 0x0)) + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); else iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 8e7af798abd1..c302e7468559 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -148,8 +148,6 @@ static const u8 iwl_nvm_channels_family_8000[] = { #define LAST_2GHZ_HT_PLUS 9 #define LAST_5GHZ_HT 161 -#define DEFAULT_MAX_TX_POWER 16 - /* rate data (static) */ static struct ieee80211_rate iwl_cfg80211_rates[] = { { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, @@ -297,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, * Default value - highest tx power value. max_power * is not used in mvm, and is used for backwards compatibility */ - channel->max_power = DEFAULT_MAX_TX_POWER; + channel->max_power = IWL_DEFAULT_MAX_TX_POWER; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; IWL_DEBUG_EEPROM(dev, "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", @@ -336,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + if (cfg->ht_params->ldpc) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + if (num_tx_ants > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index c89985a58803..9eb85249e89c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -377,6 +377,7 @@ enum iwl_trans_status { * if unset 4k will be the RX buffer size * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @queue_watchdog_timeout: time (in ms) after which queues * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries @@ -392,6 +393,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; unsigned int queue_watchdog_timeout; const char *const *command_names; }; @@ -826,12 +828,6 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); } -static inline void -iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn) -{ - iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL); -} - static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, u32 txq_bm) { diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index a28235913c2c..2d7c3ea3c4f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o coex_legacy.o -iwlmvm-y += tt.o offloading.o +iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 2262d6dc61ae..8df2021f9856 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -587,8 +587,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { - u32 mode; - switch (mvm->bt_force_ant_mode) { case BT_FORCE_ANT_BT: mode = BT_COEX_BT; @@ -758,7 +756,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, struct iwl_bt_iterator_data *data = _data; struct iwl_mvm *mvm = data->mvm; struct ieee80211_chanctx_conf *chanctx_conf; - enum ieee80211_smps_mode smps_mode; + /* default smps_mode is AUTOMATIC - only used for client modes */ + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; u32 bt_activity_grading; int ave_rssi; @@ -766,8 +765,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - /* default smps_mode for BSS / P2P client is AUTOMATIC */ - smps_mode = IEEE80211_SMPS_AUTOMATIC; break; case NL80211_IFTYPE_AP: if (!mvmvif->ap_ibss_active) @@ -799,7 +796,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, else if (bt_activity_grading >= BT_LOW_TRAFFIC) smps_mode = IEEE80211_SMPS_DYNAMIC; - /* relax SMPS contraints for next association */ + /* relax SMPS constraints for next association */ if (!vif->bss_conf.assoc) smps_mode = IEEE80211_SMPS_AUTOMATIC; @@ -1149,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { + /* there is no other antenna, shared antenna is always available */ + if (mvm->cfg->bt_shared_single_ant) + return true; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index dd00e8f7f765..a355788b1166 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -65,12 +65,18 @@ #ifndef __MVM_CONSTANTS_H #define __MVM_CONSTANTS_H +#include <linux/ieee80211.h> + #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) +#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 @@ -86,5 +92,7 @@ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 +#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 +#define IWL_MVM_QUOTA_THRESHOLD 8 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index d919b4ebc83c..9aa2311a776c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -76,8 +76,7 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, switch (param) { case MVM_DEBUGFS_PM_KEEP_ALIVE: { - struct ieee80211_hw *hw = mvm->hw; - int dtimper = hw->conf.ps_dtim_period ?: 1; + int dtimper = vif->bss_conf.dtim_period ?: 1; int dtimper_msec = dtimper * vif->bss_conf.beacon_int; IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index d98ee109c5e9..95eb9a5ef693 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, { int temperature; + if (!mvm->ucode_loaded && !mvm->temperature_test) + return -EIO; + if (kstrtoint(buf, 10, &temperature)) return -EINVAL; /* not a legal temperature */ @@ -1256,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_USER); + PRINT_MVM_REF(IWL_MVM_REF_TX); + PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); + PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); + PRINT_MVM_REF(IWL_MVM_REF_START_AP); + PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); + PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); + PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); + PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); + PRINT_MVM_REF(IWL_MVM_REF_NMI); + PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9c975f9ecfcb..a2c662808a88 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -205,6 +205,10 @@ enum { REPLY_SF_CFG_CMD = 0xd1, REPLY_BEACON_FILTERING_CMD = 0xd2, + /* DTS measurements */ + CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, + DTS_MEASUREMENT_NOTIFICATION = 0xdd, + REPLY_DEBUG_CMD = 0xf0, DEBUG_LOG_MSG = 0xf7, @@ -550,7 +554,7 @@ enum iwl_time_event_type { TE_WIDI_TX_SYNC, /* Channel Switch NoA */ - TE_P2P_GO_CSA_NOA, + TE_CHANNEL_SWITCH_PERIOD, TE_MAX }; /* MAC_EVENT_TYPE_API_E_VER_1 */ @@ -1601,19 +1605,49 @@ enum iwl_sf_scenario { #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ +#define SF_CFG_DUMMY_NOTIF_OFF BIT(16) + /** * Smart Fifo configuration command. - * @state: smart fifo state, types listed in iwl_sf_sate. + * @state: smart fifo state, types listed in enum %iwl_sf_sate. * @watermark: Minimum allowed availabe free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. * @full_on_timeouts: timer values for each scenario in full on state. */ struct iwl_sf_cfg_cmd { - enum iwl_sf_state state; + __le32 state; __le32 watermark[SF_TRANSIENT_STATES_NUMBER]; __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; } __packed; /* SF_CFG_API_S_VER_2 */ +/* DTS measurements */ + +enum iwl_dts_measurement_flags { + DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), + DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), +}; + +/** + * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements + * + * @flags: indicates which measurements we want as specified in &enum + * iwl_dts_measurement_flags + */ +struct iwl_dts_measurement_cmd { + __le32 flags; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ + +/** + * iwl_dts_measurement_notif - notification received with the measurements + * + * @temp: the measured temperature + * @voltage: the measured voltage + */ +struct iwl_dts_measurement_notif { + __le32 temp; + __le32 voltage; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 21d606028ca6..23fd711a67e4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_MVM_STATION_COUNT; i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); + /* reset quota debouncing buffer - 0xff will yield invalid data */ + memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); + /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); if (ret) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 9cbb192f680e..834267145929 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -727,11 +727,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, !force_assoc_off) { u32 dtim_offs; - /* Allow beacons to pass through as long as we are not - * associated, or we do not have dtim period information. - */ - cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON); - /* * The DTIM count counts down, so when it is N that means N * more beacon intervals happen until the DTIM TBTT. Therefore @@ -765,6 +760,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, ctxt_sta->is_assoc = cpu_to_le32(1); } else { ctxt_sta->is_assoc = cpu_to_le32(0); + + /* Allow beacons to pass through as long as we are not + * associated, or we do not have dtim period information. + */ + cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON); } ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); @@ -1234,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { u32 rel_time = (c + 1) * csa_vif->bss_conf.beacon_int - - IWL_MVM_CHANNEL_SWITCH_TIME; + IWL_MVM_CHANNEL_SWITCH_TIME_GO; u32 apply_time = gp2 + rel_time * 1024; - iwl_mvm_schedule_csa_noa(mvm, csa_vif, - IWL_MVM_CHANNEL_SWITCH_TIME - - IWL_MVM_CHANNEL_SWITCH_MARGIN, - apply_time); + iwl_mvm_schedule_csa_period(mvm, csa_vif, + IWL_MVM_CHANNEL_SWITCH_TIME_GO - + IWL_MVM_CHANNEL_SWITCH_MARGIN, + apply_time); } } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { /* we don't have CSA NoA scheduled yet, switch now */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8d1d4b40b0a3..2517f87a4453 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -327,7 +327,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && !iwlwifi_mod_params.uapsd_disable) { hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_UAPSD_AC_INFO; + hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; } @@ -398,12 +398,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - /* TODO: enable that only for firmwares that don't crash */ - /* hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; */ - hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; - hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; - /* we create the 802.11 header and zero length SSID IE. */ - hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; + if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) { + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; + hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; + /* we create the 802.11 header and zero length SSID IE. */ + hw->wiphy->max_sched_scan_ie_len = + SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; + } hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | NL80211_FEATURE_LOW_PRIORITY_SCAN | @@ -668,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, } #ifdef CONFIG_IWLWIFI_DEBUGFS -static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { + static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; @@ -761,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); mvm->fw_error_dump = fw_error_dump; + + /* notify the userspace about the error we had */ + kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); } #endif static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; - iwl_mvm_fw_error_dump(mvm); - /* notify the userspace about the error we had */ - kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); -#endif - iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; @@ -813,12 +812,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->rx_ba_sessions = 0; } -static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +int __iwl_mvm_mac_start(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* Clean up some internal and mac80211 state on restart */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) @@ -835,6 +833,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) iwl_mvm_d0i3_enable_tx(mvm, NULL); } + return ret; +} + +static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = __iwl_mvm_mac_start(mvm); mutex_unlock(&mvm->mutex); return ret; @@ -860,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) mutex_unlock(&mvm->mutex); } -static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - flush_work(&mvm->d0i3_exit_work); - flush_work(&mvm->async_handlers_wk); - - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* disallow low power states when the FW is down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -888,6 +891,19 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); + mvm->ucode_loaded = false; +} + +static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + flush_work(&mvm->d0i3_exit_work); + flush_work(&mvm->async_handlers_wk); + flush_work(&mvm->fw_error_dump_wk); + + mutex_lock(&mvm->mutex); + __iwl_mvm_mac_stop(mvm); mutex_unlock(&mvm->mutex); /* @@ -1196,14 +1212,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mcast_filter_cmd *cmd; struct netdev_hw_addr *addr; - int addr_count = netdev_hw_addr_list_count(mc_list); - bool pass_all = false; + int addr_count; + bool pass_all; int len; - if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { - pass_all = true; + addr_count = netdev_hw_addr_list_count(mc_list); + pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES || + IWL_MVM_FW_MCAST_FILTER_PASS_ALL; + if (pass_all) addr_count = 0; - } len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); cmd = kzalloc(len, GFP_ATOMIC); @@ -1403,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, } #endif -static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, - NL80211_TDLS_TEARDOWN, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, - GFP_KERNEL); - } -} - static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1544,11 +1539,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); - } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | - BSS_CHANGED_QOS)) { - ret = iwl_mvm_power_update_mac(mvm); - if (ret) - IWL_ERR(mvm, "failed to update power mode\n"); } if (changes & BSS_CHANGED_BEACON_INFO) { @@ -1556,6 +1546,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); } + if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { + ret = iwl_mvm_power_update_mac(mvm); + if (ret) + IWL_ERR(mvm, "failed to update power mode\n"); + } + if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", bss_conf->txpower); @@ -1721,7 +1717,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, return; if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | - BSS_CHANGED_BANDWIDTH) && + BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) && iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL)) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); @@ -1952,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int count = 0; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - if (vif) { - mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (mvmsta->vif != vif) - continue; - } - - count++; - } - - return count; -} - -static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool sta_added) -{ - int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); - - /* - * Disable ps when the first TDLS sta is added and re-enable it - * when the last TDLS sta is removed - */ - if ((tdls_sta_cnt == 1 && sta_added) || - (tdls_sta_cnt == 0 && !sta_added)) - iwl_mvm_power_update_mac(mvm); -} - static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2167,27 +2121,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); } -static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; - - /* - * iwl_mvm_protect_session() reads directly from the device - * (the system time), so make sure it is available. - */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) - return; - - mutex_lock(&mvm->mutex); - /* Protect the session to hear the TDLS setup response on the channel */ - iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); - mutex_unlock(&mvm->mutex); - - iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); -} - static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e292de96e09a..552995810f9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -87,11 +87,11 @@ /* A TimeUnit is 1024 microsecond */ #define MSEC_TO_TU(_msec) (_msec*1000/1024) -/* - * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" - * TBTT. This value should be big enough to ensure that we switch in time. +/* This value represents the number of TUs before CSA "beacon 0" TBTT + * when the CSA time-event needs to be scheduled to start. It must be + * big enough to ensure that we switch in time. */ -#define IWL_MVM_CHANNEL_SWITCH_TIME 40 +#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 /* * This value (in TUs) is used to fine tune the CSA NoA end time which should @@ -180,10 +180,6 @@ enum iwl_power_scheme { }; #define IWL_CONN_MAX_LISTEN_INTERVAL 10 -#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -274,6 +270,8 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, + /* update debugfs.c when changing this */ + IWL_MVM_REF_COUNT, }; @@ -649,6 +647,7 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; + struct work_struct fw_error_dump_wk; struct iwl_mvm_dump_ptrs *fw_error_dump; #ifdef CONFIG_IWLWIFI_LEDS @@ -709,6 +708,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + struct iwl_time_quota_cmd last_quota_cmd; + #ifdef CONFIG_NL80211_TESTMODE u32 noa_duration; struct ieee80211_vif *noa_vif; @@ -788,6 +789,9 @@ struct iwl_rate_info { u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ }; +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm); +int __iwl_mvm_mac_start(struct iwl_mvm *mvm); + /****************** * MVM Methods ******************/ @@ -1153,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* TDLS */ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added); +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +#else +static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {} +#endif #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 4fafd4bd89f4..af074563e770 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -64,6 +64,7 @@ *****************************************************************************/ #include <linux/firmware.h> #include "iwl-trans.h" +#include "iwl-csr.h" #include "mvm.h" #include "iwl-eeprom-parse.h" #include "iwl-eeprom-read.h" @@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) /* Maximal size depends on HW family and step */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) max_section_size = IWL_MAX_NVM_SECTION_SIZE; - else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */ + else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; else /* Family 8000 B-step */ max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 87f278cc9b2c..f887779717d5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BCAST_FILTER_CMD), CMD(REPLY_SF_CFG_CMD), CMD(REPLY_BEACON_FILTERING_CMD), + CMD(CMD_DTS_MEASUREMENT_TRIGGER), + CMD(DTS_MEASUREMENT_NOTIFICATION), CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(MAC_PM_POWER_TABLE), CMD(BT_COEX_CI), @@ -364,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) return 0; } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -431,6 +435,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); + INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); @@ -460,6 +465,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; + trans_cfg.scd_set_active = true; snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), @@ -781,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) module_put(THIS_MODULE); } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) +{ + struct iwl_mvm *mvm = + container_of(work, struct iwl_mvm, fw_error_dump_wk); + + mutex_lock(&mvm->mutex); + iwl_mvm_fw_error_dump(mvm); + mutex_unlock(&mvm->mutex); +} + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); + } else if (fw_error) { + schedule_work(&mvm->fw_error_dump_wk); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index e7a6626fe839..5b85b0cc7a2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -286,13 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, return true; } +static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; + bool radar_detect = false; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + WARN_ON(!chanctx_conf); + if (chanctx_conf) { + chan = chanctx_conf->def.chan; + radar_detect = chan->flags & IEEE80211_CHAN_RADAR; + } + rcu_read_unlock(); + + return radar_detect; +} + static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) { - struct ieee80211_hw *hw = mvm->hw; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; int dtimper, dtimper_msec; int keep_alive; bool radar_detect = false; @@ -301,7 +316,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - dtimper = hw->conf.ps_dtim_period ?: 1; + dtimper = vif->bss_conf.dtim_period; /* * Regardless of power management state the driver must set @@ -321,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - !mvmvif->pm_enabled) + !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -334,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, } /* Check if radar detection is required on current channel */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - WARN_ON(!chanctx_conf); - if (chanctx_conf) { - chan = chanctx_conf->def.chan; - radar_detect = chan->flags & IEEE80211_CHAN_RADAR; - } - rcu_read_unlock(); + radar_detect = iwl_mvm_power_is_radar(vif); /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper <= 10) && @@ -502,8 +510,6 @@ struct iwl_power_vifs { bool bss_active; bool ap_active; bool monitor_active; - bool bss_tdls; - bool p2p_tdls; }; static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, @@ -558,8 +564,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->p2p_vif); power_iterator->p2p_vif = vif; - power_iterator->p2p_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->p2p_active = true; @@ -569,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; - power_iterator->bss_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->bss_active = true; @@ -613,15 +615,13 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && - !vifs->bss_tdls) { + if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && - !vifs->p2p_tdls) { + if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) p2p_mvmvif->pm_enabled = true; return; @@ -962,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { - /* configure skip over dtim up to 300 msec */ - int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; - int dtimper_msec = dtimper * vif->bss_conf.beacon_int; + /* configure skip over dtim up to 306TU - 314 msec */ + int dtimper = vif->bss_conf.dtim_period ?: 1; + int dtimper_tu = dtimper * vif->bss_conf.beacon_int; + bool radar_detect = iwl_mvm_power_is_radar(vif); - if (WARN_ON(!dtimper_msec)) + if (WARN_ON(!dtimper_tu)) return 0; - cmd.skip_dtim_periods = 300 / dtimper_msec; - if (cmd.skip_dtim_periods) - cmd.flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + /* Check skip over DTIM conditions */ + /* TODO: check that multicast wake lock is off */ + if (!radar_detect && (dtimper < 10)) { + cmd.skip_dtim_periods = 306 / dtimper_tu; + if (cmd.skip_dtim_periods) + cmd.flags |= cpu_to_le16( + POWER_FLAGS_SKIP_OVER_DTIM_MSK); + } } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 5fd502db03d1..dbb2594390e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif) { struct iwl_time_quota_cmd cmd = {}; - int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; + int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, .disabled_vif = disabled_vif, }; + struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd; + bool send = false; lockdep_assert_held(&mvm->mutex); @@ -293,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, /* check that we have non-zero quota for all valid bindings */ for (i = 0; i < MAX_BINDINGS; i++) { + if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color) + send = true; + if (cmd.quotas[i].max_duration != last->quotas[i].max_duration) + send = true; + if (abs((int)le32_to_cpu(cmd.quotas[i].quota) - + (int)le32_to_cpu(last->quotas[i].quota)) + > IWL_MVM_QUOTA_THRESHOLD) + send = true; if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) continue; WARN_ONCE(cmd.quotas[i].quota == 0, "zero quota on binding %d\n", i); } - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - return ret; + if (!send) { + /* don't send a practically unchanged command, the firmware has + * to re-initialize a lot of state and that can have an adverse + * impact on it + */ + return 0; + } + + err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); + + if (err) + IWL_ERR(mvm, "Failed to send quota: %d\n", err); + else + mvm->last_quota_cmd = cmd; + return err; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 17002cf437db..f77dfe4df074 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -505,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, const char *prefix) { - IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", + IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n", prefix, rs_pretty_lq_type(rate->type), rate->index, rs_pretty_ant(rate->ant), - rate->bw, rate->sgi); + rate->bw, rate->sgi, rate->ldpc); } static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) @@ -672,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, return -EINVAL; if (tbl->column != RS_COLUMN_INVALID) { - lq_sta->tx_stats[tbl->column][scale_index].total += attempts; - lq_sta->tx_stats[tbl->column][scale_index].success += successes; + struct lq_sta_pers *pers = &lq_sta->pers; + + pers->tx_stats[tbl->column][scale_index].total += attempts; + pers->tx_stats[tbl->column][scale_index].success += successes; } /* Select window for current tx bit rate */ @@ -742,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, ucode_rate |= rate->bw; if (rate->sgi) ucode_rate |= RATE_MCS_SGI_MSK; + if (rate->ldpc) + ucode_rate |= RATE_MCS_LDPC_MSK; return ucode_rate; } @@ -779,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, /* HT or VHT */ if (ucode_rate & RATE_MCS_SGI_MSK) rate->sgi = true; + if (ucode_rate & RATE_MCS_LDPC_MSK) + rate->ldpc = true; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; @@ -965,13 +971,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->index > IWL_RATE_MCS_9_INDEX); rate->index = rs_ht_to_legacy[rate->index]; + rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ rate->type = is_vht_mimo2(rate) ? LQ_VHT_SISO : LQ_HT_SISO; } - if (num_of_ant(rate->ant) > 1) rate->ant = first_antenna(mvm->fw->valid_tx_ant); @@ -1621,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, } rate->bw = rs_bw_from_sta_bw(sta); + rate->ldpc = lq_sta->ldpc; search_tbl->column = col_id; rs_set_expected_tpt_table(lq_sta, search_tbl); @@ -2031,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, return; } - /* force user max rate if set by user */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < index)) { - index = lq_sta->max_rate_idx; - update_lq = 1; - window = &(tbl->win[index]); - IWL_DEBUG_RATE(mvm, - "Forcing user max rate %d\n", - index); - goto lq_update; - } - + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ window = &(tbl->win[index]); /* @@ -2130,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, low = high_low & 0xff; high = (high_low >> 8) & 0xff; - /* If user set max rate, dont allow higher than user constrain */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < high)) - high = IWL_RATE_INVALID; + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ sr = window->success_ratio; @@ -2342,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate->index = i; rate->ant = first_antenna(valid_tx_ant); rate->sgi = false; + rate->ldpc = false; rate->bw = RATE_MCS_CHAN_WIDTH_20; if (band == IEEE80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; @@ -2364,23 +2358,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct ieee80211_tx_rate_control *txrc) { struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; struct iwl_op_mode *op_mode __maybe_unused = (struct iwl_op_mode *)mvm_r; struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; - /* Get max rate if user set max rate */ - if (lq_sta) { - lq_sta->max_rate_idx = txrc->max_rate_idx; - if ((sband->band == IEEE80211_BAND_5GHZ) && - (lq_sta->max_rate_idx != -1)) - lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; - if ((lq_sta->max_rate_idx < 0) || - (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) - lq_sta->max_rate_idx = -1; - } + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ /* Treat uninitialized rate scaling data same as non-existing. */ if (lq_sta && !lq_sta->pers.drv) { @@ -2581,7 +2565,6 @@ 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->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; lq_sta->band = sband->band; /* @@ -2610,9 +2593,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; lq_sta->is_vht = false; + if (mvm->cfg->ht_params->ldpc && + (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) + lq_sta->ldpc = true; } else { rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); lq_sta->is_vht = true; + + if (mvm->cfg->ht_params->ldpc && + (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) + lq_sta->ldpc = true; } lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, @@ -2622,11 +2612,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, BITS_PER_LONG); - IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", + IWL_DEBUG_RATE(mvm, + "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht); + lq_sta->is_vht, lq_sta->ldpc); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -3032,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_ht20(rate)) ? "20MHz" : (is_ht40(rate)) ? "40MHz" : (is_ht80(rate)) ? "80Mhz" : "BAD BW"); - desc += sprintf(buff+desc, " %s %s\n", + desc += sprintf(buff+desc, " %s %s %s\n", (rate->sgi) ? "SGI" : "NGI", + (rate->ldpc) ? "LDPC" : "BCC", (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", @@ -3181,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, "%s,", column_name[col]); for (rate = 0; rate < IWL_RATE_COUNT; rate++) { - stats = &(lq_sta->tx_stats[col][rate]); + stats = &(lq_sta->pers.tx_stats[col][rate]); pos += scnprintf(pos, endpos - pos, "%llu/%llu,", stats->success, @@ -3200,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_lq_sta *lq_sta = file->private_data; - memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats)); + memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats)); return count; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f27b9d687a25..95c4b960fd71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -207,6 +207,7 @@ struct rs_rate { u8 ant; u32 bw; bool sgi; + bool ldpc; }; @@ -329,10 +330,9 @@ struct iwl_lq_sta { */ u64 last_tx; bool is_vht; + bool ldpc; /* LDPC Rx is supported by the STA */ enum ieee80211_band band; - struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ unsigned long active_legacy_rate; unsigned long active_siso_rate; @@ -343,7 +343,6 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; - s8 max_rate_idx; /* Max rate set by user */ u8 missed_rate_counter; struct iwl_lq_cmd lq; @@ -361,11 +360,14 @@ struct iwl_lq_sta { int tpc_reduce; /* persistent fields - initialized only once - keep last! */ - struct { + struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS u32 dbg_fixed_rate; u8 dbg_fixed_txp_reduction; #endif + u8 chains; + s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 48144e3ad527..a6cb84ed653f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -151,13 +151,13 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]); energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >> IWL_RX_INFO_ENERGY_ANT_A_POS; - energy_a = energy_a ? -energy_a : -256; + energy_a = energy_a ? -energy_a : S8_MIN; energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >> IWL_RX_INFO_ENERGY_ANT_B_POS; - energy_b = energy_b ? -energy_b : -256; + energy_b = energy_b ? -energy_b : S8_MIN; energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >> IWL_RX_INFO_ENERGY_ANT_C_POS; - energy_c = energy_c ? -energy_c : -256; + energy_c = energy_c ? -energy_c : S8_MIN; max_energy = max(energy_a, energy_b); max_energy = max(max_energy, energy_c); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index bf9c63dc4a7d..09545f23b24f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -160,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) { if (band == IEEE80211_BAND_2GHZ) - return 30 + 3 * (n_ssids + 1); - return 20 + 2 * (n_ssids + 1); + return 20 + 3 * (n_ssids + 1); + return 10 + 2 * (n_ssids + 1); } static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index d1922afe06f4..7eb78e2c240a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -174,11 +174,15 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, enum iwl_sf_state new_state) { struct iwl_sf_cfg_cmd sf_cmd = { - .state = new_state, + .state = cpu_to_le32(new_state), }; struct ieee80211_sta *sta; int ret = 0; + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && + mvm->cfg->disable_dummy_notification) + sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); + /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index dd9f3a4347f6..666f16b4bed9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -948,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } tid_data->ssn = 0xffff; + tid_data->state = IWL_AGG_OFF; + mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; + spin_unlock_bh(&mvmsta->lock); + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, txq_id, true); - /* fall through */ + return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: /* @@ -1003,6 +1011,8 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c new file mode 100644 index 000000000000..66c82df2d0a1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include "mvm.h" +#include "time-event.h" + +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, + GFP_KERNEL); + } +} + +int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int count = 0; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + if (vif) { + mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->vif != vif) + continue; + } + + count++; + } + + return count; +} + +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added) +{ + int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); + + /* + * Disable ps when the first TDLS sta is added and re-enable it + * when the last TDLS sta is removed + */ + if ((tdls_sta_cnt == 1 && sta_added) || + (tdls_sta_cnt == 0 && !sta_added)) + iwl_mvm_power_update_mac(mvm); +} + +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; + + /* + * iwl_mvm_protect_session() reads directly from the device + * (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) + return; + + mutex_lock(&mvm->mutex); + /* Protect the session to hear the TDLS setup response on the channel */ + iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); + mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 447d3b1003df..b7f9e61d14e2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) iwl_mvm_roc_finished(mvm); } -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time) +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; @@ -711,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (te_data->running) { - IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n"); + IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); return -EBUSY; } time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA); + time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD); time_cmd.apply_time = cpu_to_le32(apply_time); time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.duration = cpu_to_le32(duration); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index bee3b2446b35..b350e47e19da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -219,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, void iwl_mvm_roc_done_wk(struct work_struct *wk); /** - * iwl_mvm_schedule_csa_noa - request NoA for channel switch + * iwl_mvm_schedule_csa_period - request channel switch absence period * @mvm: the mvm component * @vif: the virtual interface for which the channel switch is issued * @duration: the duration of the NoA in TU. @@ -228,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk); * This function is used to schedule NoA time event and is used to perform * the channel switch flow. */ -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time); +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time); /** * iwl_mvm_te_scheduled - check if the fw received the TE cmd diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index c3e1fe4282f1..c750ca7b8269 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -69,275 +69,99 @@ #include "iwl-csr.h" #include "iwl-prph.h" -#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ -/* VBG - Voltage Band Gap error data (temperature offset) */ -#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2) -#define MEAS_VBG_MIN_VAL 2300 -#define MEAS_VBG_MAX_VAL 3000 -#define MEAS_VBG_DEFAULT_VAL 2700 -#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE) -#define MIN_TEMPERATURE 0 -#define MAX_TEMPERATURE 125 -#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1) -#define PTAT_DIGITAL_VALUE_MIN_VALUE 0 -#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF -#define DTS_VREFS_NUM 5 -static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags) -{ - return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> - DTS_DIODE_REG_FLAGS_VREFS_ID_POS; -} +#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ -#define CALC_VREFS_MIN_DIFF 43 -#define CALC_VREFS_MAX_DIFF 51 -#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF) -#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF -#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23 - -/* - * @digital_value: The diode's digital-value sampled (temperature/voltage) - * @vref_low: The lower voltage-reference (the vref just below the diode's - * sampled digital-value) - * @vref_high: The higher voltage-reference (the vref just above the diode's - * sampled digital-value) - * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref) - * bits[6:2]: Reserved. - * bits[7:7]: Indicates completion of at least 1 successful sample - * since last DTS reset. - */ -struct iwl_mvm_dts_diode_bits { - u8 digital_value; - u8 vref_low; - u8 vref_high; - u8 flags; -} __packed; - -union dts_diode_results { - u32 reg_value; - struct iwl_mvm_dts_diode_bits bits; -} __packed; - -static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) +static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { - struct iwl_nvm_section calib_sec; - const __le16 *calib; - u16 vbg; - - /* TODO: move parsing to NVM code */ - calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; - calib = (__le16 *)calib_sec.data; + u32 duration = mvm->thermal_throttle.params->ct_kill_duration; - vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); + if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) - vbg = MEAS_VBG_DEFAULT_VAL; + IWL_ERR(mvm, "Enter CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, true); - return vbg; + /* 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, + round_jiffies_relative(duration * HZ)); } -static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) +static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) { - const u8 *calib; - u8 ptat, pa1, pa2, median; - - /* TODO: move parsing to NVM code */ - calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; - ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; - pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; - pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; - - /* get the median: */ - if (ptat > pa1) { - if (ptat > pa2) - median = (pa1 > pa2) ? pa1 : pa2; - else - median = ptat; - } else { - if (pa1 > pa2) - median = (ptat > pa2) ? ptat : pa2; - else - median = pa1; - } + if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - return ptat - median; + IWL_ERR(mvm, "Exit CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, false); } -static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) +static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) { - /* Calibrate the PTAT digital value, based on PTAT deviation data: */ - s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + int *temp = data; + struct iwl_dts_measurement_notif *notif; + int len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON_ONCE(len != sizeof(*notif))) { + IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); + return true; + } - if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) - new_val = PTAT_DIGITAL_VALUE_MAX_VALUE; - else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE) - new_val = PTAT_DIGITAL_VALUE_MIN_VALUE; + notif = (void *)pkt->data; - return new_val; -} + *temp = le32_to_cpu(notif->temp); -static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u8 vrefs_results[DTS_VREFS_NUM]; - u8 low_vref_index = 0, flags; - u32 reg; - - reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG); - memcpy(vrefs_results, ®, sizeof(reg)); - reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG); - vrefs_results[4] = reg & 0xff; - - if (avg_ptat->bits.digital_value < vrefs_results[0] || - avg_ptat->bits.digital_value > vrefs_results[4]) - return false; - - if (avg_ptat->bits.digital_value > vrefs_results[3]) - low_vref_index = 3; - else if (avg_ptat->bits.digital_value > vrefs_results[2]) - low_vref_index = 2; - else if (avg_ptat->bits.digital_value > vrefs_results[1]) - low_vref_index = 1; - - avg_ptat->bits.vref_low = vrefs_results[low_vref_index]; - avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1]; - flags = avg_ptat->bits.flags; - avg_ptat->bits.flags = - (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) | - (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID); - return true; -} + /* shouldn't be negative, but since it's s32, make sure it isn't */ + if (WARN_ON_ONCE(*temp < 0)) + *temp = 0; -/* - * return true it the results are valid, and false otherwise. - */ -static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u32 reg; - u8 tmp; - - /* fill the diode value and pass_once with avg-reg results */ - reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG); - reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE; - avg_ptat->reg_value = reg; - - /* calibrate the PTAT digital value */ - tmp = avg_ptat->bits.digital_value; - tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp); - avg_ptat->bits.digital_value = tmp; - - /* - * fill vrefs fields, based on the avgVrefs results - * and the diode value - */ - return dts_get_adjacent_vrefs(mvm, avg_ptat) && - DTS_DIODE_VALID(avg_ptat->bits.flags); + IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp); + return true; } -static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, - u16 volt_band_gap) +static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { - u32 tmp_result; - u8 vrefs_diff; - /* - * For temperature calculation (at the end, shift right by 23) - * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) } - * (D2-D1) == 43 44 45 46 47 48 49 50 51 - */ - static const u16 calc_lut[CALC_LUT_SIZE] = { - 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, + struct iwl_dts_measurement_cmd cmd = { + .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; - /* - * The diff between the high and low voltage-references is assumed - * to be strictly be in range of [60,68] - */ - vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; - - if (vrefs_diff < CALC_VREFS_MIN_DIFF || - vrefs_diff > CALC_VREFS_MAX_DIFF) - return TEMPERATURE_ERROR; - - /* calculate the result: */ - tmp_result = - vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9); - tmp_result += avg_ptat.bits.digital_value; - tmp_result -= avg_ptat.bits.vref_high; - - /* multiply by the LUT value (based on the diff) */ - tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; - - /* - * Get the BandGap (the voltage refereces source) error data - * (temperature offset) - */ - tmp_result *= volt_band_gap; - - /* - * here, tmp_result value can be up to 32-bits. We want to right-shift - * it *without* sign-extend. - */ - tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; - - /* - * at this point, tmp_result should be in the range: - * 200 <= tmp_result <= 365 - */ - return (s16)tmp_result - 240; -} - -static s32 check_nic_temperature(struct iwl_mvm *mvm) -{ - u16 volt_band_gap; - union dts_diode_results avg_ptat; - - volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - /* SV initialization */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1); - iwl_write_prph(mvm->trans, DTSC_CFG_MODE, - DTSC_CFG_MODE_PERIODIC); - - /* wait for results */ - msleep(100); - if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) - return TEMPERATURE_ERROR; - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - return calculate_nic_temperature(avg_ptat, volt_band_gap); + return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, + sizeof(cmd), &cmd); } -static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) +static int iwl_mvm_get_temp(struct iwl_mvm *mvm) { - u32 duration = mvm->thermal_throttle.params->ct_kill_duration; + struct iwl_notification_wait wait_temp_notif; + static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; + int ret, temp; - if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + lockdep_assert_held(&mvm->mutex); - IWL_ERR(mvm, "Enter CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, true); + iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, + temp_notif, ARRAY_SIZE(temp_notif), + iwl_mvm_temp_notif, &temp); - /* 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, - round_jiffies_relative(duration * HZ)); -} + ret = iwl_mvm_get_temp_cmd(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret); + iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); + return ret; + } -static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) -{ - if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, + IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); + if (ret) { + IWL_ERR(mvm, "Getting the temperature timed out\n"); + return ret; + } - IWL_ERR(mvm, "Exit CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, false); + return temp; } static void check_exit_ctkill(struct work_struct *work) @@ -352,28 +176,36 @@ static void check_exit_ctkill(struct work_struct *work) duration = tt->params->ct_kill_duration; + mutex_lock(&mvm->mutex); + + if (__iwl_mvm_mac_start(mvm)) + goto reschedule; + /* make sure the device is available for direct read/writes */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) { + __iwl_mvm_mac_stop(mvm); goto reschedule; + } - iwl_trans_start_hw(mvm->trans); - temp = check_nic_temperature(mvm); - iwl_trans_stop_device(mvm->trans); + temp = iwl_mvm_get_temp(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); - if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { - IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); + __iwl_mvm_mac_stop(mvm); + + if (temp < 0) goto reschedule; - } + IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); if (temp <= tt->params->ct_kill_exit) { + mutex_unlock(&mvm->mutex); iwl_mvm_exit_ctkill(mvm); return; } reschedule: + mutex_unlock(&mvm->mutex); schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, round_jiffies(duration * HZ)); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 963edb8656ad..c67296efa04d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -170,10 +170,14 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, /* * for data packets, rate info comes from the table inside the fw. This - * table is controlled by LINK_QUALITY commands + * table is controlled by LINK_QUALITY commands. Exclude ctrl port + * frames like EAPOLs which should be treated as mgmt frames. This + * avoids them being sent initially in high rates which increases the + * chances for completion of the 4-Way handshake. */ - if (ieee80211_is_data(fc) && sta) { + if (ieee80211_is_data(fc) && sta && + !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); return; @@ -209,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, if (info->band == IEEE80211_BAND_2GHZ && !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) - rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS; + rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; else rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbbbf23082a2..ca68c3ccf633 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -354,11 +354,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x08B3, 0x8060, iwl3160_2n_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)}, {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B4, 0x8370, iwl3160_2ac_cfg)}, + {IWL_PCI_DEVICE(0x08B4, 0x8272, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x1170, iwl3160_2ac_cfg)}, +/* 3165 Series */ + {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, + /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)}, @@ -380,6 +386,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, @@ -398,6 +405,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index a4fedc4a7448..1aea6b66c594 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -257,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @cmd_queue - command queue number * @rx_buf_size_8k: 8 kB RX buffer size * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access @@ -306,6 +307,7 @@ struct iwl_trans_pcie { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; u32 rx_page_order; const char *const *command_names; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 702f47fb16fe..7b7e2f223fb2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -640,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); if (reclaim) { - kfree(txq->entries[cmd_index].free_buf); + kzfree(txq->entries[cmd_index].free_buf); txq->entries[cmd_index].free_buf = NULL; } diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3076e0e9a490..ae99240dcde4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1171,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; + trans_pcie->scd_set_active = trans_cfg->scd_set_active; /* Initialize NAPI here - it should be before registering to mac80211 * in the opmode but after the HW struct is allocated. @@ -2189,7 +2190,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) trans->hw_rev = (trans->hw_rev & 0xfff0) | - ((trans->hw_rev << 2) & 0xc); + (CSR_HW_REV_STEP(trans->hw_rev << 2)); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index a6336b4aa3a4..eb8e2984c5e9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -620,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) /* De-alloc array of command/tx buffers */ if (txq_id == trans_pcie->cmd_queue) for (i = 0; i < txq->q.n_window; i++) { - kfree(txq->entries[i].cmd); - kfree(txq->entries[i].free_buf); + kzfree(txq->entries[i].cmd); + kzfree(txq->entries[i].free_buf); } /* De-alloc circular buffer of TFDs */ @@ -1080,7 +1080,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, fifo = cfg->fifo; /* Disable the scheduler prior configuring the cmd queue */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, 0); /* Stop this Tx queue before configuring it */ @@ -1142,7 +1143,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, SCD_QUEUE_STTS_REG_MSK); /* enable the scheduler for this queue (only) */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, BIT(txq_id)); } @@ -1407,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_meta->flags = cmd->flags; if (WARN_ON_ONCE(txq->entries[idx].free_buf)) - kfree(txq->entries[idx].free_buf); + kzfree(txq->entries[idx].free_buf); txq->entries[idx].free_buf = dup_buf; trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); |