Commit ef16ea32 authored by John W. Linville's avatar John W. Linville

Merge tag 'iwlwifi-next-for-john-2014-11-24' of...

Merge tag 'iwlwifi-next-for-john-2014-11-24' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

Emmanuel Grumbach <egrumbach@gmail.com> says:

"Major works are CSA and TDLS. On top of that I have a new
firmware API for scan and a few rate control improvements.
Johannes find a few tricks to improve our CPU utilization
and adds support for a new spin of 7265 called 7265D.
Along with this a few random things that don't stand out."
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parents 9e6f3f47 dcad8e42
...@@ -59,7 +59,7 @@ config IWLDVM ...@@ -59,7 +59,7 @@ config IWLDVM
config IWLMVM config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support" tristate "Intel Wireless WiFi MVM Firmware support"
select BACKPORT_WANT_DEV_COREDUMP select WANT_DEV_COREDUMP
help help
This is the driver that supports the MVM firmware which is This is the driver that supports the MVM firmware which is
currently only available for 7260 and 3160 devices. currently only available for 7260 and 3160 devices.
......
...@@ -102,6 +102,9 @@ ...@@ -102,6 +102,9 @@
#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"
#define IWL7265D_FW_PRE "iwlwifi-7265D-"
#define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_7000 0 #define NVM_HW_SECTION_NUM_FAMILY_7000 0
static const struct iwl_base_params iwl7000_base_params = { static const struct iwl_base_params iwl7000_base_params = {
...@@ -132,8 +135,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { ...@@ -132,8 +135,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.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 .non_shared_ant = ANT_A, \
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
const struct iwl_cfg iwl7260_2ac_cfg = { const struct iwl_cfg iwl7260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7260", .name = "Intel(R) Dual Band Wireless AC 7260",
...@@ -267,7 +270,38 @@ const struct iwl_cfg iwl7265_n_cfg = { ...@@ -267,7 +270,38 @@ const struct iwl_cfg iwl7265_n_cfg = {
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
}; };
const struct iwl_cfg iwl7265d_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265D_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
const struct iwl_cfg iwl7265d_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265D_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
const struct iwl_cfg iwl7265d_n_cfg = {
.name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265D_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
};
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(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));
MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
...@@ -91,6 +91,10 @@ ...@@ -91,6 +91,10 @@
/* Max SDIO RX aggregation size of the ADDBA request/response */ /* Max SDIO RX aggregation size of the ADDBA request/response */
#define MAX_RX_AGG_SIZE_8260_SDIO 28 #define MAX_RX_AGG_SIZE_8260_SDIO 28
/* Max A-MPDU exponent for HT and VHT */
#define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K
#define MAX_VHT_AMPDU_EXPONENT_8260_SDIO IEEE80211_VHT_MAX_AMPDU_32K
static const struct iwl_base_params iwl8000_base_params = { static const struct iwl_base_params iwl8000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000,
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
...@@ -119,6 +123,7 @@ static const struct iwl_ht_params iwl8000_ht_params = { ...@@ -119,6 +123,7 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.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, \
.d0i3 = true, \
.non_shared_ant = ANT_A .non_shared_ant = ANT_A
const struct iwl_cfg iwl8260_2n_cfg = { const struct iwl_cfg iwl8260_2n_cfg = {
...@@ -137,6 +142,7 @@ const struct iwl_cfg iwl8260_2ac_cfg = { ...@@ -137,6 +142,7 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
.ht_params = &iwl8000_ht_params, .ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION, .nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
}; };
const struct iwl_cfg iwl8260_2ac_sdio_cfg = { const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
...@@ -149,6 +155,23 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { ...@@ -149,6 +155,23 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.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, .disable_dummy_notification = true,
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO,
};
const struct iwl_cfg iwl4265_2ac_sdio_cfg = {
.name = "Intel(R) Dual Band Wireless-AC 4265",
.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,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.bt_shared_single_ant = true,
.disable_dummy_notification = true,
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO,
}; };
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
...@@ -257,6 +257,10 @@ struct iwl_pwr_tx_backoff { ...@@ -257,6 +257,10 @@ struct iwl_pwr_tx_backoff {
* @pwr_tx_backoffs: translation table between power limits and backoffs * @pwr_tx_backoffs: translation table between power limits and backoffs
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
* @max_tx_agg_size: max TX aggregation size of the ADDBA request/response * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
* @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the
* station can receive in HT
* @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the
* station can receive in VHT
* *
* We enable the driver to be backward compatible wrt. hardware features. * We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs * API differences in uCode shouldn't be handled here but through TLVs
...@@ -297,6 +301,8 @@ struct iwl_cfg { ...@@ -297,6 +301,8 @@ struct iwl_cfg {
unsigned int max_rx_agg_size; unsigned int max_rx_agg_size;
bool disable_dummy_notification; bool disable_dummy_notification;
unsigned int max_tx_agg_size; unsigned int max_tx_agg_size;
unsigned int max_ht_ampdu_exponent;
unsigned int max_vht_ampdu_exponent;
}; };
/* /*
...@@ -358,9 +364,13 @@ extern const struct iwl_cfg iwl3165_2ac_cfg; ...@@ -358,9 +364,13 @@ 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 iwl7265d_2ac_cfg;
extern const struct iwl_cfg iwl7265d_2n_cfg;
extern const struct iwl_cfg iwl7265d_n_cfg;
extern const struct iwl_cfg iwl8260_2n_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;
extern const struct iwl_cfg iwl4265_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */ #endif /* CONFIG_IWLMVM */
#endif /* __IWL_CONFIG_H__ */ #endif /* __IWL_CONFIG_H__ */
...@@ -129,6 +129,8 @@ ...@@ -129,6 +129,8 @@
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
#define CSR_MBOX_SET_REG (CSR_BASE + 0x88)
#define CSR_LED_REG (CSR_BASE+0x094) #define CSR_LED_REG (CSR_BASE+0x094)
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ #define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */
...@@ -184,6 +186,8 @@ ...@@ -184,6 +186,8 @@
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
#define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */
#define CSR_MBOX_SET_REG_OS_ALIVE BIT(5)
#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
...@@ -321,6 +325,7 @@ enum { ...@@ -321,6 +325,7 @@ enum {
#define CSR_HW_REV_TYPE_2x00 (0x0000100) #define CSR_HW_REV_TYPE_2x00 (0x0000100)
#define CSR_HW_REV_TYPE_105 (0x0000110) #define CSR_HW_REV_TYPE_105 (0x0000110)
#define CSR_HW_REV_TYPE_135 (0x0000120) #define CSR_HW_REV_TYPE_135 (0x0000120)
#define CSR_HW_REV_TYPE_7265D (0x0000210)
#define CSR_HW_REV_TYPE_NONE (0x00001F0) #define CSR_HW_REV_TYPE_NONE (0x00001F0)
/* EEPROM REG */ /* EEPROM REG */
......
...@@ -143,7 +143,7 @@ do { \ ...@@ -143,7 +143,7 @@ do { \
#define IWL_DL_INFO 0x00000001 #define IWL_DL_INFO 0x00000001
#define IWL_DL_MAC80211 0x00000002 #define IWL_DL_MAC80211 0x00000002
#define IWL_DL_HCMD 0x00000004 #define IWL_DL_HCMD 0x00000004
#define IWL_DL_STATE 0x00000008 #define IWL_DL_TDLS 0x00000008
/* 0x000000F0 - 0x00000010 */ /* 0x000000F0 - 0x00000010 */
#define IWL_DL_QUOTA 0x00000010 #define IWL_DL_QUOTA 0x00000010
#define IWL_DL_TE 0x00000020 #define IWL_DL_TE 0x00000020
...@@ -180,6 +180,7 @@ do { \ ...@@ -180,6 +180,7 @@ do { \
#define IWL_DL_TX_QUEUES 0x80000000 #define IWL_DL_TX_QUEUES 0x80000000
#define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
#define IWL_DEBUG_TDLS(p, f, a...) IWL_DEBUG(p, IWL_DL_TDLS, f, ## a)
#define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
#define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) #define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a)
#define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a)
......
...@@ -764,7 +764,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ...@@ -764,7 +764,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
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;
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
ht_info->mcs.rx_mask[0] = 0xFF; ht_info->mcs.rx_mask[0] = 0xFF;
......
...@@ -145,24 +145,30 @@ enum iwl_ucode_tlv_api { ...@@ -145,24 +145,30 @@ enum iwl_ucode_tlv_api {
/** /**
* enum iwl_ucode_tlv_capa - ucode capabilities * enum iwl_ucode_tlv_capa - ucode capabilities
* @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
* @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan.
* @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality
* @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current
* tx power value into TPC Report action frame and Link Measurement Report * tx power value into TPC Report action frame and Link Measurement Report
* action frame * action frame
* @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports adding DS params * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current
* element in probe requests. * channel in DS parameter set element in probe requests.
* @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in
* probe requests. * probe requests.
* @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
* @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
* which also implies support for the scheduler configuration command * which also implies support for the scheduler configuration command
* @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
*/ */
enum iwl_ucode_tlv_capa { enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2),
IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6),
IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8),
IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9),
IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10),
IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11),
IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
}; };
/* The default calibrate table size if not specified by firmware file */ /* The default calibrate table size if not specified by firmware file */
......
...@@ -325,6 +325,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, ...@@ -325,6 +325,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
{ {
int num_rx_ants = num_of_ant(rx_chains); int num_rx_ants = num_of_ant(rx_chains);
int num_tx_ants = num_of_ant(tx_chains); int num_tx_ants = num_of_ant(tx_chains);
unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?:
IEEE80211_VHT_MAX_AMPDU_1024K);
vht_cap->vht_supported = true; vht_cap->vht_supported = true;
...@@ -332,7 +334,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, ...@@ -332,7 +334,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; max_ampdu_exponent <<
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (cfg->ht_params->ldpc) if (cfg->ht_params->ldpc)
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
......
...@@ -138,7 +138,8 @@ struct iwl_cfg; ...@@ -138,7 +138,8 @@ struct iwl_cfg;
* @nic_config: configure NIC, called before firmware is started. * @nic_config: configure NIC, called before firmware is started.
* May sleep * May sleep
* @wimax_active: invoked when WiMax becomes active. May sleep * @wimax_active: invoked when WiMax becomes active. May sleep
* @enter_d0i3: configure the fw to enter d0i3. May sleep. * @enter_d0i3: configure the fw to enter d0i3. return 1 to indicate d0i3
* entrance is aborted (e.g. due to held reference). May sleep.
* @exit_d0i3: configure the fw to exit d0i3. May sleep. * @exit_d0i3: configure the fw to exit d0i3. May sleep.
*/ */
struct iwl_op_mode_ops { struct iwl_op_mode_ops {
......
...@@ -349,10 +349,10 @@ enum secure_load_status_reg { ...@@ -349,10 +349,10 @@ enum secure_load_status_reg {
#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000) #define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000)
#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000) #define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000)
#define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x404000)
#define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x405000)
#define LMPM_SECURE_TIME_OUT (100) #define LMPM_SECURE_TIME_OUT (50000) /* 5 msec */
/* Rx FIFO */ /* Rx FIFO */
#define RXF_SIZE_ADDR (0xa00c88) #define RXF_SIZE_ADDR (0xa00c88)
...@@ -368,4 +368,10 @@ enum secure_load_status_reg { ...@@ -368,4 +368,10 @@ enum secure_load_status_reg {
#define MON_BUFF_WRPTR (0xa03c44) #define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48) #define MON_BUFF_CYCLE_CNT (0xa03c48)
/* FW chicken bits */
#define LMPM_CHICK 0xA01FF8
enum {
LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0),
};
#endif /* __iwl_prph_h__ */ #endif /* __iwl_prph_h__ */
...@@ -534,6 +534,8 @@ struct iwl_trans_ops { ...@@ -534,6 +534,8 @@ struct iwl_trans_ops {
u32 value); u32 value);
void (*ref)(struct iwl_trans *trans); void (*ref)(struct iwl_trans *trans);
void (*unref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans);
void (*suspend)(struct iwl_trans *trans);
void (*resume)(struct iwl_trans *trans);
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
}; };
...@@ -702,6 +704,18 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) ...@@ -702,6 +704,18 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
trans->ops->unref(trans); trans->ops->unref(trans);
} }
static inline void iwl_trans_suspend(struct iwl_trans *trans)
{
if (trans->ops->suspend)
trans->ops->suspend(trans);
}
static inline void iwl_trans_resume(struct iwl_trans *trans)
{
if (trans->ops->resume)
trans->ops->resume(trans);
}
static inline struct iwl_trans_dump_data * static inline struct iwl_trans_dump_data *
iwl_trans_dump_data(struct iwl_trans *trans) iwl_trans_dump_data(struct iwl_trans *trans)
{ {
......
...@@ -1137,6 +1137,22 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, ...@@ -1137,6 +1137,22 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
return lut_type != BT_COEX_LOOSE_LUT; return lut_type != BT_COEX_LOOSE_LUT;
} }
bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
{
/* there is no other antenna, shared antenna is always available */
if (mvm->cfg->bt_shared_single_ant)
return true;
if (ant & mvm->cfg->non_shared_ant)
return true;
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
BT_HIGH_TRAFFIC;
}
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 */ /* there is no other antenna, shared antenna is always available */
......
...@@ -612,7 +612,9 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) ...@@ -612,7 +612,9 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
BT_VALID_ANT_ISOLATION_THRS | BT_VALID_ANT_ISOLATION_THRS |
BT_VALID_TXTX_DELTA_FREQ_THRS | BT_VALID_TXTX_DELTA_FREQ_THRS |
BT_VALID_TXRX_MAX_FREQ_0 | BT_VALID_TXRX_MAX_FREQ_0 |
BT_VALID_SYNC_TO_SCO); BT_VALID_SYNC_TO_SCO |
BT_VALID_TTC |
BT_VALID_RRC);
if (IWL_MVM_BT_COEX_SYNC2SCO) if (IWL_MVM_BT_COEX_SYNC2SCO)
bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);
...@@ -628,6 +630,12 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) ...@@ -628,6 +630,12 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT);
} }
if (IWL_MVM_BT_COEX_TTC)
bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC);
if (IWL_MVM_BT_COEX_RRC)
bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC);
if (mvm->cfg->bt_shared_single_ant) if (mvm->cfg->bt_shared_single_ant)
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
sizeof(iwl_single_shared_ant)); sizeof(iwl_single_shared_ant));
...@@ -824,6 +832,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -824,6 +832,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (!vif->bss_conf.assoc) if (!vif->bss_conf.assoc)
smps_mode = IEEE80211_SMPS_AUTOMATIC; smps_mode = IEEE80211_SMPS_AUTOMATIC;
if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
smps_mode = IEEE80211_SMPS_AUTOMATIC;
IWL_DEBUG_COEX(data->mvm, IWL_DEBUG_COEX(data->mvm,
"mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n",
mvmvif->id, data->notif->bt_status, bt_activity_grading, mvmvif->id, data->notif->bt_status, bt_activity_grading,
...@@ -1156,6 +1167,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, ...@@ -1156,6 +1167,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
return lut_type != BT_COEX_LOOSE_LUT; return lut_type != BT_COEX_LOOSE_LUT;
} }
bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant)
{
u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
return ag < BT_HIGH_TRAFFIC;
}
bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
{ {
u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
......
...@@ -92,6 +92,8 @@ ...@@ -92,6 +92,8 @@
#define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 0 #define IWL_MVM_BT_COEX_CORUNNING 0
#define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_MPLUT 1
#define IWL_MVM_BT_COEX_RRC 1
#define IWL_MVM_BT_COEX_TTC 1
#define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280 #define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280
#define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751 #define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751
#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30
......
...@@ -878,6 +878,10 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, ...@@ -878,6 +878,10 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
}; };
int ret; int ret;
ret = iwl_mvm_switch_to_d3(mvm);
if (ret)
return ret;
ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
if (ret) if (ret)
return ret; return ret;
...@@ -962,6 +966,33 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, ...@@ -962,6 +966,33 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
return ret; return ret;
} }
static int
iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
struct cfg80211_wowlan *wowlan,
struct cfg80211_sched_scan_request *nd_config,
struct ieee80211_vif *vif)
{
struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
int ret;
ret = iwl_mvm_switch_to_d3(mvm);
if (ret)
return ret;
/* rfkill release can be either for wowlan or netdetect */
if (wowlan->rfkill_release)
wowlan_config_cmd.common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
if (ret)
return ret;
ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies);
return ret;
}
static int __iwl_mvm_suspend(struct ieee80211_hw *hw, static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan, struct cfg80211_wowlan *wowlan,
bool test) bool test)
...@@ -970,7 +1001,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, ...@@ -970,7 +1001,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
struct ieee80211_vif *vif = NULL; struct ieee80211_vif *vif = NULL;
struct iwl_mvm_vif *mvmvif = NULL; struct iwl_mvm_vif *mvmvif = NULL;
struct ieee80211_sta *ap_sta = NULL; struct ieee80211_sta *ap_sta = NULL;
struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
struct iwl_d3_manager_config d3_cfg_cmd_data = { struct iwl_d3_manager_config d3_cfg_cmd_data = {
/* /*
* Program the minimum sleep time to 10 seconds, as many * Program the minimum sleep time to 10 seconds, as many
...@@ -1007,8 +1037,22 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, ...@@ -1007,8 +1037,22 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif = iwl_mvm_vif_from_mac80211(vif);
/* if we're associated, this is wowlan */ if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) {
if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { /* if we're not associated, this must be netdetect */
if (!wowlan->nd_config && !mvm->nd_config) {
ret = 1;
goto out_noreset;
}
ret = iwl_mvm_netdetect_config(
mvm, wowlan, wowlan->nd_config ?: mvm->nd_config, vif);
if (ret)
goto out;
mvm->net_detect = true;
} else {
struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
ap_sta = rcu_dereference_protected( ap_sta = rcu_dereference_protected(
mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
lockdep_is_held(&mvm->mutex)); lockdep_is_held(&mvm->mutex));
...@@ -1021,27 +1065,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, ...@@ -1021,27 +1065,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
vif, mvmvif, ap_sta); vif, mvmvif, ap_sta);
if (ret) if (ret)
goto out_noreset; goto out_noreset;
ret = iwl_mvm_switch_to_d3(mvm);
if (ret)
goto out;
ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
vif, mvmvif, ap_sta); vif, mvmvif, ap_sta);
if (ret) if (ret)
goto out; goto out;
} else if (mvm->nd_config) {
ret = iwl_mvm_switch_to_d3(mvm);
if (ret)
goto out;
ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config, mvm->net_detect = false;
mvm->nd_ies);
if (ret)
goto out;
} else {
ret = 1;
goto out_noreset;
} }
ret = iwl_mvm_power_update_device(mvm); ret = iwl_mvm_power_update_device(mvm);
...@@ -1087,6 +1116,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -1087,6 +1116,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
iwl_trans_suspend(mvm->trans);
if (iwl_mvm_is_d0i3_supported(mvm)) { if (iwl_mvm_is_d0i3_supported(mvm)) {
mutex_lock(&mvm->d0i3_suspend_mutex); mutex_lock(&mvm->d0i3_suspend_mutex);
__set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
...@@ -1465,9 +1495,8 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ...@@ -1465,9 +1495,8 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
return true; return true;
} }
/* releases the MVM mutex */ static struct iwl_wowlan_status *
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
struct ieee80211_vif *vif)
{ {
u32 base = mvm->error_event_table; u32 base = mvm->error_event_table;
struct error_table_start { struct error_table_start {
...@@ -1479,19 +1508,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, ...@@ -1479,19 +1508,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
.id = WOWLAN_GET_STATUSES, .id = WOWLAN_GET_STATUSES,
.flags = CMD_WANT_SKB, .flags = CMD_WANT_SKB,
}; };
struct iwl_wowlan_status_data status; struct iwl_wowlan_status *status, *fw_status;
struct iwl_wowlan_status *fw_status; int ret, len, status_size;
int ret, len, status_size, i;
bool keep;
struct ieee80211_sta *ap_sta;
struct iwl_mvm_sta *mvm_ap_sta;
iwl_trans_read_mem_bytes(mvm->trans, base, iwl_trans_read_mem_bytes(mvm->trans, base,
&err_info, sizeof(err_info)); &err_info, sizeof(err_info));
if (err_info.valid) { if (err_info.valid) {
IWL_INFO(mvm, "error table is valid (%d)\n", IWL_INFO(mvm, "error table is valid (%d) with error (%d)\n",
err_info.valid); err_info.valid, err_info.error_id);
if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
struct cfg80211_wowlan_wakeup wakeup = { struct cfg80211_wowlan_wakeup wakeup = {
.rfkill_release = true, .rfkill_release = true,
...@@ -1499,7 +1524,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, ...@@ -1499,7 +1524,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
ieee80211_report_wowlan_wakeup(vif, &wakeup, ieee80211_report_wowlan_wakeup(vif, &wakeup,
GFP_KERNEL); GFP_KERNEL);
} }
goto out_unlock; return ERR_PTR(-EIO);
} }
/* only for tracing for now */ /* only for tracing for now */
...@@ -1510,22 +1535,53 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, ...@@ -1510,22 +1535,53 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
ret = iwl_mvm_send_cmd(mvm, &cmd); ret = iwl_mvm_send_cmd(mvm, &cmd);
if (ret) { if (ret) {
IWL_ERR(mvm, "failed to query status (%d)\n", ret); IWL_ERR(mvm, "failed to query status (%d)\n", ret);
goto out_unlock; return ERR_PTR(ret);
} }
/* RF-kill already asserted again... */ /* RF-kill already asserted again... */
if (!cmd.resp_pkt) if (!cmd.resp_pkt) {
goto out_unlock; ret = -ERFKILL;
goto out_free_resp;
}
status_size = sizeof(*fw_status); status_size = sizeof(*fw_status);
len = iwl_rx_packet_payload_len(cmd.resp_pkt); len = iwl_rx_packet_payload_len(cmd.resp_pkt);
if (len < status_size) { if (len < status_size) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
ret = -EIO;
goto out_free_resp;
}
status = (void *)cmd.resp_pkt->data;
if (len != (status_size +
ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
ret = -EIO;
goto out_free_resp; goto out_free_resp;
} }
fw_status = (void *)cmd.resp_pkt->data; fw_status = kmemdup(status, len, GFP_KERNEL);
out_free_resp:
iwl_free_resp(&cmd);
return ret ? ERR_PTR(ret) : fw_status;
}
/* releases the MVM mutex */
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_wowlan_status_data status;
struct iwl_wowlan_status *fw_status;
int i;
bool keep;
struct ieee80211_sta *ap_sta;
struct iwl_mvm_sta *mvm_ap_sta;
fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
if (IS_ERR_OR_NULL(fw_status))
goto out_unlock;
status.pattern_number = le16_to_cpu(fw_status->pattern_number); status.pattern_number = le16_to_cpu(fw_status->pattern_number);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
...@@ -1538,17 +1594,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, ...@@ -1538,17 +1594,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
le32_to_cpu(fw_status->wake_packet_bufsize); le32_to_cpu(fw_status->wake_packet_bufsize);
status.wake_packet = fw_status->wake_packet; status.wake_packet = fw_status->wake_packet;
if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
goto out_free_resp;
}
/* still at hard-coded place 0 for D3 image */ /* still at hard-coded place 0 for D3 image */
ap_sta = rcu_dereference_protected( ap_sta = rcu_dereference_protected(
mvm->fw_id_to_mac_id[0], mvm->fw_id_to_mac_id[0],
lockdep_is_held(&mvm->mutex)); lockdep_is_held(&mvm->mutex));
if (IS_ERR_OR_NULL(ap_sta)) if (IS_ERR_OR_NULL(ap_sta))
goto out_free_resp; goto out_free;
mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) { for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
...@@ -1565,16 +1616,42 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, ...@@ -1565,16 +1616,42 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status);
iwl_free_resp(&cmd); kfree(fw_status);
return keep; return keep;
out_free_resp: out_free:
iwl_free_resp(&cmd); kfree(fw_status);
out_unlock: out_unlock:
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
return false; return false;
} }
static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct cfg80211_wowlan_wakeup wakeup = {
.pattern_idx = -1,
};
struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
struct iwl_wowlan_status *fw_status;
u32 reasons = 0;
fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
if (!IS_ERR_OR_NULL(fw_status))
reasons = le32_to_cpu(fw_status->wakeup_reasons);
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
wakeup.rfkill_release = true;
if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
/* TODO: read and check if it was netdetect */
wakeup_report = NULL;
}
mutex_unlock(&mvm->mutex);
ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
}
static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
{ {
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
...@@ -1632,11 +1709,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) ...@@ -1632,11 +1709,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* query SRAM first in case we want event logging */ /* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram(mvm); iwl_mvm_read_d3_sram(mvm);
if (mvm->net_detect) {
iwl_mvm_query_netdetect_reasons(mvm, vif);
} else {
keep = iwl_mvm_query_wakeup_reasons(mvm, vif); keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
if (keep) if (keep)
mvm->keep_vif = vif; mvm->keep_vif = vif;
#endif #endif
}
/* has unlocked the mutex, so skip that */ /* has unlocked the mutex, so skip that */
goto out; goto out;
...@@ -1651,6 +1732,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) ...@@ -1651,6 +1732,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* return 1 to reconfigure the device */ /* return 1 to reconfigure the device */
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
return 1; return 1;
} }
...@@ -1658,18 +1740,10 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) ...@@ -1658,18 +1740,10 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (iwl_mvm_is_d0i3_supported(mvm)) { iwl_trans_resume(mvm->trans);
bool exit_now;
mutex_lock(&mvm->d0i3_suspend_mutex); if (iwl_mvm_is_d0i3_supported(mvm))
__clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP,
&mvm->d0i3_suspend_flags);
mutex_unlock(&mvm->d0i3_suspend_mutex);
if (exit_now)
_iwl_mvm_exit_d0i3(mvm);
return 0; return 0;
}
return __iwl_mvm_resume(mvm, false); return __iwl_mvm_resume(mvm, false);
} }
......
...@@ -936,7 +936,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, ...@@ -936,7 +936,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
if (scan_rx_ant & ~mvm->fw->valid_rx_ant) if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
return -EINVAL; return -EINVAL;
if (mvm->scan_rx_ant != scan_rx_ant) {
mvm->scan_rx_ant = scan_rx_ant; mvm->scan_rx_ant = scan_rx_ant;
if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
iwl_mvm_config_scan(mvm);
}
return count; return count;
} }
...@@ -1194,14 +1198,8 @@ static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf, ...@@ -1194,14 +1198,8 @@ static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
kfree(mvm->nd_config->match_sets); kfree(mvm->nd_config->match_sets);
kfree(mvm->nd_config); kfree(mvm->nd_config);
mvm->nd_config = NULL; mvm->nd_config = NULL;
kfree(mvm->nd_ies);
mvm->nd_ies = NULL;
} }
mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
if (!mvm->nd_ies)
return -ENOMEM;
mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) + mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
(11 * sizeof(struct ieee80211_channel *)), (11 * sizeof(struct ieee80211_channel *)),
GFP_KERNEL); GFP_KERNEL);
...@@ -1258,8 +1256,6 @@ static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf, ...@@ -1258,8 +1256,6 @@ static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
kfree(mvm->nd_config->match_sets); kfree(mvm->nd_config->match_sets);
kfree(mvm->nd_config); kfree(mvm->nd_config);
mvm->nd_config = NULL; mvm->nd_config = NULL;
kfree(mvm->nd_ies);
mvm->nd_ies = NULL;
out: out:
return ret; return ret;
} }
......
...@@ -84,6 +84,8 @@ ...@@ -84,6 +84,8 @@
* @BT_COEX_SYNC2SCO: * @BT_COEX_SYNC2SCO:
* @BT_COEX_CORUNNING: * @BT_COEX_CORUNNING:
* @BT_COEX_MPLUT: * @BT_COEX_MPLUT:
* @BT_COEX_TTC:
* @BT_COEX_RRC:
* *
* The COEX_MODE must be set for each command. Even if it is not changed. * The COEX_MODE must be set for each command. Even if it is not changed.
*/ */
...@@ -100,6 +102,8 @@ enum iwl_bt_coex_flags { ...@@ -100,6 +102,8 @@ enum iwl_bt_coex_flags {
BT_COEX_SYNC2SCO = BIT(7), BT_COEX_SYNC2SCO = BIT(7),
BT_COEX_CORUNNING = BIT(8), BT_COEX_CORUNNING = BIT(8),
BT_COEX_MPLUT = BIT(9), BT_COEX_MPLUT = BIT(9),
BT_COEX_TTC = BIT(20),
BT_COEX_RRC = BIT(21),
}; };
/* /*
...@@ -127,6 +131,8 @@ enum iwl_bt_coex_valid_bit_msk { ...@@ -127,6 +131,8 @@ enum iwl_bt_coex_valid_bit_msk {
BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
BT_VALID_SYNC_TO_SCO = BIT(18), BT_VALID_SYNC_TO_SCO = BIT(18),
BT_VALID_TTC = BIT(20),
BT_VALID_RRC = BIT(21),
}; };
/** /**
...@@ -506,7 +512,8 @@ struct iwl_bt_coex_profile_notif_old { ...@@ -506,7 +512,8 @@ struct iwl_bt_coex_profile_notif_old {
u8 bt_agg_traffic_load; u8 bt_agg_traffic_load;
u8 bt_ci_compliance; u8 bt_ci_compliance;
u8 ttc_enabled; u8 ttc_enabled;
__le16 reserved; u8 rrc_enabled;
u8 reserved;
__le32 primary_ch_lut; __le32 primary_ch_lut;
__le32 secondary_ch_lut; __le32 secondary_ch_lut;
......
...@@ -370,7 +370,7 @@ struct iwl_beacon_filter_cmd { ...@@ -370,7 +370,7 @@ struct iwl_beacon_filter_cmd {
#define IWL_BF_DEBUG_FLAG_DEFAULT 0 #define IWL_BF_DEBUG_FLAG_DEFAULT 0
#define IWL_BF_DEBUG_FLAG_D0I3 0 #define IWL_BF_DEBUG_FLAG_D0I3 0
#define IWL_BF_ESCAPE_TIMER_DEFAULT 50 #define IWL_BF_ESCAPE_TIMER_DEFAULT 0
#define IWL_BF_ESCAPE_TIMER_D0I3 0 #define IWL_BF_ESCAPE_TIMER_D0I3 0
#define IWL_BF_ESCAPE_TIMER_MAX 1024 #define IWL_BF_ESCAPE_TIMER_MAX 1024
#define IWL_BF_ESCAPE_TIMER_MIN 0 #define IWL_BF_ESCAPE_TIMER_MIN 0
......
...@@ -794,4 +794,257 @@ struct iwl_periodic_scan_complete { ...@@ -794,4 +794,257 @@ struct iwl_periodic_scan_complete {
__le32 reserved; __le32 reserved;
} __packed; } __packed;
/* UMAC Scan API */
/**
* struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands
* @size: size of the command (not including header)
* @reserved0: for future use and alignment
* @ver: API version number
*/
struct iwl_mvm_umac_cmd_hdr {
__le16 size;
u8 reserved0;
u8 ver;
} __packed;
#define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8
enum scan_config_flags {
SCAN_CONFIG_FLAG_ACTIVATE = BIT(0),
SCAN_CONFIG_FLAG_DEACTIVATE = BIT(1),
SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = BIT(2),
SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = BIT(3),
SCAN_CONFIG_FLAG_SET_TX_CHAINS = BIT(8),
SCAN_CONFIG_FLAG_SET_RX_CHAINS = BIT(9),
SCAN_CONFIG_FLAG_SET_AUX_STA_ID = BIT(10),
SCAN_CONFIG_FLAG_SET_ALL_TIMES = BIT(11),
SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = BIT(12),
SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = BIT(13),
SCAN_CONFIG_FLAG_SET_LEGACY_RATES = BIT(14),
SCAN_CONFIG_FLAG_SET_MAC_ADDR = BIT(15),
SCAN_CONFIG_FLAG_SET_FRAGMENTED = BIT(16),
SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = BIT(17),
SCAN_CONFIG_FLAG_SET_CAM_MODE = BIT(18),
SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = BIT(19),
SCAN_CONFIG_FLAG_SET_PROMISC_MODE = BIT(20),
SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = BIT(21),
/* Bits 26-31 are for num of channels in channel_array */
#define SCAN_CONFIG_N_CHANNELS(n) ((n) << 26)
};
enum scan_config_rates {
/* OFDM basic rates */
SCAN_CONFIG_RATE_6M = BIT(0),
SCAN_CONFIG_RATE_9M = BIT(1),
SCAN_CONFIG_RATE_12M = BIT(2),
SCAN_CONFIG_RATE_18M = BIT(3),
SCAN_CONFIG_RATE_24M = BIT(4),
SCAN_CONFIG_RATE_36M = BIT(5),
SCAN_CONFIG_RATE_48M = BIT(6),
SCAN_CONFIG_RATE_54M = BIT(7),
/* CCK basic rates */
SCAN_CONFIG_RATE_1M = BIT(8),
SCAN_CONFIG_RATE_2M = BIT(9),
SCAN_CONFIG_RATE_5M = BIT(10),
SCAN_CONFIG_RATE_11M = BIT(11),
/* Bits 16-27 are for supported rates */
#define SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16)
};
enum iwl_channel_flags {
IWL_CHANNEL_FLAG_EBS = BIT(0),
IWL_CHANNEL_FLAG_ACCURATE_EBS = BIT(1),
IWL_CHANNEL_FLAG_EBS_ADD = BIT(2),
IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = BIT(3),
};
/**
* struct iwl_scan_config
* @hdr: umac command header
* @flags: enum scan_config_flags
* @tx_chains: valid_tx antenna - ANT_* definitions
* @rx_chains: valid_rx antenna - ANT_* definitions
* @legacy_rates: default legacy rates - enum scan_config_rates
* @out_of_channel_time: default max out of serving channel time
* @suspend_time: default max suspend time
* @dwell_active: default dwell time for active scan
* @dwell_passive: default dwell time for passive scan
* @dwell_fragmented: default dwell time for fragmented scan
* @reserved: for future use and alignment
* @mac_addr: default mac address to be used in probes
* @bcast_sta_id: the index of the station in the fw
* @channel_flags: default channel flags - enum iwl_channel_flags
* scan_config_channel_flag
* @channel_array: default supported channels
*/
struct iwl_scan_config {
struct iwl_mvm_umac_cmd_hdr hdr;
__le32 flags;
__le32 tx_chains;
__le32 rx_chains;
__le32 legacy_rates;
__le32 out_of_channel_time;
__le32 suspend_time;
u8 dwell_active;
u8 dwell_passive;
u8 dwell_fragmented;
u8 reserved;
u8 mac_addr[ETH_ALEN];
u8 bcast_sta_id;
u8 channel_flags;
u8 channel_array[];
} __packed; /* SCAN_CONFIG_DB_CMD_API_S */
/**
* iwl_umac_scan_flags
*@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
* can be preempted by other scan requests with higher priority.
* The low priority scan is aborted.
*@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
* when scan starts.
*/
enum iwl_umac_scan_flags {
IWL_UMAC_SCAN_FLAG_PREEMPTIVE = BIT(0),
IWL_UMAC_SCAN_FLAG_START_NOTIF = BIT(1),
};
enum iwl_umac_scan_uid_offsets {
IWL_UMAC_SCAN_UID_TYPE_OFFSET = 0,
IWL_UMAC_SCAN_UID_SEQ_OFFSET = 8,
};
enum iwl_umac_scan_general_flags {
IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC = BIT(0),
IWL_UMAC_SCAN_GEN_FLAGS_OVER_BT = BIT(1),
IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL = BIT(2),
IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE = BIT(3),
IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = BIT(4),
IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = BIT(5),
IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = BIT(6),
IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = BIT(7),
IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8),
IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9)
};
/**
* struct iwl_scan_channel_cfg_umac
* @flags: bitmap - 0-19: directed scan to i'th ssid.
* @channel_num: channel number 1-13 etc.
* @iter_count: repetition count for the channel.
* @iter_interval: interval between two scan interations on one channel.
*/
struct iwl_scan_channel_cfg_umac {
__le32 flags;
u8 channel_num;
u8 iter_count;
__le16 iter_interval;
} __packed; /* SCAN_CHANNEL_CFG_S_VER2 */
/**
* struct iwl_scan_umac_schedule
* @interval: interval in seconds between scan iterations
* @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop
* @reserved: for alignment and future use
*/
struct iwl_scan_umac_schedule {
__le16 interval;
u8 iter_count;
u8 reserved;
} __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */
/**
* struct iwl_scan_req_umac_tail - the rest of the UMAC scan request command
* parameters following channels configuration array.
* @schedule: two scheduling plans.
* @delay: delay in TUs before starting the first scan iteration
* @reserved: for future use and alignment
* @preq: probe request with IEs blocks
* @direct_scan: list of SSIDs for directed active scan
*/
struct iwl_scan_req_umac_tail {
/* SCAN_PERIODIC_PARAMS_API_S_VER_1 */
struct iwl_scan_umac_schedule schedule[2];
__le16 delay;
__le16 reserved;
/* SCAN_PROBE_PARAMS_API_S_VER_1 */
struct iwl_scan_probe_req preq;
struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
} __packed;
/**
* struct iwl_scan_req_umac
* @hdr: umac command header
* @flags: &enum iwl_umac_scan_flags
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @ooc_priority: out of channel priority - &enum iwl_scan_priority
* @general_flags: &enum iwl_umac_scan_general_flags
* @reserved1: for future use and alignment
* @active_dwell: dwell time for active scan
* @passive_dwell: dwell time for passive scan
* @fragmented_dwell: dwell time for fragmented passive scan
* @max_out_time: max out of serving channel time
* @suspend_time: max suspend time
* @scan_priority: scan internal prioritization &enum iwl_scan_priority
* @channel_flags: &enum iwl_scan_channel_flags
* @n_channels: num of channels in scan request
* @reserved2: for future use and alignment
* @data: &struct iwl_scan_channel_cfg_umac and
* &struct iwl_scan_req_umac_tail
*/
struct iwl_scan_req_umac {
struct iwl_mvm_umac_cmd_hdr hdr;
__le32 flags;
__le32 uid;
__le32 ooc_priority;
/* SCAN_GENERAL_PARAMS_API_S_VER_1 */
__le32 general_flags;
u8 reserved1;
u8 active_dwell;
u8 passive_dwell;
u8 fragmented_dwell;
__le32 max_out_time;
__le32 suspend_time;
__le32 scan_priority;
/* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
u8 channel_flags;
u8 n_channels;
__le16 reserved2;
u8 data[];
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
/**
* struct iwl_umac_scan_abort
* @hdr: umac command header
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @flags: reserved
*/
struct iwl_umac_scan_abort {
struct iwl_mvm_umac_cmd_hdr hdr;
__le32 uid;
__le32 flags;
} __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
/**
* struct iwl_umac_scan_complete
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @last_schedule: last scheduling line
* @last_iter: last scan iteration number
* @scan status: &enum iwl_scan_offload_complete_status
* @ebs_status: &enum iwl_scan_ebs_status
* @time_from_last_iter: time elapsed from last iteration
* @reserved: for future use
*/
struct iwl_umac_scan_complete {
__le32 uid;
u8 last_schedule;
u8 last_iter;
u8 status;
u8 ebs_status;
__le32 time_from_last_iter;
__le32 reserved;
} __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */
#endif #endif
...@@ -106,6 +106,12 @@ enum { ...@@ -106,6 +106,12 @@ enum {
DBG_CFG = 0x9, DBG_CFG = 0x9,
ANTENNA_COUPLING_NOTIFICATION = 0xa, ANTENNA_COUPLING_NOTIFICATION = 0xa,
/* UMAC scan commands */
SCAN_CFG_CMD = 0xc,
SCAN_REQ_UMAC = 0xd,
SCAN_ABORT_UMAC = 0xe,
SCAN_COMPLETE_UMAC = 0xf,
/* station table */ /* station table */
ADD_STA_KEY = 0x17, ADD_STA_KEY = 0x17,
ADD_STA = 0x18, ADD_STA = 0x18,
...@@ -122,6 +128,11 @@ enum { ...@@ -122,6 +128,11 @@ enum {
/* global key */ /* global key */
WEP_KEY = 0x20, WEP_KEY = 0x20,
/* TDLS */
TDLS_CHANNEL_SWITCH_CMD = 0x27,
TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa,
TDLS_CONFIG_CMD = 0xa7,
/* MAC and Binding commands */ /* MAC and Binding commands */
MAC_CONTEXT_CMD = 0x28, MAC_CONTEXT_CMD = 0x28,
TIME_EVENT_CMD = 0x29, /* both CMD and response */ TIME_EVENT_CMD = 0x29, /* both CMD and response */
...@@ -190,6 +201,8 @@ enum { ...@@ -190,6 +201,8 @@ enum {
/* Power - new power table command */ /* Power - new power table command */
MAC_PM_POWER_TABLE = 0xa9, MAC_PM_POWER_TABLE = 0xa9,
MFUART_LOAD_NOTIFICATION = 0xb1,
REPLY_RX_PHY_CMD = 0xc0, REPLY_RX_PHY_CMD = 0xc0,
REPLY_RX_MPDU_CMD = 0xc1, REPLY_RX_MPDU_CMD = 0xc1,
BA_NOTIF = 0xc5, BA_NOTIF = 0xc5,
...@@ -1200,6 +1213,21 @@ struct iwl_missed_beacons_notif { ...@@ -1200,6 +1213,21 @@ struct iwl_missed_beacons_notif {
__le32 num_recvd_beacons; __le32 num_recvd_beacons;
} __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */
/**
* struct iwl_mfuart_load_notif - mfuart image version & status
* ( MFUART_LOAD_NOTIFICATION = 0xb1 )
* @installed_ver: installed image version
* @external_ver: external image version
* @status: MFUART loading status
* @duration: MFUART loading time
*/
struct iwl_mfuart_load_notif {
__le32 installed_ver;
__le32 external_ver;
__le32 status;
__le32 duration;
} __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/
/** /**
* struct iwl_set_calib_default_cmd - set default value for calibration. * struct iwl_set_calib_default_cmd - set default value for calibration.
* ( SET_CALIB_DEFAULT_CMD = 0x8e ) * ( SET_CALIB_DEFAULT_CMD = 0x8e )
...@@ -1711,4 +1739,145 @@ struct iwl_scd_txq_cfg_cmd { ...@@ -1711,4 +1739,145 @@ struct iwl_scd_txq_cfg_cmd {
u8 flags; u8 flags;
} __packed; } __packed;
/***********************************
* TDLS API
***********************************/
/* Type of TDLS request */
enum iwl_tdls_channel_switch_type {
TDLS_SEND_CHAN_SW_REQ = 0,
TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH,
TDLS_MOVE_CH,
}; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */
/**
* Switch timing sub-element in a TDLS channel-switch command
* @frame_timestamp: GP2 timestamp of channel-switch request/response packet
* received from peer
* @max_offchan_duration: What amount of microseconds out of a DTIM is given
* to the TDLS off-channel communication. For instance if the DTIM is
* 200TU and the TDLS peer is to be given 25% of the time, the value
* given will be 50TU, or 50 * 1024 if translated into microseconds.
* @switch_time: switch time the peer sent in its channel switch timing IE
* @switch_timout: switch timeout the peer sent in its channel switch timing IE
*/
struct iwl_tdls_channel_switch_timing {
__le32 frame_timestamp; /* GP2 time of peer packet Rx */
__le32 max_offchan_duration; /* given in micro-seconds */
__le32 switch_time; /* given in micro-seconds */
__le32 switch_timeout; /* given in micro-seconds */
} __packed; /* TDLS_STA_CHANNEL_SWITCH_TIMING_DATA_API_S_VER_1 */
#define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200
/**
* TDLS channel switch frame template
*
* A template representing a TDLS channel-switch request or response frame
*
* @switch_time_offset: offset to the channel switch timing IE in the template
* @tx_cmd: Tx parameters for the frame
* @data: frame data
*/
struct iwl_tdls_channel_switch_frame {
__le32 switch_time_offset;
struct iwl_tx_cmd tx_cmd;
u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE];
} __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */
/**
* TDLS channel switch command
*
* The command is sent to initiate a channel switch and also in response to
* incoming TDLS channel-switch request/response packets from remote peers.
*
* @switch_type: see &enum iwl_tdls_channel_switch_type
* @peer_sta_id: station id of TDLS peer
* @ci: channel we switch to
* @timing: timing related data for command
* @frame: channel-switch request/response template, depending to switch_type
*/
struct iwl_tdls_channel_switch_cmd {
u8 switch_type;
__le32 peer_sta_id;
struct iwl_fw_channel_info ci;
struct iwl_tdls_channel_switch_timing timing;
struct iwl_tdls_channel_switch_frame frame;
} __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */
/**
* TDLS channel switch start notification
*
* @status: non-zero on success
* @offchannel_duration: duration given in microseconds
* @sta_id: peer currently performing the channel-switch with
*/
struct iwl_tdls_channel_switch_notif {
__le32 status;
__le32 offchannel_duration;
__le32 sta_id;
} __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */
/**
* TDLS station info
*
* @sta_id: station id of the TDLS peer
* @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx
* @tx_to_peer_ssn: initial SSN the FW should use for Tx on its TID vs the peer
* @is_initiator: 1 if the peer is the TDLS link initiator, 0 otherwise
*/
struct iwl_tdls_sta_info {
u8 sta_id;
u8 tx_to_peer_tid;
__le16 tx_to_peer_ssn;
__le32 is_initiator;
} __packed; /* TDLS_STA_INFO_VER_1 */
/**
* TDLS basic config command
*
* @id_and_color: MAC id and color being configured
* @tdls_peer_count: amount of currently connected TDLS peers
* @tx_to_ap_tid: TID reverved vs. the AP for FW based Tx
* @tx_to_ap_ssn: initial SSN the FW should use for Tx on its TID vs. the AP
* @sta_info: per-station info. Only the first tdls_peer_count entries are set
* @pti_req_data_offset: offset of network-level data for the PTI template
* @pti_req_tx_cmd: Tx parameters for PTI request template
* @pti_req_template: PTI request template data
*/
struct iwl_tdls_config_cmd {
__le32 id_and_color; /* mac id and color */
u8 tdls_peer_count;
u8 tx_to_ap_tid;
__le16 tx_to_ap_ssn;
struct iwl_tdls_sta_info sta_info[IWL_MVM_TDLS_STA_COUNT];
__le32 pti_req_data_offset;
struct iwl_tx_cmd pti_req_tx_cmd;
u8 pti_req_template[0];
} __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */
/**
* TDLS per-station config information from FW
*
* @sta_id: station id of the TDLS peer
* @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to
* the peer
*/
struct iwl_tdls_config_sta_info_res {
__le16 sta_id;
__le16 tx_to_peer_last_seq;
} __packed; /* TDLS_STA_INFO_RSP_VER_1 */
/**
* TDLS config information from FW
*
* @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP
* @sta_info: per-station TDLS config information
*/
struct iwl_tdls_config_res {
__le32 tx_to_ap_last_seq;
struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT];
} __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */
#endif /* __fw_api_h__ */ #endif /* __fw_api_h__ */
...@@ -227,6 +227,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ...@@ -227,6 +227,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
st_fwrd_space.addr = mvm->sf_space.addr; st_fwrd_space.addr = mvm->sf_space.addr;
st_fwrd_space.size = mvm->sf_space.size; st_fwrd_space.size = mvm->sf_space.size;
ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space); ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space);
if (ret) {
IWL_ERR(mvm, "Failed to update SF size. ret %d\n", ret);
return ret;
}
iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr);
...@@ -462,6 +466,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -462,6 +466,8 @@ 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);
mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
/* reset quota debouncing buffer - 0xff will yield invalid data */ /* reset quota debouncing buffer - 0xff will yield invalid data */
memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
...@@ -501,6 +507,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -501,6 +507,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret) if (ret)
goto error; goto error;
if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
ret = iwl_mvm_config_scan(mvm);
if (ret)
goto error;
}
/* allow FW/transport low power modes if not during restart */ /* allow FW/transport low power modes if not during restart */
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
...@@ -587,3 +599,19 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, ...@@ -587,3 +599,19 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
le32_to_cpu(radio_version->radio_dash)); le32_to_cpu(radio_version->radio_dash));
return 0; return 0;
} }
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data;
IWL_DEBUG_INFO(mvm,
"MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n",
le32_to_cpu(mfuart_notif->installed_ver),
le32_to_cpu(mfuart_notif->external_ver),
le32_to_cpu(mfuart_notif->status),
le32_to_cpu(mfuart_notif->duration));
return 0;
}
...@@ -83,11 +83,15 @@ struct iwl_mvm_mac_iface_iterator_data { ...@@ -83,11 +83,15 @@ struct iwl_mvm_mac_iface_iterator_data {
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
u32 used_hw_queues;
enum iwl_tsf_id preferred_tsf; enum iwl_tsf_id preferred_tsf;
bool found_vif; bool found_vif;
}; };
struct iwl_mvm_hw_queues_iface_iterator_data {
struct ieee80211_vif *exclude_vif;
unsigned long used_hw_queues;
};
static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
...@@ -213,6 +217,54 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) ...@@ -213,6 +217,54 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
return qmask; return qmask;
} }
static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_hw_queues_iface_iterator_data *data = _data;
/* exclude the given vif */
if (vif == data->exclude_vif)
return;
data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
}
static void iwl_mvm_mac_sta_hw_queues_iter(void *_data,
struct ieee80211_sta *sta)
{
struct iwl_mvm_hw_queues_iface_iterator_data *data = _data;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
/* Mark the queues used by the sta */
data->used_hw_queues |= mvmsta->tfd_queue_msk;
}
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *exclude_vif)
{
struct iwl_mvm_hw_queues_iface_iterator_data data = {
.exclude_vif = exclude_vif,
.used_hw_queues =
BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
BIT(mvm->aux_queue) |
BIT(IWL_MVM_CMD_QUEUE),
};
lockdep_assert_held(&mvm->mutex);
/* mark all VIF used hw queues */
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
iwl_mvm_iface_hw_queues_iter, &data);
/* don't assign the same hw queues as TDLS stations */
ieee80211_iterate_stations_atomic(mvm->hw,
iwl_mvm_mac_sta_hw_queues_iter,
&data);
return data.used_hw_queues;
}
static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
...@@ -225,9 +277,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, ...@@ -225,9 +277,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
return; return;
} }
/* Mark the queues used by the vif */
data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
/* Mark MAC IDs as used by clearing the available bit, and /* Mark MAC IDs as used by clearing the available bit, and
* (below) mark TSFs as used if their existing use is not * (below) mark TSFs as used if their existing use is not
* compatible with the new interface type. * compatible with the new interface type.
...@@ -274,10 +323,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, ...@@ -274,10 +323,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
.available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
/* no preference yet */ /* no preference yet */
.preferred_tsf = NUM_TSF_IDS, .preferred_tsf = NUM_TSF_IDS,
.used_hw_queues =
BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
BIT(mvm->aux_queue) |
BIT(IWL_MVM_CMD_QUEUE),
.found_vif = false, .found_vif = false,
}; };
u32 ac; u32 ac;
...@@ -316,6 +361,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, ...@@ -316,6 +361,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
iwl_mvm_mac_iface_iterator, &data); iwl_mvm_mac_iface_iterator, &data);
used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif);
/* /*
* In the case we're getting here during resume, it's similar to * In the case we're getting here during resume, it's similar to
* firmware restart, and with RESUME_ALL the iterator will find * firmware restart, and with RESUME_ALL the iterator will find
...@@ -365,8 +412,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, ...@@ -365,8 +412,6 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
return 0; return 0;
} }
used_hw_queues = data.used_hw_queues;
/* Find available queues, and allocate them to the ACs */ /* Find available queues, and allocate them to the ACs */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
u8 queue = find_first_zero_bit(&used_hw_queues, u8 queue = find_first_zero_bit(&used_hw_queues,
...@@ -1218,17 +1263,25 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -1218,17 +1263,25 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
} }
static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
struct ieee80211_vif *csa_vif, u32 gp2) struct ieee80211_vif *csa_vif, u32 gp2,
bool tx_success)
{ {
struct iwl_mvm_vif *mvmvif = struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(csa_vif); iwl_mvm_vif_from_mac80211(csa_vif);
/* Don't start to countdown from a failed beacon */
if (!tx_success && !mvmvif->csa_countdown)
return;
mvmvif->csa_countdown = true;
if (!ieee80211_csa_is_complete(csa_vif)) { if (!ieee80211_csa_is_complete(csa_vif)) {
int c = ieee80211_csa_update_counter(csa_vif); int c = ieee80211_csa_update_counter(csa_vif);
iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif);
if (csa_vif->p2p && if (csa_vif->p2p &&
!iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 &&
tx_success) {
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_GO; IWL_MVM_CHANNEL_SWITCH_TIME_GO;
...@@ -1255,6 +1308,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, ...@@ -1255,6 +1308,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
struct ieee80211_vif *csa_vif; struct ieee80211_vif *csa_vif;
struct ieee80211_vif *tx_blocked_vif; struct ieee80211_vif *tx_blocked_vif;
u64 tsf; u64 tsf;
u16 status;
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
...@@ -1271,18 +1325,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, ...@@ -1271,18 +1325,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
tsf = le64_to_cpu(beacon->tsf); tsf = le64_to_cpu(beacon->tsf);
} }
status = le16_to_cpu(beacon_notify_hdr->status.status) & TX_STATUS_MSK;
IWL_DEBUG_RX(mvm, IWL_DEBUG_RX(mvm,
"beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n",
le16_to_cpu(beacon_notify_hdr->status.status) & status, beacon_notify_hdr->failure_frame, tsf,
TX_STATUS_MSK,
beacon_notify_hdr->failure_frame, tsf,
mvm->ap_last_beacon_gp2, mvm->ap_last_beacon_gp2,
le32_to_cpu(beacon_notify_hdr->initial_rate)); le32_to_cpu(beacon_notify_hdr->initial_rate));
csa_vif = rcu_dereference_protected(mvm->csa_vif, csa_vif = rcu_dereference_protected(mvm->csa_vif,
lockdep_is_held(&mvm->mutex)); lockdep_is_held(&mvm->mutex));
if (unlikely(csa_vif && csa_vif->csa_active)) if (unlikely(csa_vif && csa_vif->csa_active))
iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2,
(status == TX_STATUS_SUCCESS));
tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif,
lockdep_is_held(&mvm->mutex)); lockdep_is_held(&mvm->mutex));
......
This diff is collapsed.
This diff is collapsed.
...@@ -244,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { ...@@ -244,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
iwl_mvm_rx_scan_offload_complete_notif, true), iwl_mvm_rx_scan_offload_complete_notif, true),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
false), false),
RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
true),
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
...@@ -254,6 +256,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { ...@@ -254,6 +256,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
iwl_mvm_power_uapsd_misbehaving_ap_notif, false), iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),
RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
true),
RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false),
}; };
#undef RX_HANDLER #undef RX_HANDLER
#define CMD(x) [x] = #x #define CMD(x) [x] = #x
...@@ -344,6 +352,13 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { ...@@ -344,6 +352,13 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
CMD(ANTENNA_COUPLING_NOTIFICATION), CMD(ANTENNA_COUPLING_NOTIFICATION),
CMD(SCD_QUEUE_CFG), CMD(SCD_QUEUE_CFG),
CMD(SCAN_CFG_CMD),
CMD(SCAN_REQ_UMAC),
CMD(SCAN_ABORT_UMAC),
CMD(SCAN_COMPLETE_UMAC),
CMD(TDLS_CHANNEL_SWITCH_CMD),
CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
CMD(TDLS_CONFIG_CMD),
}; };
#undef CMD #undef CMD
...@@ -442,6 +457,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -442,6 +457,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
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); INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
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);
...@@ -525,6 +541,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -525,6 +541,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true); err = iwl_run_init_mvm_ucode(mvm, true);
if (!err || !iwlmvm_mod_params.init_dbg)
iwl_trans_stop_device(trans); iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */ /* returns 0 if successful, 1 if success but in rfkill */
...@@ -534,16 +551,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -534,16 +551,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
} }
} }
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) scan_size = iwl_mvm_scan_size(mvm);
scan_size = sizeof(struct iwl_scan_req_unified_lmac) +
sizeof(struct iwl_scan_channel_cfg_lmac) *
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_probe_req);
else
scan_size = sizeof(struct iwl_scan_cmd) +
mvm->fw->ucode_capa.max_probe_length +
mvm->fw->ucode_capa.n_scan_channels *
sizeof(struct iwl_scan_channel);
mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
if (!mvm->scan_cmd) if (!mvm->scan_cmd)
...@@ -597,8 +605,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ...@@ -597,8 +605,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->nd_config->match_sets); kfree(mvm->nd_config->match_sets);
kfree(mvm->nd_config); kfree(mvm->nd_config);
mvm->nd_config = NULL; mvm->nd_config = NULL;
kfree(mvm->nd_ies);
mvm->nd_ies = NULL;
} }
#endif #endif
...@@ -1050,6 +1056,19 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) ...@@ -1050,6 +1056,19 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
synchronize_net(); synchronize_net();
/*
* iwl_mvm_ref_sync takes a reference before checking the flag.
* so by checking there is no held reference we prevent a state
* in which iwl_mvm_ref_sync continues successfully while we
* configure the firmware to enter d0i3
*/
if (iwl_mvm_ref_taken(mvm)) {
IWL_DEBUG_RPM(mvm->trans, "abort d0i3 due to taken ref\n");
clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
wake_up(&mvm->d0i3_exit_waitq);
return 1;
}
ieee80211_iterate_active_interfaces_atomic(mvm->hw, ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_enter_d0i3_iterator, iwl_mvm_enter_d0i3_iterator,
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
#include "mvm.h" #include "mvm.h"
/* Maps the driver specific channel width definition to the the fw values */ /* Maps the driver specific channel width definition to the the fw values */
static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)
{ {
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
...@@ -90,7 +90,7 @@ static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) ...@@ -90,7 +90,7 @@ static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)
* Maps the driver specific control channel position (relative to the center * Maps the driver specific control channel position (relative to the center
* freq) definitions to the the fw values * freq) definitions to the the fw values
*/ */
static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef)
{ {
switch (chandef->chan->center_freq - chandef->center_freq1) { switch (chandef->chan->center_freq - chandef->center_freq1) {
case -70: case -70:
......
...@@ -286,6 +286,27 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, ...@@ -286,6 +286,27 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
return true; return true;
} }
static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi)
{
int numerator;
int dtim_interval = dtimper * bi;
if (WARN_ON(!dtim_interval))
return 0;
if (dtimper == 1) {
if (bi > 100)
numerator = 408;
else
numerator = 510;
} else if (dtimper < 10) {
numerator = 612;
} else {
return 0;
}
return max(1, (numerator / dtim_interval));
}
static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
{ {
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
...@@ -308,7 +329,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -308,7 +329,7 @@ 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)
{ {
int dtimper, dtimper_msec; int dtimper, bi;
int keep_alive; int keep_alive;
bool radar_detect = false; bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused = struct iwl_mvm_vif *mvmvif __maybe_unused =
...@@ -317,6 +338,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -317,6 +338,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 = vif->bss_conf.dtim_period; dtimper = vif->bss_conf.dtim_period;
bi = vif->bss_conf.beacon_int;
/* /*
* Regardless of power management state the driver must set * Regardless of power management state the driver must set
...@@ -324,10 +346,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -324,10 +346,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
* immediately after association. Check that keep alive period * immediately after association. Check that keep alive period
* is at least 3 * DTIM * is at least 3 * DTIM
*/ */
dtimper_msec = dtimper * vif->bss_conf.beacon_int; keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi),
keep_alive = max_t(int, 3 * dtimper_msec, USEC_PER_SEC);
MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC);
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = cpu_to_le16(keep_alive); cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
if (mvm->ps_disabled) if (mvm->ps_disabled)
...@@ -352,11 +373,14 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, ...@@ -352,11 +373,14 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
radar_detect = iwl_mvm_power_is_radar(vif); radar_detect = iwl_mvm_power_is_radar(vif);
/* Check skip over DTIM conditions */ /* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) && if (!radar_detect && (dtimper < 10) &&
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP ||
mvm->cur_ucode == IWL_UCODE_WOWLAN)) { mvm->cur_ucode == IWL_UCODE_WOWLAN)) {
cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); cmd->skip_dtim_periods =
cmd->skip_dtim_periods = 3; iwl_mvm_power_get_skip_over_dtim(dtimper, bi);
if (cmd->skip_dtim_periods)
cmd->flags |=
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
} }
if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { if (mvm->cur_ucode != IWL_UCODE_WOWLAN) {
......
...@@ -158,6 +158,12 @@ struct rs_tx_column { ...@@ -158,6 +158,12 @@ struct rs_tx_column {
allow_column_func_t checks[MAX_COLUMN_CHECKS]; allow_column_func_t checks[MAX_COLUMN_CHECKS];
}; };
static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_scale_tbl_info *tbl)
{
return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant);
}
static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_scale_tbl_info *tbl) struct iwl_scale_tbl_info *tbl)
{ {
...@@ -218,6 +224,9 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -218,6 +224,9 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_INVALID, RS_COLUMN_INVALID,
RS_COLUMN_INVALID, RS_COLUMN_INVALID,
}, },
.checks = {
rs_ant_allow,
},
}, },
[RS_COLUMN_LEGACY_ANT_B] = { [RS_COLUMN_LEGACY_ANT_B] = {
.mode = RS_LEGACY, .mode = RS_LEGACY,
...@@ -231,6 +240,9 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -231,6 +240,9 @@ static const struct rs_tx_column rs_tx_columns[] = {
RS_COLUMN_INVALID, RS_COLUMN_INVALID,
RS_COLUMN_INVALID, RS_COLUMN_INVALID,
}, },
.checks = {
rs_ant_allow,
},
}, },
[RS_COLUMN_SISO_ANT_A] = { [RS_COLUMN_SISO_ANT_A] = {
.mode = RS_SISO, .mode = RS_SISO,
...@@ -246,6 +258,7 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -246,6 +258,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
}, },
.checks = { .checks = {
rs_siso_allow, rs_siso_allow,
rs_ant_allow,
}, },
}, },
[RS_COLUMN_SISO_ANT_B] = { [RS_COLUMN_SISO_ANT_B] = {
...@@ -262,6 +275,7 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -262,6 +275,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
}, },
.checks = { .checks = {
rs_siso_allow, rs_siso_allow,
rs_ant_allow,
}, },
}, },
[RS_COLUMN_SISO_ANT_A_SGI] = { [RS_COLUMN_SISO_ANT_A_SGI] = {
...@@ -279,6 +293,7 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -279,6 +293,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
}, },
.checks = { .checks = {
rs_siso_allow, rs_siso_allow,
rs_ant_allow,
rs_sgi_allow, rs_sgi_allow,
}, },
}, },
...@@ -297,6 +312,7 @@ static const struct rs_tx_column rs_tx_columns[] = { ...@@ -297,6 +312,7 @@ static const struct rs_tx_column rs_tx_columns[] = {
}, },
.checks = { .checks = {
rs_siso_allow, rs_siso_allow,
rs_ant_allow,
rs_sgi_allow, rs_sgi_allow,
}, },
}, },
...@@ -506,7 +522,7 @@ static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, ...@@ -506,7 +522,7 @@ 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, IWL_DEBUG_RATE(mvm,
"%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n", "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC: %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->ldpc, rate->stbc); rate->bw, rate->sgi, rate->ldpc, rate->stbc);
...@@ -816,7 +832,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, ...@@ -816,7 +832,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
if (nss == 1) { if (nss == 1) {
rate->type = LQ_VHT_SISO; rate->type = LQ_VHT_SISO;
WARN_ON_ONCE(num_of_ant != 1); WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
} else if (nss == 2) { } else if (nss == 2) {
rate->type = LQ_VHT_MIMO2; rate->type = LQ_VHT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2); WARN_ON_ONCE(num_of_ant != 2);
...@@ -1110,10 +1126,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -1110,10 +1126,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (time_after(jiffies, if (time_after(jiffies,
(unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) {
int tid; int t;
IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) for (t = 0; t < IWL_MAX_TID_COUNT; t++)
ieee80211_stop_tx_ba_session(sta, tid); ieee80211_stop_tx_ba_session(sta, t);
iwl_mvm_rs_rate_init(mvm, sta, info->band, false); iwl_mvm_rs_rate_init(mvm, sta, info->band, false);
return; return;
...@@ -1154,16 +1171,15 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -1154,16 +1171,15 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* Rate did match, so reset the missed_rate_counter */ /* Rate did match, so reset the missed_rate_counter */
lq_sta->missed_rate_counter = 0; lq_sta->missed_rate_counter = 0;
/* Figure out if rate scale algorithm is in active or search table */ if (!lq_sta->search_better_tbl) {
if (rs_rate_match(&rate,
&(lq_sta->lq_info[lq_sta->active_tbl].rate))) {
curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
} else if (rs_rate_match(&rate, } else {
&lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) {
curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
} else { }
if (WARN_ON_ONCE(!rs_rate_match(&rate, &curr_tbl->rate))) {
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"Neither active nor search matches tx rate\n"); "Neither active nor search matches tx rate\n");
tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
...@@ -1188,6 +1204,13 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -1188,6 +1204,13 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* first index into rate scale table. * first index into rate scale table.
*/ */
if (info->flags & IEEE80211_TX_STAT_AMPDU) { if (info->flags & IEEE80211_TX_STAT_AMPDU) {
/* ampdu_ack_len = 0 marks no BA was received. In this case
* treat it as a single frame loss as we don't want the success
* ratio to dip too quickly because a BA wasn't received
*/
if (info->status.ampdu_ack_len == 0)
info->status.ampdu_len = 1;
ucode_rate = le32_to_cpu(table->rs_table[0]); ucode_rate = le32_to_cpu(table->rs_table[0]);
rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
rs_collect_tx_data(lq_sta, curr_tbl, rate.index, rs_collect_tx_data(lq_sta, curr_tbl, rate.index,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -264,6 +264,7 @@ enum iwl_mvm_agg_state { ...@@ -264,6 +264,7 @@ enum iwl_mvm_agg_state {
* the first packet to be sent in legacy HW queue in Tx AGG stop flow. * the first packet to be sent in legacy HW queue in Tx AGG stop flow.
* Basically when next_reclaimed reaches ssn, we can tell mac80211 that * Basically when next_reclaimed reaches ssn, we can tell mac80211 that
* we are ready to finish the Tx AGG stop / start flow. * we are ready to finish the Tx AGG stop / start flow.
* @tx_time: medium time consumed by this A-MPDU
*/ */
struct iwl_mvm_tid_data { struct iwl_mvm_tid_data {
u16 seq_number; u16 seq_number;
...@@ -274,6 +275,7 @@ struct iwl_mvm_tid_data { ...@@ -274,6 +275,7 @@ struct iwl_mvm_tid_data {
enum iwl_mvm_agg_state state; enum iwl_mvm_agg_state state;
u16 txq_id; u16 txq_id;
u16 ssn; u16 ssn;
u16 tx_time;
}; };
static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
...@@ -286,6 +288,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -286,6 +288,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
* struct iwl_mvm_sta - representation of a station in the driver * struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color) * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
* @tfd_queue_msk: the tfd queues used by the station * @tfd_queue_msk: the tfd queues used by the station
* @hw_queue: per-AC mapping of the TFD queues used by station
* @mac_id_n_color: the MAC context this station is linked to * @mac_id_n_color: the MAC context this station is linked to
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid. * tid.
...@@ -309,6 +312,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -309,6 +312,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
struct iwl_mvm_sta { struct iwl_mvm_sta {
u32 sta_id; u32 sta_id;
u32 tfd_queue_msk; u32 tfd_queue_msk;
u8 hw_queue[IEEE80211_NUM_ACS];
u32 mac_id_n_color; u32 mac_id_n_color;
u16 tid_disable_agg; u16 tid_disable_agg;
u8 max_agg_bufsize; u8 max_agg_bufsize;
...@@ -418,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, ...@@ -418,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif, struct iwl_mvm_vif *mvmvif,
bool disable); bool disable);
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
#endif /* __sta_h__ */ #endif /* __sta_h__ */
This diff is collapsed.
...@@ -182,14 +182,14 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -182,14 +182,14 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int duration, enum ieee80211_roc_type type); int duration, enum ieee80211_roc_type type);
/** /**
* iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity * iwl_mvm_stop_roc - stop remain on channel functionality
* @mvm: the mvm component * @mvm: the mvm component
* *
* This function can be used to cancel an ongoing ROC session. * This function can be used to cancel an ongoing ROC session.
* The function is async, it will instruct the FW to stop serving the ROC * The function is async, it will instruct the FW to stop serving the ROC
* session, but will not wait for the actual stopping of the session. * session, but will not wait for the actual stopping of the session.
*/ */
void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm); void iwl_mvm_stop_roc(struct iwl_mvm *mvm);
/** /**
* iwl_mvm_remove_time_event - general function to clean up of time event * iwl_mvm_remove_time_event - general function to clean up of time event
......
...@@ -95,30 +95,79 @@ static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) ...@@ -95,30 +95,79 @@ static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
iwl_mvm_set_hw_ctkill_state(mvm, false); iwl_mvm_set_hw_ctkill_state(mvm, false);
} }
static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait, void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp)
struct iwl_rx_packet *pkt, void *data) {
/* ignore the notification if we are in test mode */
if (mvm->temperature_test)
return;
if (mvm->temperature == temp)
return;
mvm->temperature = temp;
iwl_mvm_tt_handler(mvm);
}
static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt)
{ {
struct iwl_mvm *mvm =
container_of(notif_wait, struct iwl_mvm, notif_wait);
int *temp = data;
struct iwl_dts_measurement_notif *notif; struct iwl_dts_measurement_notif *notif;
int len = iwl_rx_packet_payload_len(pkt); int len = iwl_rx_packet_payload_len(pkt);
int temp;
if (WARN_ON_ONCE(len != sizeof(*notif))) { if (WARN_ON_ONCE(len != sizeof(*notif))) {
IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
return true; return -EINVAL;
} }
notif = (void *)pkt->data; notif = (void *)pkt->data;
*temp = le32_to_cpu(notif->temp); temp = le32_to_cpu(notif->temp);
/* shouldn't be negative, but since it's s32, make sure it isn't */ /* shouldn't be negative, but since it's s32, make sure it isn't */
if (WARN_ON_ONCE(*temp < 0)) if (WARN_ON_ONCE(temp < 0))
*temp = 0; temp = 0;
IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp);
return temp;
}
static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt, void *data)
{
struct iwl_mvm *mvm =
container_of(notif_wait, struct iwl_mvm, notif_wait);
int *temp = data;
int ret;
IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp); ret = iwl_mvm_temp_notif_parse(mvm, pkt);
if (ret < 0)
return true; return true;
*temp = ret;
return true;
}
int iwl_mvm_temp_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
int temp;
/* the notification is handled synchronously in ctkill, so skip here */
if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
return 0;
temp = iwl_mvm_temp_notif_parse(mvm, pkt);
if (temp < 0)
return 0;
iwl_mvm_tt_temp_changed(mvm, temp);
return 0;
} }
static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
...@@ -141,7 +190,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm) ...@@ -141,7 +190,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm)
iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
temp_notif, ARRAY_SIZE(temp_notif), temp_notif, ARRAY_SIZE(temp_notif),
iwl_mvm_temp_notif, &temp); iwl_mvm_temp_notif_wait, &temp);
ret = iwl_mvm_get_temp_cmd(mvm); ret = iwl_mvm_get_temp_cmd(mvm);
if (ret) { if (ret) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1431,6 +1431,9 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, ...@@ -1431,6 +1431,9 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
trans_pcie->cmd_in_flight = true; trans_pcie->cmd_in_flight = true;
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
udelay(2);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL, ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
......
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