Commit eb2eacf7 authored by John W. Linville's avatar John W. Linville
parents 167bf96d f991e17b
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include "commands.h" #include "commands.h"
#include "power.h" #include "power.h"
static bool force_cam; static bool force_cam = true;
module_param(force_cam, bool, 0644); module_param(force_cam, bool, 0644);
MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)"); MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)");
......
...@@ -85,6 +85,8 @@ ...@@ -85,6 +85,8 @@
#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */
#define IWL3160_NVM_VERSION 0x709 #define IWL3160_NVM_VERSION 0x709
#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ #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_NVM_VERSION 0x0a1d
#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */
...@@ -94,6 +96,9 @@ ...@@ -94,6 +96,9 @@
#define IWL3160_FW_PRE "iwlwifi-3160-" #define IWL3160_FW_PRE "iwlwifi-3160-"
#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" #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_FW_PRE "iwlwifi-7265-"
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
...@@ -126,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { ...@@ -126,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_data_size = IWL60_RTC_DATA_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \ .base_params = &iwl7000_base_params, \
.led_mode = IWL_LED_RF_STATE, \ .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 = { const struct iwl_cfg iwl7260_2ac_cfg = {
...@@ -215,11 +221,27 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { ...@@ -215,11 +221,27 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
{0}, {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 = { const struct iwl_cfg iwl7265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265", .name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265_FW_PRE, .fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000, IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params, .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION, .nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
...@@ -229,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { ...@@ -229,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265", .name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE, .fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000, IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params, .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION, .nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
...@@ -239,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = { ...@@ -239,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.name = "Intel(R) Wireless N 7265", .name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE, .fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000, IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params, .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION, .nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
...@@ -247,4 +269,5 @@ const struct iwl_cfg iwl7265_n_cfg = { ...@@ -247,4 +269,5 @@ const struct iwl_cfg iwl7265_n_cfg = {
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_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)); MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
...@@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = { ...@@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = {
}; };
static const struct iwl_ht_params iwl8000_ht_params = { static const struct iwl_ht_params iwl8000_ht_params = {
.ldpc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
}; };
...@@ -115,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = { ...@@ -115,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.max_data_size = IWL60_RTC_DATA_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl8000_base_params, \ .base_params = &iwl8000_base_params, \
.led_mode = IWL_LED_RF_STATE, \ .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 = { const struct iwl_cfg iwl8260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 8260", .name = "Intel(R) Dual Band Wireless AC 8260",
...@@ -135,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { ...@@ -135,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_calib_ver = IWL8000_TX_POWER_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.disable_dummy_notification = true,
}; };
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
...@@ -120,6 +120,8 @@ enum iwl_led_mode { ...@@ -120,6 +120,8 @@ enum iwl_led_mode {
#define IWL_LONG_WD_TIMEOUT 10000 #define IWL_LONG_WD_TIMEOUT 10000
#define IWL_MAX_WD_TIMEOUT 120000 #define IWL_MAX_WD_TIMEOUT 120000
#define IWL_DEFAULT_MAX_TX_POWER 22
/* Antenna presence definitions */ /* Antenna presence definitions */
#define ANT_NONE 0x0 #define ANT_NONE 0x0
#define ANT_A BIT(0) #define ANT_A BIT(0)
...@@ -169,6 +171,7 @@ struct iwl_base_params { ...@@ -169,6 +171,7 @@ struct iwl_base_params {
/* /*
* @stbc: support Tx STBC and 1*SS Rx STBC * @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 * @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/ */
...@@ -176,6 +179,7 @@ struct iwl_ht_params { ...@@ -176,6 +179,7 @@ struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode; enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */ const bool ht_greenfield_support; /* if used set to true */
const bool stbc; const bool stbc;
const bool ldpc;
bool use_rts_for_aggregation; bool use_rts_for_aggregation;
u8 ht40_bands; u8 ht40_bands;
}; };
...@@ -226,6 +230,7 @@ struct iwl_pwr_tx_backoff { ...@@ -226,6 +230,7 @@ struct iwl_pwr_tx_backoff {
* @max_data_size: The maximal length of the fw data section * @max_data_size: The maximal length of the fw data section
* @valid_tx_ant: valid transmit antenna * @valid_tx_ant: valid transmit antenna
* @valid_rx_ant: valid receive antenna * @valid_rx_ant: valid receive antenna
* @non_shared_ant: the antenna that is for WiFi only
* @nvm_ver: NVM version * @nvm_ver: NVM version
* @nvm_calib_ver: NVM calibration version * @nvm_calib_ver: NVM calibration version
* @lib: pointer to the lib ops * @lib: pointer to the lib ops
...@@ -258,6 +263,7 @@ struct iwl_cfg { ...@@ -258,6 +263,7 @@ struct iwl_cfg {
const u32 max_inst_size; const u32 max_inst_size;
u8 valid_tx_ant; u8 valid_tx_ant;
u8 valid_rx_ant; u8 valid_rx_ant;
u8 non_shared_ant;
bool bt_shared_single_ant; bool bt_shared_single_ant;
u16 nvm_ver; u16 nvm_ver;
u16 nvm_calib_ver; u16 nvm_calib_ver;
...@@ -278,6 +284,7 @@ struct iwl_cfg { ...@@ -278,6 +284,7 @@ struct iwl_cfg {
bool no_power_up_nic_in_init; bool no_power_up_nic_in_init;
const char *default_nvm_file; const char *default_nvm_file;
unsigned int max_rx_agg_size; unsigned int max_rx_agg_size;
bool disable_dummy_notification;
}; };
/* /*
...@@ -335,9 +342,11 @@ extern const struct iwl_cfg iwl7260_n_cfg; ...@@ -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_2ac_cfg;
extern const struct iwl_cfg iwl3160_2n_cfg; extern const struct iwl_cfg iwl3160_2n_cfg;
extern const struct iwl_cfg iwl3160_n_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_2ac_cfg;
extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_2n_cfg;
extern const struct iwl_cfg iwl7265_n_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_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */ #endif /* CONFIG_IWLMVM */
......
...@@ -295,6 +295,16 @@ ...@@ -295,6 +295,16 @@
#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0)
#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) #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_MSK (0x000FFF0)
#define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5300 (0x0000020)
#define CSR_HW_REV_TYPE_5350 (0x0000030) #define CSR_HW_REV_TYPE_5350 (0x0000030)
......
...@@ -1363,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)") ...@@ -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, module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
int, S_IRUGO); int, S_IRUGO);
MODULE_PARM_DESC(antenna_coupling, 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_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
MODULE_PARM_DESC(wd_disable, MODULE_PARM_DESC(wd_disable,
......
...@@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ...@@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; 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) if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
......
...@@ -127,6 +127,7 @@ enum iwl_ucode_tlv_flag { ...@@ -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_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_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_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 * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
* longer than the passive one, which is essential for fragmented scan. * longer than the passive one, which is essential for fragmented scan.
*/ */
...@@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api { ...@@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), 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), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
}; };
......
...@@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans) ...@@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans)
* DEVICE_SET_NMI_8000B_REG - is used. * DEVICE_SET_NMI_8000B_REG - is used.
*/ */
if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || 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); iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
else else
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
......
...@@ -148,8 +148,6 @@ static const u8 iwl_nvm_channels_family_8000[] = { ...@@ -148,8 +148,6 @@ static const u8 iwl_nvm_channels_family_8000[] = {
#define LAST_2GHZ_HT_PLUS 9 #define LAST_2GHZ_HT_PLUS 9
#define LAST_5GHZ_HT 161 #define LAST_5GHZ_HT 161
#define DEFAULT_MAX_TX_POWER 16
/* rate data (static) */ /* rate data (static) */
static struct ieee80211_rate iwl_cfg80211_rates[] = { static struct ieee80211_rate iwl_cfg80211_rates[] = {
{ .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, { .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, ...@@ -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 * Default value - highest tx power value. max_power
* is not used in mvm, and is used for backwards compatibility * 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; is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
IWL_DEBUG_EEPROM(dev, IWL_DEBUG_EEPROM(dev,
"Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", "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, ...@@ -336,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_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) if (num_tx_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
else else
......
...@@ -377,6 +377,7 @@ enum iwl_trans_status { ...@@ -377,6 +377,7 @@ enum iwl_trans_status {
* if unset 4k will be the RX buffer size * 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 * @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes) * 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 * @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart * are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries * @command_names: array of command names, must be 256 entries
...@@ -392,6 +393,7 @@ struct iwl_trans_config { ...@@ -392,6 +393,7 @@ struct iwl_trans_config {
bool rx_buf_size_8k; bool rx_buf_size_8k;
bool bc_table_dword; bool bc_table_dword;
bool scd_set_active;
unsigned int queue_watchdog_timeout; unsigned int queue_watchdog_timeout;
const char *const *command_names; const char *const *command_names;
}; };
...@@ -826,12 +828,6 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, ...@@ -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); 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, static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
u32 txq_bm) u32 txq_bm)
{ {
......
...@@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o ...@@ -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 += 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 += scan.o time-event.o rs.o
iwlmvm-y += power.o coex.o coex_legacy.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_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
......
...@@ -587,8 +587,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -587,8 +587,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
u32 mode;
switch (mvm->bt_force_ant_mode) { switch (mvm->bt_force_ant_mode) {
case BT_FORCE_ANT_BT: case BT_FORCE_ANT_BT:
mode = BT_COEX_BT; mode = BT_COEX_BT;
...@@ -758,7 +756,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -758,7 +756,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct iwl_bt_iterator_data *data = _data; struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm; struct iwl_mvm *mvm = data->mvm;
struct ieee80211_chanctx_conf *chanctx_conf; 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; u32 bt_activity_grading;
int ave_rssi; int ave_rssi;
...@@ -766,8 +765,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -766,8 +765,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
/* default smps_mode for BSS / P2P client is AUTOMATIC */
smps_mode = IEEE80211_SMPS_AUTOMATIC;
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
if (!mvmvif->ap_ibss_active) if (!mvmvif->ap_ibss_active)
...@@ -799,7 +796,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -799,7 +796,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
else if (bt_activity_grading >= BT_LOW_TRAFFIC) else if (bt_activity_grading >= BT_LOW_TRAFFIC)
smps_mode = IEEE80211_SMPS_DYNAMIC; smps_mode = IEEE80211_SMPS_DYNAMIC;
/* relax SMPS contraints for next association */ /* relax SMPS constraints for next association */
if (!vif->bss_conf.assoc) if (!vif->bss_conf.assoc)
smps_mode = IEEE80211_SMPS_AUTOMATIC; smps_mode = IEEE80211_SMPS_AUTOMATIC;
...@@ -1149,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, ...@@ -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) 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)) 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); return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
......
...@@ -65,12 +65,18 @@ ...@@ -65,12 +65,18 @@
#ifndef __MVM_CONSTANTS_H #ifndef __MVM_CONSTANTS_H
#define __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_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_DEFAULT_PS_RX_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_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_RX_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_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_TX_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_TX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
...@@ -86,5 +92,7 @@ ...@@ -86,5 +92,7 @@
#define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_CORUNNING 1
#define IWL_MVM_BT_COEX_MPLUT 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 */ #endif /* __MVM_CONSTANTS_H */
...@@ -76,8 +76,7 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, ...@@ -76,8 +76,7 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
switch (param) { switch (param) {
case MVM_DEBUGFS_PM_KEEP_ALIVE: { case MVM_DEBUGFS_PM_KEEP_ALIVE: {
struct ieee80211_hw *hw = mvm->hw; int dtimper = vif->bss_conf.dtim_period ?: 1;
int dtimper = hw->conf.ps_dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int; int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
......
...@@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, ...@@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
{ {
int temperature; int temperature;
if (!mvm->ucode_loaded && !mvm->temperature_test)
return -EIO;
if (kstrtoint(buf, 10, &temperature)) if (kstrtoint(buf, 10, &temperature))
return -EINVAL; return -EINVAL;
/* not a legal temperature */ /* not a legal temperature */
...@@ -1256,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, ...@@ -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_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER); 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); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos); return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
......
...@@ -205,6 +205,10 @@ enum { ...@@ -205,6 +205,10 @@ enum {
REPLY_SF_CFG_CMD = 0xd1, REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2, REPLY_BEACON_FILTERING_CMD = 0xd2,
/* DTS measurements */
CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
DTS_MEASUREMENT_NOTIFICATION = 0xdd,
REPLY_DEBUG_CMD = 0xf0, REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7, DEBUG_LOG_MSG = 0xf7,
...@@ -550,7 +554,7 @@ enum iwl_time_event_type { ...@@ -550,7 +554,7 @@ enum iwl_time_event_type {
TE_WIDI_TX_SYNC, TE_WIDI_TX_SYNC,
/* Channel Switch NoA */ /* Channel Switch NoA */
TE_P2P_GO_CSA_NOA, TE_CHANNEL_SWITCH_PERIOD,
TE_MAX TE_MAX
}; /* MAC_EVENT_TYPE_API_E_VER_1 */ }; /* MAC_EVENT_TYPE_API_E_VER_1 */
...@@ -1601,19 +1605,49 @@ enum iwl_sf_scenario { ...@@ -1601,19 +1605,49 @@ enum iwl_sf_scenario {
#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
#define SF_CFG_DUMMY_NOTIF_OFF BIT(16)
/** /**
* Smart Fifo configuration command. * 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. * @watermark: Minimum allowed availabe free space in RXF for transient state.
* @long_delay_timeouts: aging and idle timer values for each scenario * @long_delay_timeouts: aging and idle timer values for each scenario
* in long delay state. * in long delay state.
* @full_on_timeouts: timer values for each scenario in full on state. * @full_on_timeouts: timer values for each scenario in full on state.
*/ */
struct iwl_sf_cfg_cmd { struct iwl_sf_cfg_cmd {
enum iwl_sf_state state; __le32 state;
__le32 watermark[SF_TRANSIENT_STATES_NUMBER]; __le32 watermark[SF_TRANSIENT_STATES_NUMBER];
__le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
__le32 full_on_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 */ } __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__ */ #endif /* __fw_api_h__ */
...@@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); 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 */ /* Add auxiliary station for scanning */
ret = iwl_mvm_add_aux_sta(mvm); ret = iwl_mvm_add_aux_sta(mvm);
if (ret) if (ret)
......
...@@ -727,11 +727,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, ...@@ -727,11 +727,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
!force_assoc_off) { !force_assoc_off) {
u32 dtim_offs; 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 * The DTIM count counts down, so when it is N that means N
* more beacon intervals happen until the DTIM TBTT. Therefore * 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, ...@@ -765,6 +760,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
ctxt_sta->is_assoc = cpu_to_le32(1); ctxt_sta->is_assoc = cpu_to_le32(1);
} else { } else {
ctxt_sta->is_assoc = cpu_to_le32(0); 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); 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, ...@@ -1234,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
!iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
u32 rel_time = (c + 1) * u32 rel_time = (c + 1) *
csa_vif->bss_conf.beacon_int - csa_vif->bss_conf.beacon_int -
IWL_MVM_CHANNEL_SWITCH_TIME; IWL_MVM_CHANNEL_SWITCH_TIME_GO;
u32 apply_time = gp2 + rel_time * 1024; u32 apply_time = gp2 + rel_time * 1024;
iwl_mvm_schedule_csa_noa(mvm, csa_vif, iwl_mvm_schedule_csa_period(mvm, csa_vif,
IWL_MVM_CHANNEL_SWITCH_TIME - IWL_MVM_CHANNEL_SWITCH_TIME_GO -
IWL_MVM_CHANNEL_SWITCH_MARGIN, IWL_MVM_CHANNEL_SWITCH_MARGIN,
apply_time); apply_time);
} }
} else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
/* we don't have CSA NoA scheduled yet, switch now */ /* we don't have CSA NoA scheduled yet, switch now */
......
...@@ -327,7 +327,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -327,7 +327,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 &&
!iwlwifi_mod_params.uapsd_disable) { !iwlwifi_mod_params.uapsd_disable) {
hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; 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; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
} }
...@@ -398,12 +398,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -398,12 +398,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
else else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/* TODO: enable that only for firmwares that don't crash */ if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) {
/* hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; */ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
/* we create the 802.11 header and zero length SSID IE. */ /* 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->max_sched_scan_ie_len =
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
}
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN | NL80211_FEATURE_LOW_PRIORITY_SCAN |
...@@ -668,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, ...@@ -668,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS #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_file *dump_file;
struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info; struct iwl_fw_error_dump_info *dump_info;
...@@ -761,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -761,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
file_len += fw_error_dump->trans_ptr->len; file_len += fw_error_dump->trans_ptr->len;
dump_file->file_len = cpu_to_le32(file_len); dump_file->file_len = cpu_to_le32(file_len);
mvm->fw_error_dump = fw_error_dump; 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 #endif
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) 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); 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); iwl_trans_stop_device(mvm->trans);
mvm->scan_status = IWL_MVM_SCAN_NONE; mvm->scan_status = IWL_MVM_SCAN_NONE;
...@@ -813,12 +812,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ...@@ -813,12 +812,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->rx_ba_sessions = 0; 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; int ret;
mutex_lock(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* Clean up some internal and mac80211 state on restart */ /* Clean up some internal and mac80211 state on restart */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 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) ...@@ -835,6 +833,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
iwl_mvm_d0i3_enable_tx(mvm, NULL); 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); mutex_unlock(&mvm->mutex);
return ret; return ret;
...@@ -860,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) ...@@ -860,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
mutex_unlock(&mvm->mutex); 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); lockdep_assert_held(&mvm->mutex);
flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
mutex_lock(&mvm->mutex);
/* disallow low power states when the FW is down */ /* disallow low power states when the FW is down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
...@@ -888,6 +891,19 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) ...@@ -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 */ /* the fw is stopped, the aux sta is dead: clean up driver state */
iwl_mvm_del_aux_sta(mvm); 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); mutex_unlock(&mvm->mutex);
/* /*
...@@ -1196,14 +1212,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, ...@@ -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_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mcast_filter_cmd *cmd; struct iwl_mcast_filter_cmd *cmd;
struct netdev_hw_addr *addr; struct netdev_hw_addr *addr;
int addr_count = netdev_hw_addr_list_count(mc_list); int addr_count;
bool pass_all = false; bool pass_all;
int len; int len;
if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { addr_count = netdev_hw_addr_list_count(mc_list);
pass_all = true; pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||
IWL_MVM_FW_MCAST_FILTER_PASS_ALL;
if (pass_all)
addr_count = 0; addr_count = 0;
}
len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
cmd = kzalloc(len, GFP_ATOMIC); cmd = kzalloc(len, GFP_ATOMIC);
...@@ -1403,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, ...@@ -1403,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
} }
#endif #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, static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
...@@ -1544,11 +1539,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ...@@ -1544,11 +1539,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/ */
iwl_mvm_remove_time_event(mvm, mvmvif, iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data); &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) { if (changes & BSS_CHANGED_BEACON_INFO) {
...@@ -1556,6 +1546,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ...@@ -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)); 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) { if (changes & BSS_CHANGED_TXPOWER) {
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
bss_conf->txpower); bss_conf->txpower);
...@@ -1721,7 +1717,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, ...@@ -1721,7 +1717,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
return; return;
if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | 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_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); 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, ...@@ -1952,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex); 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, static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
...@@ -2167,27 +2121,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, ...@@ -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); 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, static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req, struct cfg80211_sched_scan_request *req,
......
...@@ -87,11 +87,11 @@ ...@@ -87,11 +87,11 @@
/* A TimeUnit is 1024 microsecond */ /* A TimeUnit is 1024 microsecond */
#define MSEC_TO_TU(_msec) (_msec*1000/1024) #define MSEC_TO_TU(_msec) (_msec*1000/1024)
/* /* This value represents the number of TUs before CSA "beacon 0" TBTT
* The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" * when the CSA time-event needs to be scheduled to start. It must be
* TBTT. This value should be big enough to ensure that we switch in time. * 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 * This value (in TUs) is used to fine tune the CSA NoA end time which should
...@@ -180,10 +180,6 @@ enum iwl_power_scheme { ...@@ -180,10 +180,6 @@ enum iwl_power_scheme {
}; };
#define IWL_CONN_MAX_LISTEN_INTERVAL 10 #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 #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
...@@ -274,6 +270,8 @@ enum iwl_mvm_ref_type { ...@@ -274,6 +270,8 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TM_CMD, IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_EXIT_WORK,
/* update debugfs.c when changing this */
IWL_MVM_REF_COUNT, IWL_MVM_REF_COUNT,
}; };
...@@ -649,6 +647,7 @@ struct iwl_mvm { ...@@ -649,6 +647,7 @@ struct iwl_mvm {
/* -1 for always, 0 for never, >0 for that many times */ /* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw; s8 restart_fw;
struct work_struct fw_error_dump_wk;
struct iwl_mvm_dump_ptrs *fw_error_dump; struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
...@@ -709,6 +708,8 @@ struct iwl_mvm { ...@@ -709,6 +708,8 @@ struct iwl_mvm {
*/ */
bool temperature_test; /* Debug test temperature is enabled */ bool temperature_test; /* Debug test temperature is enabled */
struct iwl_time_quota_cmd last_quota_cmd;
#ifdef CONFIG_NL80211_TESTMODE #ifdef CONFIG_NL80211_TESTMODE
u32 noa_duration; u32 noa_duration;
struct ieee80211_vif *noa_vif; struct ieee80211_vif *noa_vif;
...@@ -788,6 +789,9 @@ struct iwl_rate_info { ...@@ -788,6 +789,9 @@ struct iwl_rate_info {
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ 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 * MVM Methods
******************/ ******************/
...@@ -1153,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -1153,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* TDLS */ /* TDLS */
int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); 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); 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__ */ #endif /* __IWL_MVM_H__ */
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
*****************************************************************************/ *****************************************************************************/
#include <linux/firmware.h> #include <linux/firmware.h>
#include "iwl-trans.h" #include "iwl-trans.h"
#include "iwl-csr.h"
#include "mvm.h" #include "mvm.h"
#include "iwl-eeprom-parse.h" #include "iwl-eeprom-parse.h"
#include "iwl-eeprom-read.h" #include "iwl-eeprom-read.h"
...@@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) ...@@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
/* Maximal size depends on HW family and step */ /* Maximal size depends on HW family and step */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
max_section_size = IWL_MAX_NVM_SECTION_SIZE; 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; max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
else /* Family 8000 B-step */ else /* Family 8000 B-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
......
...@@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { ...@@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BCAST_FILTER_CMD), CMD(BCAST_FILTER_CMD),
CMD(REPLY_SF_CFG_CMD), CMD(REPLY_SF_CFG_CMD),
CMD(REPLY_BEACON_FILTERING_CMD), CMD(REPLY_BEACON_FILTERING_CMD),
CMD(CMD_DTS_MEASUREMENT_TRIGGER),
CMD(DTS_MEASUREMENT_NOTIFICATION),
CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE), CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI), CMD(BT_COEX_CI),
...@@ -364,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) ...@@ -364,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
return 0; return 0;
} }
static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
static struct iwl_op_mode * static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir) 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, ...@@ -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->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_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->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->d0i3_tx_lock);
spin_lock_init(&mvm->refs_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, ...@@ -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_queue = IWL_MVM_CMD_QUEUE;
trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
trans_cfg.scd_set_active = true;
snprintf(mvm->hw->wiphy->fw_version, snprintf(mvm->hw->wiphy->fw_version,
sizeof(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) ...@@ -781,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
module_put(THIS_MODULE); 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) void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
{ {
iwl_abort_notification_waits(&mvm->notif_wait); iwl_abort_notification_waits(&mvm->notif_wait);
...@@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) ...@@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
if (fw_error && mvm->restart_fw > 0) if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--; mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw); ieee80211_restart_hw(mvm->hw);
} else if (fw_error) {
schedule_work(&mvm->fw_error_dump_wk);
} }
} }
......
...@@ -286,13 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, ...@@ -286,13 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
return true; 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, static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd) 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 dtimper, dtimper_msec;
int keep_alive; int keep_alive;
bool radar_detect = false; bool radar_detect = false;
...@@ -301,7 +316,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -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, cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color)); mvmvif->color));
dtimper = hw->conf.ps_dtim_period ?: 1; dtimper = vif->bss_conf.dtim_period;
/* /*
* Regardless of power management state the driver must set * Regardless of power management state the driver must set
...@@ -321,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -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); cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || 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; return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 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, ...@@ -334,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
} }
/* Check if radar detection is required on current channel */ /* Check if radar detection is required on current channel */
rcu_read_lock(); radar_detect = iwl_mvm_power_is_radar(vif);
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();
/* Check skip over DTIM conditions */ /* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) && if (!radar_detect && (dtimper <= 10) &&
...@@ -502,8 +510,6 @@ struct iwl_power_vifs { ...@@ -502,8 +510,6 @@ struct iwl_power_vifs {
bool bss_active; bool bss_active;
bool ap_active; bool ap_active;
bool monitor_active; bool monitor_active;
bool bss_tdls;
bool p2p_tdls;
}; };
static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, 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, ...@@ -558,8 +564,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */ /* only a single MAC of the same type */
WARN_ON(power_iterator->p2p_vif); WARN_ON(power_iterator->p2p_vif);
power_iterator->p2p_vif = 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)
if (mvmvif->phy_ctxt->id < MAX_PHYS) if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->p2p_active = true; power_iterator->p2p_active = true;
...@@ -569,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, ...@@ -569,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */ /* only a single MAC of the same type */
WARN_ON(power_iterator->bss_vif); WARN_ON(power_iterator->bss_vif);
power_iterator->bss_vif = 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)
if (mvmvif->phy_ctxt->id < MAX_PHYS) if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->bss_active = true; power_iterator->bss_active = true;
...@@ -613,15 +615,13 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, ...@@ -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); ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
/* enable PM on bss if bss stand alone */ /* enable PM on bss if bss stand alone */
if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
!vifs->bss_tdls) {
bss_mvmvif->pm_enabled = true; bss_mvmvif->pm_enabled = true;
return; return;
} }
/* enable PM on p2p if p2p stand alone */ /* enable PM on p2p if p2p stand alone */
if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
!vifs->p2p_tdls) {
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
p2p_mvmvif->pm_enabled = true; p2p_mvmvif->pm_enabled = true;
return; return;
...@@ -962,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, ...@@ -962,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_build_cmd(mvm, vif, &cmd);
if (enable) { if (enable) {
/* configure skip over dtim up to 300 msec */ /* configure skip over dtim up to 306TU - 314 msec */
int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; int dtimper = vif->bss_conf.dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int; 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; return 0;
cmd.skip_dtim_periods = 300 / dtimper_msec; /* Check skip over DTIM conditions */
if (cmd.skip_dtim_periods) /* TODO: check that multicast wake lock is off */
cmd.flags |= if (!radar_detect && (dtimper < 10)) {
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); 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); iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
......
...@@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, ...@@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
struct ieee80211_vif *disabled_vif) struct ieee80211_vif *disabled_vif)
{ {
struct iwl_time_quota_cmd cmd = {}; 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 = { struct iwl_mvm_quota_iterator_data data = {
.n_interfaces = {}, .n_interfaces = {},
.colors = { -1, -1, -1, -1 }, .colors = { -1, -1, -1, -1 },
.disabled_vif = disabled_vif, .disabled_vif = disabled_vif,
}; };
struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
bool send = false;
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
...@@ -293,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, ...@@ -293,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
/* check that we have non-zero quota for all valid bindings */ /* check that we have non-zero quota for all valid bindings */
for (i = 0; i < MAX_BINDINGS; i++) { 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)) if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
continue; continue;
WARN_ONCE(cmd.quotas[i].quota == 0, WARN_ONCE(cmd.quotas[i].quota == 0,
"zero quota on binding %d\n", i); "zero quota on binding %d\n", i);
} }
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, if (!send) {
sizeof(cmd), &cmd); /* don't send a practically unchanged command, the firmware has
if (ret) * to re-initialize a lot of state and that can have an adverse
IWL_ERR(mvm, "Failed to send quota: %d\n", ret); * impact on it
return ret; */
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;
} }
...@@ -505,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) ...@@ -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, static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix) 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), prefix, rs_pretty_lq_type(rate->type),
rate->index, rs_pretty_ant(rate->ant), 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) 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, ...@@ -672,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
return -EINVAL; return -EINVAL;
if (tbl->column != RS_COLUMN_INVALID) { if (tbl->column != RS_COLUMN_INVALID) {
lq_sta->tx_stats[tbl->column][scale_index].total += attempts; struct lq_sta_pers *pers = &lq_sta->pers;
lq_sta->tx_stats[tbl->column][scale_index].success += successes;
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 */ /* Select window for current tx bit rate */
...@@ -742,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, ...@@ -742,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
ucode_rate |= rate->bw; ucode_rate |= rate->bw;
if (rate->sgi) if (rate->sgi)
ucode_rate |= RATE_MCS_SGI_MSK; ucode_rate |= RATE_MCS_SGI_MSK;
if (rate->ldpc)
ucode_rate |= RATE_MCS_LDPC_MSK;
return ucode_rate; return ucode_rate;
} }
...@@ -779,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, ...@@ -779,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
/* HT or VHT */ /* HT or VHT */
if (ucode_rate & RATE_MCS_SGI_MSK) if (ucode_rate & RATE_MCS_SGI_MSK)
rate->sgi = true; rate->sgi = true;
if (ucode_rate & RATE_MCS_LDPC_MSK)
rate->ldpc = true;
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; 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, ...@@ -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 > IWL_RATE_MCS_9_INDEX);
rate->index = rs_ht_to_legacy[rate->index]; rate->index = rs_ht_to_legacy[rate->index];
rate->ldpc = false;
} else { } else {
/* Downgrade to SISO with same MCS if in MIMO */ /* Downgrade to SISO with same MCS if in MIMO */
rate->type = is_vht_mimo2(rate) ? rate->type = is_vht_mimo2(rate) ?
LQ_VHT_SISO : LQ_HT_SISO; LQ_VHT_SISO : LQ_HT_SISO;
} }
if (num_of_ant(rate->ant) > 1) if (num_of_ant(rate->ant) > 1)
rate->ant = first_antenna(mvm->fw->valid_tx_ant); rate->ant = first_antenna(mvm->fw->valid_tx_ant);
...@@ -1621,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, ...@@ -1621,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
} }
rate->bw = rs_bw_from_sta_bw(sta); rate->bw = rs_bw_from_sta_bw(sta);
rate->ldpc = lq_sta->ldpc;
search_tbl->column = col_id; search_tbl->column = col_id;
rs_set_expected_tpt_table(lq_sta, search_tbl); rs_set_expected_tpt_table(lq_sta, search_tbl);
...@@ -2031,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, ...@@ -2031,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
return; return;
} }
/* force user max rate if set by user */ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
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;
}
window = &(tbl->win[index]); window = &(tbl->win[index]);
/* /*
...@@ -2130,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, ...@@ -2130,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
low = high_low & 0xff; low = high_low & 0xff;
high = (high_low >> 8) & 0xff; high = (high_low >> 8) & 0xff;
/* If user set max rate, dont allow higher than user constrain */ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
if ((lq_sta->max_rate_idx != -1) &&
(lq_sta->max_rate_idx < high))
high = IWL_RATE_INVALID;
sr = window->success_ratio; sr = window->success_ratio;
...@@ -2342,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, ...@@ -2342,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rate->index = i; rate->index = i;
rate->ant = first_antenna(valid_tx_ant); rate->ant = first_antenna(valid_tx_ant);
rate->sgi = false; rate->sgi = false;
rate->ldpc = false;
rate->bw = RATE_MCS_CHAN_WIDTH_20; rate->bw = RATE_MCS_CHAN_WIDTH_20;
if (band == IEEE80211_BAND_5GHZ) if (band == IEEE80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A; rate->type = LQ_LEGACY_A;
...@@ -2364,23 +2358,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, ...@@ -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 ieee80211_tx_rate_control *txrc)
{ {
struct sk_buff *skb = txrc->skb; 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 *op_mode __maybe_unused =
(struct iwl_op_mode *)mvm_r; (struct iwl_op_mode *)mvm_r;
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = mvm_sta; struct iwl_lq_sta *lq_sta = mvm_sta;
/* Get max rate if user set max rate */ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
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;
}
/* Treat uninitialized rate scaling data same as non-existing. */ /* Treat uninitialized rate scaling data same as non-existing. */
if (lq_sta && !lq_sta->pers.drv) { 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, ...@@ -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 * previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */ * after assoc.. */
lq_sta->max_rate_idx = -1;
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
lq_sta->band = sband->band; lq_sta->band = sband->band;
/* /*
...@@ -2610,9 +2593,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -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->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
lq_sta->is_vht = false; lq_sta->is_vht = false;
if (mvm->cfg->ht_params->ldpc &&
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
lq_sta->ldpc = true;
} else { } else {
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
lq_sta->is_vht = true; 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, 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, ...@@ -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, lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
BITS_PER_LONG); 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_legacy_rate,
lq_sta->active_siso_rate, lq_sta->active_siso_rate,
lq_sta->active_mimo2_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", IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx, lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx, lq_sta->max_siso_rate_idx,
...@@ -3032,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ...@@ -3032,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(is_ht20(rate)) ? "20MHz" : (is_ht20(rate)) ? "20MHz" :
(is_ht40(rate)) ? "40MHz" : (is_ht40(rate)) ? "40MHz" :
(is_ht80(rate)) ? "80Mhz" : "BAD BW"); (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->sgi) ? "SGI" : "NGI",
(rate->ldpc) ? "LDPC" : "BCC",
(lq_sta->is_agg) ? "AGG on" : ""); (lq_sta->is_agg) ? "AGG on" : "");
} }
desc += sprintf(buff+desc, "last tx rate=0x%X\n", 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, ...@@ -3181,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file,
"%s,", column_name[col]); "%s,", column_name[col]);
for (rate = 0; rate < IWL_RATE_COUNT; rate++) { 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, pos += scnprintf(pos, endpos - pos,
"%llu/%llu,", "%llu/%llu,",
stats->success, stats->success,
...@@ -3200,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, ...@@ -3200,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct iwl_lq_sta *lq_sta = file->private_data; 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; return count;
} }
......
...@@ -207,6 +207,7 @@ struct rs_rate { ...@@ -207,6 +207,7 @@ struct rs_rate {
u8 ant; u8 ant;
u32 bw; u32 bw;
bool sgi; bool sgi;
bool ldpc;
}; };
...@@ -329,10 +330,9 @@ struct iwl_lq_sta { ...@@ -329,10 +330,9 @@ struct iwl_lq_sta {
*/ */
u64 last_tx; u64 last_tx;
bool is_vht; bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */
enum ieee80211_band band; 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. */ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
unsigned long active_legacy_rate; unsigned long active_legacy_rate;
unsigned long active_siso_rate; unsigned long active_siso_rate;
...@@ -343,7 +343,6 @@ struct iwl_lq_sta { ...@@ -343,7 +343,6 @@ struct iwl_lq_sta {
u8 max_siso_rate_idx; u8 max_siso_rate_idx;
u8 max_mimo2_rate_idx; u8 max_mimo2_rate_idx;
s8 max_rate_idx; /* Max rate set by user */
u8 missed_rate_counter; u8 missed_rate_counter;
struct iwl_lq_cmd lq; struct iwl_lq_cmd lq;
...@@ -361,11 +360,14 @@ struct iwl_lq_sta { ...@@ -361,11 +360,14 @@ struct iwl_lq_sta {
int tpc_reduce; int tpc_reduce;
/* persistent fields - initialized only once - keep last! */ /* persistent fields - initialized only once - keep last! */
struct { struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
u32 dbg_fixed_rate; u32 dbg_fixed_rate;
u8 dbg_fixed_txp_reduction; u8 dbg_fixed_txp_reduction;
#endif #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; struct iwl_mvm *drv;
} pers; } pers;
}; };
......
...@@ -151,13 +151,13 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, ...@@ -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]); 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) >> energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >>
IWL_RX_INFO_ENERGY_ANT_A_POS; 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) >> energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
IWL_RX_INFO_ENERGY_ANT_B_POS; 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) >> energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >>
IWL_RX_INFO_ENERGY_ANT_C_POS; 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(energy_a, energy_b);
max_energy = max(max_energy, energy_c); max_energy = max(max_energy, energy_c);
......
...@@ -160,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, ...@@ -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) static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
{ {
if (band == IEEE80211_BAND_2GHZ) if (band == IEEE80211_BAND_2GHZ)
return 30 + 3 * (n_ssids + 1); return 20 + 3 * (n_ssids + 1);
return 20 + 2 * (n_ssids + 1); return 10 + 2 * (n_ssids + 1);
} }
static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
......
...@@ -174,11 +174,15 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, ...@@ -174,11 +174,15 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
enum iwl_sf_state new_state) enum iwl_sf_state new_state)
{ {
struct iwl_sf_cfg_cmd sf_cmd = { struct iwl_sf_cfg_cmd sf_cmd = {
.state = new_state, .state = cpu_to_le32(new_state),
}; };
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
int ret = 0; 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 * If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered. * will remain FULL_ON but SF parameters need to be reconsidered.
......
...@@ -948,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -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->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); iwl_trans_txq_disable(mvm->trans, txq_id, true);
/* fall through */ return 0;
case IWL_AGG_STARTING: case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA: 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, ...@@ -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)) if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); 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); iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
} }
......
/******************************************************************************
*
* 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);
}
...@@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) ...@@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
iwl_mvm_roc_finished(mvm); iwl_mvm_roc_finished(mvm);
} }
int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u32 duration, u32 apply_time) u32 duration, u32 apply_time)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; 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, ...@@ -711,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (te_data->running) { 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; return -EBUSY;
} }
time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
time_cmd.id_and_color = time_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->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.apply_time = cpu_to_le32(apply_time);
time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.max_frags = TE_V2_FRAG_NONE;
time_cmd.duration = cpu_to_le32(duration); time_cmd.duration = cpu_to_le32(duration);
......
...@@ -219,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, ...@@ -219,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
void iwl_mvm_roc_done_wk(struct work_struct *wk); 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 * @mvm: the mvm component
* @vif: the virtual interface for which the channel switch is issued * @vif: the virtual interface for which the channel switch is issued
* @duration: the duration of the NoA in TU. * @duration: the duration of the NoA in TU.
...@@ -228,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk); ...@@ -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 * This function is used to schedule NoA time event and is used to perform
* the channel switch flow. * the channel switch flow.
*/ */
int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u32 duration, u32 apply_time); u32 duration, u32 apply_time);
/** /**
* iwl_mvm_te_scheduled - check if the fw received the TE cmd * iwl_mvm_te_scheduled - check if the fw received the TE cmd
......
...@@ -69,275 +69,99 @@ ...@@ -69,275 +69,99 @@
#include "iwl-csr.h" #include "iwl-csr.h"
#include "iwl-prph.h" #include "iwl-prph.h"
#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
/* 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 CALC_VREFS_MIN_DIFF 43 static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
#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)
{ {
struct iwl_nvm_section calib_sec; u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
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;
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) IWL_ERR(mvm, "Enter CT Kill\n");
vbg = MEAS_VBG_DEFAULT_VAL; 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; if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
u8 ptat, pa1, pa2, median; return;
/* 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;
}
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: */ struct iwl_mvm *mvm =
s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(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) notif = (void *)pkt->data;
new_val = PTAT_DIGITAL_VALUE_MAX_VALUE;
else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE)
new_val = PTAT_DIGITAL_VALUE_MIN_VALUE;
return new_val; *temp = le32_to_cpu(notif->temp);
}
static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, /* shouldn't be negative, but since it's s32, make sure it isn't */
union dts_diode_results *avg_ptat) if (WARN_ON_ONCE(*temp < 0))
{ *temp = 0;
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, &reg, 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;
}
/* IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp);
* return true it the results are valid, and false otherwise. return true;
*/
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);
} }
static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
u16 volt_band_gap)
{ {
u32 tmp_result; struct iwl_dts_measurement_cmd cmd = {
u8 vrefs_diff; .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
/*
* 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,
}; };
/* return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0,
* The diff between the high and low voltage-references is assumed sizeof(cmd), &cmd);
* 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);
} }
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)) lockdep_assert_held(&mvm->mutex);
return;
IWL_ERR(mvm, "Enter CT Kill\n"); iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
iwl_mvm_set_hw_ctkill_state(mvm, true); temp_notif, ARRAY_SIZE(temp_notif),
iwl_mvm_temp_notif, &temp);
/* Don't schedule an exit work if we're in test mode, since ret = iwl_mvm_get_temp_cmd(mvm);
* the temperature will not change unless we manually set it if (ret) {
* again (or disable testing). IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
*/ iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
if (!mvm->temperature_test) return ret;
schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, }
round_jiffies_relative(duration * HZ));
}
static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
{ IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) if (ret) {
return; IWL_ERR(mvm, "Getting the temperature timed out\n");
return ret;
}
IWL_ERR(mvm, "Exit CT Kill\n"); return temp;
iwl_mvm_set_hw_ctkill_state(mvm, false);
} }
static void check_exit_ctkill(struct work_struct *work) static void check_exit_ctkill(struct work_struct *work)
...@@ -352,28 +176,36 @@ 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; 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 */ /* 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; goto reschedule;
}
iwl_trans_start_hw(mvm->trans); temp = iwl_mvm_get_temp(mvm);
temp = check_nic_temperature(mvm);
iwl_trans_stop_device(mvm->trans);
iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { __iwl_mvm_mac_stop(mvm);
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
if (temp < 0)
goto reschedule; goto reschedule;
}
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
if (temp <= tt->params->ct_kill_exit) { if (temp <= tt->params->ct_kill_exit) {
mutex_unlock(&mvm->mutex);
iwl_mvm_exit_ctkill(mvm); iwl_mvm_exit_ctkill(mvm);
return; return;
} }
reschedule: reschedule:
mutex_unlock(&mvm->mutex);
schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
round_jiffies(duration * HZ)); round_jiffies(duration * HZ));
} }
......
...@@ -170,10 +170,14 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, ...@@ -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 * 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->initial_rate_index = 0;
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
return; return;
...@@ -209,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, ...@@ -209,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
if (info->band == IEEE80211_BAND_2GHZ && if (info->band == IEEE80211_BAND_2GHZ &&
!iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) !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 else
rate_flags = rate_flags =
BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
......
...@@ -354,11 +354,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -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, 0x8060, iwl3160_2n_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)},
{IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_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, 0x8470, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)}, {IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x1170, 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 */ /* 7265 Series */
{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5110, 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[] = { ...@@ -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(0x095B, 0x5202, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9012, 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, 0x9110, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9210, 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[] = { ...@@ -398,6 +405,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 8000 Series */ /* 8000 Series */
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
#endif /* CONFIG_IWLMVM */ #endif /* CONFIG_IWLMVM */
......
...@@ -257,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) ...@@ -257,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @cmd_queue - command queue number * @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size * @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @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 * @rx_page_order: page order for receive buffer size
* @wd_timeout: queue watchdog timeout (jiffies) * @wd_timeout: queue watchdog timeout (jiffies)
* @reg_lock: protect hw register access * @reg_lock: protect hw register access
...@@ -306,6 +307,7 @@ struct iwl_trans_pcie { ...@@ -306,6 +307,7 @@ struct iwl_trans_pcie {
bool rx_buf_size_8k; bool rx_buf_size_8k;
bool bc_table_dword; bool bc_table_dword;
bool scd_set_active;
u32 rx_page_order; u32 rx_page_order;
const char *const *command_names; const char *const *command_names;
......
...@@ -640,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, ...@@ -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); err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
if (reclaim) { if (reclaim) {
kfree(txq->entries[cmd_index].free_buf); kzfree(txq->entries[cmd_index].free_buf);
txq->entries[cmd_index].free_buf = NULL; txq->entries[cmd_index].free_buf = NULL;
} }
......
...@@ -1171,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, ...@@ -1171,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->command_names = trans_cfg->command_names; trans_pcie->command_names = trans_cfg->command_names;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; 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 /* Initialize NAPI here - it should be before registering to mac80211
* in the opmode but after the HW struct is allocated. * 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, ...@@ -2189,7 +2190,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
*/ */
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
trans->hw_rev = (trans->hw_rev & 0xfff0) | 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; trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
......
...@@ -620,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) ...@@ -620,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
if (txq_id == trans_pcie->cmd_queue) if (txq_id == trans_pcie->cmd_queue)
for (i = 0; i < txq->q.n_window; i++) { for (i = 0; i < txq->q.n_window; i++) {
kfree(txq->entries[i].cmd); kzfree(txq->entries[i].cmd);
kfree(txq->entries[i].free_buf); kzfree(txq->entries[i].free_buf);
} }
/* De-alloc circular buffer of TFDs */ /* 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, ...@@ -1080,7 +1080,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
fifo = cfg->fifo; fifo = cfg->fifo;
/* Disable the scheduler prior configuring the cmd queue */ /* 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); iwl_scd_enable_set_active(trans, 0);
/* Stop this Tx queue before configuring it */ /* 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, ...@@ -1142,7 +1143,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
SCD_QUEUE_STTS_REG_MSK); SCD_QUEUE_STTS_REG_MSK);
/* enable the scheduler for this queue (only) */ /* 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)); iwl_scd_enable_set_active(trans, BIT(txq_id));
} }
...@@ -1407,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, ...@@ -1407,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
out_meta->flags = cmd->flags; out_meta->flags = cmd->flags;
if (WARN_ON_ONCE(txq->entries[idx].free_buf)) 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; txq->entries[idx].free_buf = dup_buf;
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment