mirror of
https://github.com/torvalds/linux.git
synced 2024-12-16 08:02:17 +00:00
* Location Aware Regulatory was added by Arik
* 8000 device family work * Update to the BT Coex firmware API -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVAYnmAAoJEC0Llv5uNjIB3MUQAIhWBI+R9s6Dzz0stjs+CdJX V5k/yNOleRuwVPXzIbeX8hN+rAuiIoxS1/SLi7vRqNRwuz7Wn0DFIXsK9+WG3kQ1 3KOtY3LpJyoVxGck6vxmVZN9tFMFH0RpYuz54XY3qO7ZXDPBfB3VZCD3AH2faAWW S990Wg7W8z92L8XFBzfnJ+6gF5iiS7LP14dqvRu05Gp1NoZog8s0DMZrpSYuVg6u AyobaA9RGfJ90f9e/RX5KbTZE5LUFSEYUmB95LXJkqDGu6zj2ac9VNoSczstjuvb s7ceA9Ds3WCghvfUUcIVnBVBcjkVa4I9UbbKR7lHyj+4rOfWO0XO9qNOXRrqfDhx KB0eQN9S4cEOML5HeX/d+63Pm1fcRT0TzE7O+LIzBNQUd1jQC5hyK6Src2rLK/6w XS2wEU0qnKYMqzl6GzhQsSzfaFfMand65+podYSdMPVi0qjZ70wTFe+vGL1cwnVJ zXn/xxonNadH/IRdEP/roJK8vVnk2uSwJePxGgrQzIIqWYQmRm0KsreKY0dg4B9R dPmZW2FaWPnuv2/RyDe0VWuC2jr1ZdEcXuVF7lykPMkcy1CyLBrWSN/DIeXchQUN 5QF+dKTJc4IWN+NgOSW5ADXeR8mMSGnyoBmm8FlrmtBbFsiSKkWYwOdaZ0q1ODhL 8GIrb23uFg93mOXIJlrF =l2Ap -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-for-kalle-2015-03-12' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next * Location Aware Regulatory was added by Arik * 8000 device family work * Update to the BT Coex firmware API
This commit is contained in:
commit
0cf151bdf9
@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
|
||||
BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
|
||||
|
||||
if (vif)
|
||||
scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
|
||||
if (iwlagn_txfifo_flush(priv, scd_queues)) {
|
||||
IWL_ERR(priv, "flush request fail\n");
|
||||
goto done;
|
||||
if (drop) {
|
||||
IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n",
|
||||
scd_queues);
|
||||
if (iwlagn_txfifo_flush(priv, scd_queues)) {
|
||||
IWL_ERR(priv, "flush request fail\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
|
||||
iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
|
||||
iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues);
|
||||
done:
|
||||
mutex_unlock(&priv->mutex);
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
|
@ -3153,12 +3153,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
||||
desc += sprintf(buff+desc, "lq type %s\n",
|
||||
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
|
||||
if (is_Ht(tbl->lq_type)) {
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
desc += sprintf(buff + desc, " %s",
|
||||
(is_siso(tbl->lq_type)) ? "SISO" :
|
||||
((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
desc += sprintf(buff + desc, " %s",
|
||||
(tbl->is_ht40) ? "40MHz" : "20MHz");
|
||||
desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "",
|
||||
desc += sprintf(buff + desc, " %s %s %s\n",
|
||||
(tbl->is_SGI) ? "SGI" : "",
|
||||
(lq_sta->is_green) ? "GF enabled" : "",
|
||||
(lq_sta->is_agg) ? "AGG on" : "");
|
||||
}
|
||||
|
@ -189,9 +189,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
/* Set up antennas */
|
||||
if (priv->lib->bt_params &&
|
||||
priv->lib->bt_params->advanced_bt_coexist &&
|
||||
priv->bt_full_concurrent) {
|
||||
if (priv->lib->bt_params &&
|
||||
priv->lib->bt_params->advanced_bt_coexist &&
|
||||
priv->bt_full_concurrent) {
|
||||
/* operated as 1x1 in full concurrency mode */
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
|
||||
first_antenna(priv->nvm_data->valid_tx_ant));
|
||||
|
@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = {
|
||||
.nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.eeprom_params = &iwl1000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl1000_bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
|
||||
@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = {
|
||||
.base_params = &iwl1000_base_params, \
|
||||
.eeprom_params = &iwl1000_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.rx_with_siso_diversity = true
|
||||
.rx_with_siso_diversity = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl100_bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
|
||||
|
@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
|
||||
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
|
||||
const struct iwl_cfg iwl2000_2bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
|
||||
@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
|
||||
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl2030_2bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
|
||||
@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
|
||||
.base_params = &iwl2000_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.rx_with_siso_diversity = true
|
||||
.rx_with_siso_diversity = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl105_bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
|
||||
@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
|
||||
.base_params = &iwl2030_base_params, \
|
||||
.eeprom_params = &iwl20x0_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.rx_with_siso_diversity = true
|
||||
.rx_with_siso_diversity = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl135_bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
|
||||
|
@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = {
|
||||
.nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.eeprom_params = &iwl5000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl5300_agn_cfg = {
|
||||
.name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
|
||||
@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = {
|
||||
.base_params = &iwl5000_base_params, \
|
||||
.eeprom_params = &iwl5000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
||||
.internal_wimax_coex = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl5150_agn_cfg = {
|
||||
.name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
|
||||
|
@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
|
||||
.nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6005_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
|
||||
@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
|
||||
.nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6030_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
|
||||
@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
|
||||
.nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_g2_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_RF_STATE
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6035_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
|
||||
@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = {
|
||||
.nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \
|
||||
.base_params = &iwl6000_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6000i_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
|
||||
@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = {
|
||||
.base_params = &iwl6050_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
||||
.internal_wimax_coex = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6050_2agn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
|
||||
@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = {
|
||||
.base_params = &iwl6050_base_params, \
|
||||
.eeprom_params = &iwl6000_eeprom_params, \
|
||||
.led_mode = IWL_LED_BLINK, \
|
||||
.internal_wimax_coex = true
|
||||
.internal_wimax_coex = true, \
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
|
||||
|
||||
const struct iwl_cfg iwl6150_bgn_cfg = {
|
||||
.name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
|
||||
|
@ -69,12 +69,12 @@
|
||||
#include "iwl-agn-hw.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL7260_UCODE_API_MAX 12
|
||||
#define IWL3160_UCODE_API_MAX 12
|
||||
#define IWL7260_UCODE_API_MAX 13
|
||||
#define IWL3160_UCODE_API_MAX 13
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL7260_UCODE_API_OK 10
|
||||
#define IWL3160_UCODE_API_OK 10
|
||||
#define IWL7260_UCODE_API_OK 12
|
||||
#define IWL3160_UCODE_API_OK 12
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL7260_UCODE_API_MIN 10
|
||||
|
@ -69,10 +69,10 @@
|
||||
#include "iwl-agn-hw.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL8000_UCODE_API_MAX 12
|
||||
#define IWL8000_UCODE_API_MAX 13
|
||||
|
||||
/* Oldest version we won't warn about */
|
||||
#define IWL8000_UCODE_API_OK 10
|
||||
#define IWL8000_UCODE_API_OK 12
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL8000_UCODE_API_MIN 10
|
||||
|
@ -157,6 +157,7 @@ do { \
|
||||
/* 0x0000F000 - 0x00001000 */
|
||||
#define IWL_DL_ASSOC 0x00001000
|
||||
#define IWL_DL_DROP 0x00002000
|
||||
#define IWL_DL_LAR 0x00004000
|
||||
#define IWL_DL_COEX 0x00008000
|
||||
/* 0x000F0000 - 0x00010000 */
|
||||
#define IWL_DL_FW 0x00010000
|
||||
@ -219,5 +220,6 @@ do { \
|
||||
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
|
||||
#define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a)
|
||||
#define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a)
|
||||
#define IWL_DEBUG_LAR(p, f, a...) IWL_DEBUG(p, IWL_DL_LAR, f, ## a)
|
||||
|
||||
#endif
|
||||
|
@ -1014,34 +1014,34 @@ static int validate_sec_sizes(struct iwl_drv *drv,
|
||||
|
||||
/* Verify that uCode images will fit in card's SRAM. */
|
||||
if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) >
|
||||
cfg->max_inst_size) {
|
||||
cfg->max_inst_size) {
|
||||
IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n",
|
||||
get_sec_size(pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_INST));
|
||||
IWL_UCODE_SECTION_INST));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) >
|
||||
cfg->max_data_size) {
|
||||
cfg->max_data_size) {
|
||||
IWL_ERR(drv, "uCode data len %Zd too large to fit in\n",
|
||||
get_sec_size(pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) >
|
||||
cfg->max_inst_size) {
|
||||
if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) >
|
||||
cfg->max_inst_size) {
|
||||
IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n",
|
||||
get_sec_size(pieces, IWL_UCODE_INIT,
|
||||
IWL_UCODE_SECTION_INST));
|
||||
IWL_UCODE_SECTION_INST));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) >
|
||||
cfg->max_data_size) {
|
||||
cfg->max_data_size) {
|
||||
IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n",
|
||||
get_sec_size(pieces, IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
IWL_UCODE_SECTION_DATA));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@ -1546,6 +1546,10 @@ module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
|
||||
bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
|
||||
|
||||
module_param_named(lar_disable, iwlwifi_mod_params.lar_disable,
|
||||
bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)");
|
||||
|
||||
module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
|
||||
bool, S_IRUGO | S_IWUSR);
|
||||
#ifdef CONFIG_IWLWIFI_UAPSD
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
/* for all modules */
|
||||
#define DRV_NAME "iwlwifi"
|
||||
#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation"
|
||||
#define DRV_COPYRIGHT "Copyright(c) 2003- 2015 Intel Corporation"
|
||||
#define DRV_AUTHOR "<ilw@linux.intel.com>"
|
||||
|
||||
/* radio config bits (actual values from NVM definition) */
|
||||
|
@ -94,6 +94,7 @@ struct iwl_nvm_data {
|
||||
u32 nvm_version;
|
||||
s8 max_tx_pwr_half_dbm;
|
||||
|
||||
bool lar_enabled;
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
struct ieee80211_channel channels[];
|
||||
};
|
||||
|
@ -240,10 +240,9 @@ enum iwl_ucode_tlv_flag {
|
||||
/**
|
||||
* enum iwl_ucode_tlv_api - ucode api
|
||||
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
|
||||
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
|
||||
* @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
|
||||
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
|
||||
* longer than the passive one, which is essential for fragmented scan.
|
||||
* @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
|
||||
* IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
|
||||
* @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
|
||||
* regardless of the band or the number of the probes. FW will calculate
|
||||
@ -258,9 +257,8 @@ enum iwl_ucode_tlv_flag {
|
||||
*/
|
||||
enum iwl_ucode_tlv_api {
|
||||
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
|
||||
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
|
||||
IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
|
||||
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
|
||||
IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9),
|
||||
IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
|
||||
IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13),
|
||||
IWL_UCODE_TLV_API_SCD_CFG = BIT(15),
|
||||
@ -292,6 +290,7 @@ enum iwl_ucode_tlv_api {
|
||||
* @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
|
||||
* @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
|
||||
* @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
|
||||
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
|
||||
*/
|
||||
enum iwl_ucode_tlv_capa {
|
||||
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
|
||||
@ -308,6 +307,7 @@ enum iwl_ucode_tlv_capa {
|
||||
IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
|
||||
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
|
||||
IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28),
|
||||
IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30),
|
||||
};
|
||||
|
||||
/* The default calibrate table size if not specified by firmware file */
|
||||
|
@ -201,6 +201,8 @@ void iwl_force_nmi(struct iwl_trans *trans)
|
||||
} else {
|
||||
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
|
||||
DEVICE_SET_NMI_8000B_VAL);
|
||||
iwl_write_prph(trans, DEVICE_SET_NMI_REG,
|
||||
DEVICE_SET_NMI_VAL_DRV);
|
||||
}
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_force_nmi);
|
||||
|
@ -103,6 +103,7 @@ enum iwl_disable_11n {
|
||||
* @debug_level: levels are IWL_DL_*
|
||||
* @ant_coupling: antenna coupling in dB, default = 0
|
||||
* @d0i3_disable: disable d0i3, default = 1,
|
||||
* @lar_disable: disable LAR (regulatory), default = 0
|
||||
* @fw_monitor: allow to use firmware monitor
|
||||
*/
|
||||
struct iwl_mod_params {
|
||||
@ -121,6 +122,7 @@ struct iwl_mod_params {
|
||||
char *nvm_file;
|
||||
bool uapsd_disable;
|
||||
bool d0i3_disable;
|
||||
bool lar_disable;
|
||||
bool fw_monitor;
|
||||
};
|
||||
|
||||
|
@ -103,8 +103,16 @@ enum family_8000_nvm_offsets {
|
||||
SKU_FAMILY_8000 = 4,
|
||||
N_HW_ADDRS_FAMILY_8000 = 5,
|
||||
|
||||
/* NVM PHY-SKU-Section offset (in words) for B0 */
|
||||
RADIO_CFG_FAMILY_8000_B0 = 0,
|
||||
SKU_FAMILY_8000_B0 = 2,
|
||||
N_HW_ADDRS_FAMILY_8000_B0 = 3,
|
||||
|
||||
/* NVM REGULATORY -Section offset (in words) definitions */
|
||||
NVM_CHANNELS_FAMILY_8000 = 0,
|
||||
NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7,
|
||||
NVM_LAR_OFFSET_FAMILY_8000 = 0x507,
|
||||
NVM_LAR_ENABLED_FAMILY_8000 = 0x7,
|
||||
|
||||
/* NVM calibration section offset (in words) definitions */
|
||||
NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
|
||||
@ -146,7 +154,9 @@ static const u8 iwl_nvm_channels_family_8000[] = {
|
||||
#define NUM_2GHZ_CHANNELS_FAMILY_8000 14
|
||||
#define FIRST_2GHZ_HT_MINUS 5
|
||||
#define LAST_2GHZ_HT_PLUS 9
|
||||
#define LAST_5GHZ_HT 161
|
||||
#define LAST_5GHZ_HT 165
|
||||
#define LAST_5GHZ_HT_FAMILY_8000 181
|
||||
#define N_HW_ADDR_MASK 0xF
|
||||
|
||||
/* rate data (static) */
|
||||
static struct ieee80211_rate iwl_cfg80211_rates[] = {
|
||||
@ -201,9 +211,57 @@ enum iwl_nvm_channel_flags {
|
||||
#define CHECK_AND_PRINT_I(x) \
|
||||
((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
|
||||
|
||||
static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
|
||||
u16 nvm_flags, const struct iwl_cfg *cfg)
|
||||
{
|
||||
u32 flags = IEEE80211_CHAN_NO_HT40;
|
||||
u32 last_5ghz_ht = LAST_5GHZ_HT;
|
||||
|
||||
if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
||||
last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
|
||||
|
||||
if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if (ch_num <= LAST_2GHZ_HT_PLUS)
|
||||
flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
if (ch_num >= FIRST_2GHZ_HT_MINUS)
|
||||
flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
} else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
|
||||
flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
else
|
||||
flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
}
|
||||
if (!(nvm_flags & NVM_CHANNEL_80MHZ))
|
||||
flags |= IEEE80211_CHAN_NO_80MHZ;
|
||||
if (!(nvm_flags & NVM_CHANNEL_160MHZ))
|
||||
flags |= IEEE80211_CHAN_NO_160MHZ;
|
||||
|
||||
if (!(nvm_flags & NVM_CHANNEL_IBSS))
|
||||
flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
|
||||
flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (nvm_flags & NVM_CHANNEL_RADAR)
|
||||
flags |= IEEE80211_CHAN_RADAR;
|
||||
|
||||
if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
|
||||
flags |= IEEE80211_CHAN_INDOOR_ONLY;
|
||||
|
||||
/* Set the GO concurrent flag only in case that NO_IR is set.
|
||||
* Otherwise it is meaningless
|
||||
*/
|
||||
if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
|
||||
(flags & IEEE80211_CHAN_NO_IR))
|
||||
flags |= IEEE80211_CHAN_GO_CONCURRENT;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data,
|
||||
const __le16 * const nvm_ch_flags)
|
||||
const __le16 * const nvm_ch_flags,
|
||||
bool lar_supported)
|
||||
{
|
||||
int ch_idx;
|
||||
int n_channels = 0;
|
||||
@ -228,9 +286,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
||||
|
||||
if (ch_idx >= num_2ghz_channels &&
|
||||
!data->sku_cap_band_52GHz_enable)
|
||||
ch_flags &= ~NVM_CHANNEL_VALID;
|
||||
continue;
|
||||
|
||||
if (!(ch_flags & NVM_CHANNEL_VALID)) {
|
||||
if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
|
||||
/*
|
||||
* Channels might become valid later if lar is
|
||||
* supported, hence we still want to add them to
|
||||
* the list of supported channels to cfg80211.
|
||||
*/
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d Flags %x [%sGHz] - No traffic\n",
|
||||
nvm_chan[ch_idx],
|
||||
@ -250,45 +313,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
||||
ieee80211_channel_to_frequency(
|
||||
channel->hw_value, channel->band);
|
||||
|
||||
/* TODO: Need to be dependent to the NVM */
|
||||
channel->flags = IEEE80211_CHAN_NO_HT40;
|
||||
if (ch_idx < num_2ghz_channels &&
|
||||
(ch_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
} else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
|
||||
(ch_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if ((ch_idx - num_2ghz_channels) % 2 == 0)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
else
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
}
|
||||
if (!(ch_flags & NVM_CHANNEL_80MHZ))
|
||||
channel->flags |= IEEE80211_CHAN_NO_80MHZ;
|
||||
if (!(ch_flags & NVM_CHANNEL_160MHZ))
|
||||
channel->flags |= IEEE80211_CHAN_NO_160MHZ;
|
||||
|
||||
if (!(ch_flags & NVM_CHANNEL_IBSS))
|
||||
channel->flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (!(ch_flags & NVM_CHANNEL_ACTIVE))
|
||||
channel->flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (ch_flags & NVM_CHANNEL_RADAR)
|
||||
channel->flags |= IEEE80211_CHAN_RADAR;
|
||||
|
||||
if (ch_flags & NVM_CHANNEL_INDOOR_ONLY)
|
||||
channel->flags |= IEEE80211_CHAN_INDOOR_ONLY;
|
||||
|
||||
/* Set the GO concurrent flag only in case that NO_IR is set.
|
||||
* Otherwise it is meaningless
|
||||
*/
|
||||
if ((ch_flags & NVM_CHANNEL_GO_CONCURRENT) &&
|
||||
(channel->flags & IEEE80211_CHAN_NO_IR))
|
||||
channel->flags |= IEEE80211_CHAN_GO_CONCURRENT;
|
||||
|
||||
/* Initialize regulatory-based run-time data */
|
||||
|
||||
/*
|
||||
@ -297,6 +321,15 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
||||
*/
|
||||
channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
|
||||
is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
|
||||
|
||||
/* don't put limitations in case we're using LAR */
|
||||
if (!lar_supported)
|
||||
channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx],
|
||||
ch_idx, is_5ghz,
|
||||
ch_flags, cfg);
|
||||
else
|
||||
channel->flags = 0;
|
||||
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
|
||||
channel->hw_value,
|
||||
@ -370,8 +403,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
||||
|
||||
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data,
|
||||
const __le16 *ch_section, bool enable_vht,
|
||||
u8 tx_chains, u8 rx_chains)
|
||||
const __le16 *ch_section,
|
||||
u8 tx_chains, u8 rx_chains, bool lar_supported)
|
||||
{
|
||||
int n_channels;
|
||||
int n_used = 0;
|
||||
@ -380,11 +413,12 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
n_channels = iwl_init_channel_map(
|
||||
dev, cfg, data,
|
||||
&ch_section[NVM_CHANNELS]);
|
||||
&ch_section[NVM_CHANNELS], lar_supported);
|
||||
else
|
||||
n_channels = iwl_init_channel_map(
|
||||
dev, cfg, data,
|
||||
&ch_section[NVM_CHANNELS_FAMILY_8000]);
|
||||
&ch_section[NVM_CHANNELS_FAMILY_8000],
|
||||
lar_supported);
|
||||
|
||||
sband = &data->bands[IEEE80211_BAND_2GHZ];
|
||||
sband->band = IEEE80211_BAND_2GHZ;
|
||||
@ -403,7 +437,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
IEEE80211_BAND_5GHZ);
|
||||
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
|
||||
tx_chains, rx_chains);
|
||||
if (enable_vht)
|
||||
if (data->sku_cap_11ac_enable)
|
||||
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
|
||||
tx_chains, rx_chains);
|
||||
|
||||
@ -413,10 +447,15 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
}
|
||||
|
||||
static int iwl_get_sku(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
const __le16 *nvm_sw, const __le16 *phy_sku,
|
||||
bool is_family_8000_a_step)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + SKU);
|
||||
|
||||
if (!is_family_8000_a_step)
|
||||
return le32_to_cpup((__le32 *)(phy_sku +
|
||||
SKU_FAMILY_8000_B0));
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
|
||||
}
|
||||
@ -432,23 +471,36 @@ static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
|
||||
}
|
||||
|
||||
static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
const __le16 *nvm_sw, const __le16 *phy_sku,
|
||||
bool is_family_8000_a_step)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + RADIO_CFG);
|
||||
|
||||
if (!is_family_8000_a_step)
|
||||
return le32_to_cpup((__le32 *)(phy_sku +
|
||||
RADIO_CFG_FAMILY_8000_B0));
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
|
||||
|
||||
}
|
||||
|
||||
#define N_HW_ADDRS_MASK_FAMILY_8000 0xF
|
||||
static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
const __le16 *nvm_sw, bool is_family_8000_a_step)
|
||||
{
|
||||
int n_hw_addr;
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + N_HW_ADDRS);
|
||||
|
||||
if (!is_family_8000_a_step)
|
||||
n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
|
||||
N_HW_ADDRS_FAMILY_8000_B0));
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000))
|
||||
& N_HW_ADDRS_MASK_FAMILY_8000;
|
||||
n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
|
||||
N_HW_ADDRS_FAMILY_8000));
|
||||
|
||||
return n_hw_addr & N_HW_ADDR_MASK;
|
||||
}
|
||||
|
||||
static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
|
||||
@ -491,7 +543,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
|
||||
const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data,
|
||||
const __le16 *mac_override,
|
||||
const __le16 *nvm_hw)
|
||||
const __le16 *nvm_hw,
|
||||
u32 mac_addr0, u32 mac_addr1)
|
||||
{
|
||||
const u8 *hw_addr;
|
||||
|
||||
@ -515,48 +568,17 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
|
||||
}
|
||||
|
||||
if (nvm_hw) {
|
||||
/* read the MAC address from OTP */
|
||||
if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) {
|
||||
/* read the mac address from the WFPM location */
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR0_WFPM_FAMILY_8000);
|
||||
data->hw_addr[0] = hw_addr[3];
|
||||
data->hw_addr[1] = hw_addr[2];
|
||||
data->hw_addr[2] = hw_addr[1];
|
||||
data->hw_addr[3] = hw_addr[0];
|
||||
/* read the MAC address from HW resisters */
|
||||
hw_addr = (const u8 *)&mac_addr0;
|
||||
data->hw_addr[0] = hw_addr[3];
|
||||
data->hw_addr[1] = hw_addr[2];
|
||||
data->hw_addr[2] = hw_addr[1];
|
||||
data->hw_addr[3] = hw_addr[0];
|
||||
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR1_WFPM_FAMILY_8000);
|
||||
data->hw_addr[4] = hw_addr[1];
|
||||
data->hw_addr[5] = hw_addr[0];
|
||||
} else if ((data->nvm_version >= 0xE08) &&
|
||||
(data->nvm_version < 0xE0B)) {
|
||||
/* read "reverse order" from the PCIe location */
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR0_PCIE_FAMILY_8000);
|
||||
data->hw_addr[5] = hw_addr[2];
|
||||
data->hw_addr[4] = hw_addr[1];
|
||||
data->hw_addr[3] = hw_addr[0];
|
||||
hw_addr = (const u8 *)&mac_addr1;
|
||||
data->hw_addr[4] = hw_addr[1];
|
||||
data->hw_addr[5] = hw_addr[0];
|
||||
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR1_PCIE_FAMILY_8000);
|
||||
data->hw_addr[2] = hw_addr[3];
|
||||
data->hw_addr[1] = hw_addr[2];
|
||||
data->hw_addr[0] = hw_addr[1];
|
||||
} else {
|
||||
/* read from the PCIe location */
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR0_PCIE_FAMILY_8000);
|
||||
data->hw_addr[5] = hw_addr[0];
|
||||
data->hw_addr[4] = hw_addr[1];
|
||||
data->hw_addr[3] = hw_addr[2];
|
||||
|
||||
hw_addr = (const u8 *)(nvm_hw +
|
||||
HW_ADDR1_PCIE_FAMILY_8000);
|
||||
data->hw_addr[2] = hw_addr[1];
|
||||
data->hw_addr[1] = hw_addr[2];
|
||||
data->hw_addr[0] = hw_addr[3];
|
||||
}
|
||||
if (!is_valid_ether_addr(data->hw_addr))
|
||||
IWL_ERR_DEV(dev,
|
||||
"mac address from hw section is not valid\n");
|
||||
@ -571,11 +593,15 @@ struct iwl_nvm_data *
|
||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_hw, const __le16 *nvm_sw,
|
||||
const __le16 *nvm_calib, const __le16 *regulatory,
|
||||
const __le16 *mac_override, u8 tx_chains, u8 rx_chains)
|
||||
const __le16 *mac_override, const __le16 *phy_sku,
|
||||
u8 tx_chains, u8 rx_chains,
|
||||
bool lar_fw_supported, bool is_family_8000_a_step,
|
||||
u32 mac_addr0, u32 mac_addr1)
|
||||
{
|
||||
struct iwl_nvm_data *data;
|
||||
u32 sku;
|
||||
u32 radio_cfg;
|
||||
u16 lar_config;
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
data = kzalloc(sizeof(*data) +
|
||||
@ -592,22 +618,25 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
|
||||
data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
|
||||
|
||||
radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
|
||||
radio_cfg =
|
||||
iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
|
||||
iwl_set_radio_cfg(cfg, data, radio_cfg);
|
||||
if (data->valid_tx_ant)
|
||||
tx_chains &= data->valid_tx_ant;
|
||||
if (data->valid_rx_ant)
|
||||
rx_chains &= data->valid_rx_ant;
|
||||
|
||||
sku = iwl_get_sku(cfg, nvm_sw);
|
||||
sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
|
||||
data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
|
||||
data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
|
||||
data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
|
||||
data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE;
|
||||
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
|
||||
data->sku_cap_11n_enable = false;
|
||||
data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
|
||||
(sku & NVM_SKU_CAP_11AC_ENABLE);
|
||||
|
||||
data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
|
||||
data->n_hw_addrs =
|
||||
iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step);
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
/* Checking for required sections */
|
||||
@ -626,16 +655,23 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
iwl_set_hw_address(cfg, data, nvm_hw);
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, nvm_sw,
|
||||
sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
|
||||
rx_chains);
|
||||
tx_chains, rx_chains, lar_fw_supported);
|
||||
} else {
|
||||
u16 lar_offset = data->nvm_version < 0xE39 ?
|
||||
NVM_LAR_OFFSET_FAMILY_8000_OLD :
|
||||
NVM_LAR_OFFSET_FAMILY_8000;
|
||||
|
||||
lar_config = le16_to_cpup(regulatory + lar_offset);
|
||||
data->lar_enabled = !!(lar_config &
|
||||
NVM_LAR_ENABLED_FAMILY_8000);
|
||||
|
||||
/* MAC address in family 8000 */
|
||||
iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
|
||||
nvm_hw);
|
||||
nvm_hw, mac_addr0, mac_addr1);
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, regulatory,
|
||||
sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
|
||||
rx_chains);
|
||||
tx_chains, rx_chains,
|
||||
lar_fw_supported && data->lar_enabled);
|
||||
}
|
||||
|
||||
data->calib_version = 255;
|
||||
@ -643,3 +679,164 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
return data;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
|
||||
|
||||
static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
|
||||
int ch_idx, u16 nvm_flags,
|
||||
const struct iwl_cfg *cfg)
|
||||
{
|
||||
u32 flags = NL80211_RRF_NO_HT40;
|
||||
u32 last_5ghz_ht = LAST_5GHZ_HT;
|
||||
|
||||
if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
||||
last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
|
||||
|
||||
if (ch_idx < NUM_2GHZ_CHANNELS &&
|
||||
(nvm_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
|
||||
flags &= ~NL80211_RRF_NO_HT40PLUS;
|
||||
if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
|
||||
flags &= ~NL80211_RRF_NO_HT40MINUS;
|
||||
} else if (nvm_chan[ch_idx] <= last_5ghz_ht &&
|
||||
(nvm_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
|
||||
flags &= ~NL80211_RRF_NO_HT40PLUS;
|
||||
else
|
||||
flags &= ~NL80211_RRF_NO_HT40MINUS;
|
||||
}
|
||||
|
||||
if (!(nvm_flags & NVM_CHANNEL_80MHZ))
|
||||
flags |= NL80211_RRF_NO_80MHZ;
|
||||
if (!(nvm_flags & NVM_CHANNEL_160MHZ))
|
||||
flags |= NL80211_RRF_NO_160MHZ;
|
||||
|
||||
if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
|
||||
flags |= NL80211_RRF_NO_IR;
|
||||
|
||||
if (nvm_flags & NVM_CHANNEL_RADAR)
|
||||
flags |= NL80211_RRF_DFS;
|
||||
|
||||
if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
|
||||
flags |= NL80211_RRF_NO_OUTDOOR;
|
||||
|
||||
/* Set the GO concurrent flag only in case that NO_IR is set.
|
||||
* Otherwise it is meaningless
|
||||
*/
|
||||
if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
|
||||
(flags & NL80211_RRF_NO_IR))
|
||||
flags |= NL80211_RRF_GO_CONCURRENT;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
struct ieee80211_regdomain *
|
||||
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
|
||||
int num_of_ch, __le32 *channels, u16 fw_mcc)
|
||||
{
|
||||
int ch_idx;
|
||||
u16 ch_flags, prev_ch_flags = 0;
|
||||
const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
|
||||
iwl_nvm_channels_family_8000 : iwl_nvm_channels;
|
||||
struct ieee80211_regdomain *regd;
|
||||
int size_of_regd;
|
||||
struct ieee80211_reg_rule *rule;
|
||||
enum ieee80211_band band;
|
||||
int center_freq, prev_center_freq = 0;
|
||||
int valid_rules = 0;
|
||||
bool new_rule;
|
||||
int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
|
||||
IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS;
|
||||
|
||||
if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (WARN_ON(num_of_ch > max_num_ch))
|
||||
num_of_ch = max_num_ch;
|
||||
|
||||
IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
|
||||
num_of_ch);
|
||||
|
||||
/* build a regdomain rule for every valid channel */
|
||||
size_of_regd =
|
||||
sizeof(struct ieee80211_regdomain) +
|
||||
num_of_ch * sizeof(struct ieee80211_reg_rule);
|
||||
|
||||
regd = kzalloc(size_of_regd, GFP_KERNEL);
|
||||
if (!regd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
|
||||
ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
|
||||
band = (ch_idx < NUM_2GHZ_CHANNELS) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
|
||||
band);
|
||||
new_rule = false;
|
||||
|
||||
if (!(ch_flags & NVM_CHANNEL_VALID)) {
|
||||
IWL_DEBUG_DEV(dev, IWL_DL_LAR,
|
||||
"Ch. %d Flags %x [%sGHz] - No traffic\n",
|
||||
nvm_chan[ch_idx],
|
||||
ch_flags,
|
||||
(ch_idx >= NUM_2GHZ_CHANNELS) ?
|
||||
"5.2" : "2.4");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we can't continue the same rule */
|
||||
if (ch_idx == 0 || prev_ch_flags != ch_flags ||
|
||||
center_freq - prev_center_freq > 20) {
|
||||
valid_rules++;
|
||||
new_rule = true;
|
||||
}
|
||||
|
||||
rule = ®d->reg_rules[valid_rules - 1];
|
||||
|
||||
if (new_rule)
|
||||
rule->freq_range.start_freq_khz =
|
||||
MHZ_TO_KHZ(center_freq - 10);
|
||||
|
||||
rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
|
||||
|
||||
/* this doesn't matter - not used by FW */
|
||||
rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
|
||||
rule->power_rule.max_eirp =
|
||||
DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);
|
||||
|
||||
rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
|
||||
ch_flags, cfg);
|
||||
|
||||
/* rely on auto-calculation to merge BW of contiguous chans */
|
||||
rule->flags |= NL80211_RRF_AUTO_BW;
|
||||
rule->freq_range.max_bandwidth_khz = 0;
|
||||
|
||||
prev_ch_flags = ch_flags;
|
||||
prev_center_freq = center_freq;
|
||||
|
||||
IWL_DEBUG_DEV(dev, IWL_DL_LAR,
|
||||
"Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n",
|
||||
center_freq,
|
||||
band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
|
||||
CHECK_AND_PRINT_I(VALID),
|
||||
CHECK_AND_PRINT_I(ACTIVE),
|
||||
CHECK_AND_PRINT_I(RADAR),
|
||||
CHECK_AND_PRINT_I(WIDE),
|
||||
CHECK_AND_PRINT_I(40MHZ),
|
||||
CHECK_AND_PRINT_I(80MHZ),
|
||||
CHECK_AND_PRINT_I(160MHZ),
|
||||
CHECK_AND_PRINT_I(INDOOR_ONLY),
|
||||
CHECK_AND_PRINT_I(GO_CONCURRENT),
|
||||
ch_flags,
|
||||
((ch_flags & NVM_CHANNEL_ACTIVE) &&
|
||||
!(ch_flags & NVM_CHANNEL_RADAR))
|
||||
? "" : "not ");
|
||||
}
|
||||
|
||||
regd->n_reg_rules = valid_rules;
|
||||
|
||||
/* set alpha2 from FW. */
|
||||
regd->alpha2[0] = fw_mcc >> 8;
|
||||
regd->alpha2[1] = fw_mcc & 0xff;
|
||||
|
||||
return regd;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
|
||||
|
@ -62,6 +62,7 @@
|
||||
#ifndef __iwl_nvm_parse_h__
|
||||
#define __iwl_nvm_parse_h__
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
#include "iwl-eeprom-parse.h"
|
||||
|
||||
/**
|
||||
@ -76,6 +77,22 @@ struct iwl_nvm_data *
|
||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_hw, const __le16 *nvm_sw,
|
||||
const __le16 *nvm_calib, const __le16 *regulatory,
|
||||
const __le16 *mac_override, u8 tx_chains, u8 rx_chains);
|
||||
const __le16 *mac_override, const __le16 *phy_sku,
|
||||
u8 tx_chains, u8 rx_chains,
|
||||
bool lar_fw_supported, bool is_family_8000_a_step,
|
||||
u32 mac_addr0, u32 mac_addr1);
|
||||
|
||||
/**
|
||||
* iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
|
||||
*
|
||||
* This function parses the regulatory channel data received as a
|
||||
* MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain,
|
||||
* to be fed into the regulatory core. An ERR_PTR is returned on error.
|
||||
* If not given to the regulatory core, the user is responsible for freeing
|
||||
* the regdomain returned here with kfree.
|
||||
*/
|
||||
struct ieee80211_regdomain *
|
||||
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
|
||||
int num_of_ch, __le32 *channels, u16 fw_mcc);
|
||||
|
||||
#endif /* __iwl_nvm_parse_h__ */
|
||||
|
@ -371,6 +371,33 @@ enum secure_load_status_reg {
|
||||
|
||||
#define DBGC_IN_SAMPLE (0xa03c00)
|
||||
|
||||
/* enable the ID buf for read */
|
||||
#define WFPM_PS_CTL_CLR 0xA0300C
|
||||
#define WFMP_MAC_ADDR_0 0xA03080
|
||||
#define WFMP_MAC_ADDR_1 0xA03084
|
||||
#define LMPM_PMG_EN 0xA01CEC
|
||||
#define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078
|
||||
#define RFIC_REG_RD 0xAD0470
|
||||
#define WFPM_CTRL_REG 0xA03030
|
||||
enum {
|
||||
ENABLE_WFPM = BIT(31),
|
||||
WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000,
|
||||
};
|
||||
|
||||
#define AUX_MISC_REG 0xA200B0
|
||||
enum {
|
||||
HW_STEP_LOCATION_BITS = 24,
|
||||
};
|
||||
|
||||
#define AUX_MISC_MASTER1_EN 0xA20818
|
||||
enum aux_misc_master1_en {
|
||||
AUX_MISC_MASTER1_EN_SBE_MSK = 0x1,
|
||||
};
|
||||
|
||||
#define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800
|
||||
#define RSA_ENABLE 0xA24B08
|
||||
#define PREG_AUX_BUS_WPROT_0 0xA04CC0
|
||||
|
||||
/* FW chicken bits */
|
||||
#define LMPM_CHICK 0xA01FF8
|
||||
enum {
|
||||
|
@ -458,6 +458,8 @@ struct iwl_trans_txq_scd_cfg {
|
||||
* @txq_disable: de-configure a Tx queue to send AMPDUs
|
||||
* Must be atomic
|
||||
* @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
|
||||
* @freeze_txq_timer: prevents the timer of the queue from firing until the
|
||||
* queue is set to awake. Must be atomic.
|
||||
* @dbgfs_register: add the dbgfs files under this directory. Files will be
|
||||
* automatically deleted.
|
||||
* @write8: write a u8 to a register at offset ofs from the BAR
|
||||
@ -517,6 +519,8 @@ struct iwl_trans_ops {
|
||||
|
||||
int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
|
||||
int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
|
||||
void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
|
||||
bool freeze);
|
||||
|
||||
void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
|
||||
void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
|
||||
@ -873,6 +877,17 @@ void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo,
|
||||
iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans,
|
||||
unsigned long txqs,
|
||||
bool freeze)
|
||||
{
|
||||
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
|
||||
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
|
||||
|
||||
if (trans->ops->freeze_txq_timer)
|
||||
trans->ops->freeze_txq_timer(trans, txqs, freeze);
|
||||
}
|
||||
|
||||
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
|
||||
u32 txqs)
|
||||
{
|
||||
|
@ -72,158 +72,6 @@
|
||||
#include "mvm.h"
|
||||
#include "iwl-debug.h"
|
||||
|
||||
const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
||||
[BT_KILL_MSK_NEVER] = 0xffffffff,
|
||||
[BT_KILL_MSK_ALWAYS] = 0,
|
||||
};
|
||||
|
||||
const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
|
||||
cpu_to_le32(0xf0f0f0f0), /* 50% */
|
||||
cpu_to_le32(0xc0c0c0c0), /* 25% */
|
||||
cpu_to_le32(0xfcfcfcfc), /* 75% */
|
||||
cpu_to_le32(0xfefefefe), /* 87.5% */
|
||||
};
|
||||
|
||||
static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
};
|
||||
|
||||
static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
|
||||
{
|
||||
/* Tight */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0x00004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
/* Loose */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
/* Tx Tx disabled */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xeeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
};
|
||||
|
||||
/* 20MHz / 40MHz below / 40Mhz above*/
|
||||
static const __le64 iwl_ci_mask[][3] = {
|
||||
/* dummy entry for channel 0 */
|
||||
@ -596,14 +444,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
||||
goto send_cmd;
|
||||
}
|
||||
|
||||
bt_cmd->max_kill = cpu_to_le32(5);
|
||||
bt_cmd->bt4_antenna_isolation_thr =
|
||||
cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS);
|
||||
bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
|
||||
bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
|
||||
bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
|
||||
bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
|
||||
|
||||
mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE;
|
||||
bt_cmd->mode = cpu_to_le32(mode);
|
||||
|
||||
@ -622,18 +462,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
||||
|
||||
bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
|
||||
|
||||
if (mvm->cfg->bt_shared_single_ant)
|
||||
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
|
||||
sizeof(iwl_single_shared_ant));
|
||||
else
|
||||
memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
|
||||
sizeof(iwl_combined_lookup));
|
||||
|
||||
memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
|
||||
sizeof(iwl_bt_prio_boost));
|
||||
bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
|
||||
bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
|
||||
|
||||
send_cmd:
|
||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
|
||||
@ -644,48 +472,6 @@ send_cmd:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
|
||||
u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
|
||||
u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut);
|
||||
u32 ag = le32_to_cpu(notif->bt_activity_grading);
|
||||
struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
|
||||
u8 ack_kill_msk[NUM_PHY_CTX] = {};
|
||||
u8 cts_kill_msk[NUM_PHY_CTX] = {};
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut];
|
||||
cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut];
|
||||
|
||||
ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut];
|
||||
cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut];
|
||||
|
||||
/* Don't send HCMD if there is no update */
|
||||
if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) ||
|
||||
!memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk)))
|
||||
return 0;
|
||||
|
||||
memcpy(mvm->bt_ack_kill_msk, ack_kill_msk,
|
||||
sizeof(mvm->bt_ack_kill_msk));
|
||||
memcpy(mvm->bt_cts_kill_msk, cts_kill_msk,
|
||||
sizeof(mvm->bt_cts_kill_msk));
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) {
|
||||
cmd.boost_values[i].kill_ack_msk =
|
||||
cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]);
|
||||
cmd.boost_values[i].kill_cts_msk =
|
||||
cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]);
|
||||
}
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0,
|
||||
sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
|
||||
bool enable)
|
||||
{
|
||||
@ -793,7 +579,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (!vif->bss_conf.assoc)
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
|
||||
if (mvmvif->phy_ctxt &&
|
||||
IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
|
||||
mvmvif->phy_ctxt->id))
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
@ -950,9 +737,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
IWL_ERR(mvm, "Failed to send BT_CI cmd\n");
|
||||
memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
|
||||
@ -1073,9 +857,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_bt_rssi_iterator, &data);
|
||||
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
|
||||
|
@ -288,6 +288,65 @@ static const __le64 iwl_ci_mask[][3] = {
|
||||
},
|
||||
};
|
||||
|
||||
enum iwl_bt_kill_msk {
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_MAX,
|
||||
};
|
||||
|
||||
static const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
||||
[BT_KILL_MSK_NEVER] = 0xffffffff,
|
||||
[BT_KILL_MSK_ALWAYS] = 0,
|
||||
};
|
||||
|
||||
static const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
static const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
struct corunning_block_luts {
|
||||
u8 range;
|
||||
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
|
||||
@ -633,7 +692,7 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
|
||||
if (IWL_MVM_BT_COEX_TTC)
|
||||
bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC);
|
||||
|
||||
if (IWL_MVM_BT_COEX_RRC)
|
||||
if (iwl_mvm_bt_is_rrc_supported(mvm))
|
||||
bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC);
|
||||
|
||||
if (mvm->cfg->bt_shared_single_ant)
|
||||
@ -832,7 +891,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (!vif->bss_conf.assoc)
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
|
||||
if (mvmvif->phy_ctxt &&
|
||||
data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
IWL_DEBUG_COEX(data->mvm,
|
||||
|
@ -694,6 +694,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
|
||||
|
||||
if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm))
|
||||
IWL_ERR(mvm, "Failed to initialize D3 LAR information\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1596,7 +1599,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
|
||||
/* RF-kill already asserted again... */
|
||||
if (!cmd.resp_pkt) {
|
||||
ret = -ERFKILL;
|
||||
fw_status = ERR_PTR(-ERFKILL);
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
||||
@ -1605,7 +1608,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
if (len < status_size) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
ret = -EIO;
|
||||
fw_status = ERR_PTR(-EIO);
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
||||
@ -1613,7 +1616,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
if (len != (status_size +
|
||||
ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
ret = -EIO;
|
||||
fw_status = ERR_PTR(-EIO);
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
||||
@ -1621,7 +1624,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
|
||||
out_free_resp:
|
||||
iwl_free_resp(&cmd);
|
||||
return ret ? ERR_PTR(ret) : fw_status;
|
||||
return fw_status;
|
||||
}
|
||||
|
||||
/* releases the MVM mutex */
|
||||
@ -1874,6 +1877,12 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||
/* query SRAM first in case we want event logging */
|
||||
iwl_mvm_read_d3_sram(mvm);
|
||||
|
||||
/*
|
||||
* Query the current location and source from the D3 firmware so we
|
||||
* can play it back when we re-intiailize the D0 firmware
|
||||
*/
|
||||
iwl_mvm_update_changed_regdom(mvm);
|
||||
|
||||
if (mvm->net_detect) {
|
||||
iwl_mvm_query_netdetect_reasons(mvm, vif);
|
||||
/* has unlocked the mutex, so skip that */
|
||||
@ -1883,9 +1892,9 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (keep)
|
||||
mvm->keep_vif = vif;
|
||||
#endif
|
||||
/* has unlocked the mutex, so skip that */
|
||||
goto out_iterate;
|
||||
#endif
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
|
@ -562,11 +562,12 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
"\tSecondary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"BT Configuration CMD - 0=default, 1=never, 2=always\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill msk idx %d\n",
|
||||
mvm->bt_ack_kill_msk[0]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill msk idx %d\n",
|
||||
mvm->bt_cts_kill_msk[0]);
|
||||
|
||||
} else {
|
||||
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
|
||||
@ -579,21 +580,6 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary Channel Bitmap 0x%016llx\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary: ACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary: CTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary: ACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary: CTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]);
|
||||
|
||||
}
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
@ -235,36 +235,12 @@ enum iwl_bt_coex_enabled_modules {
|
||||
* struct iwl_bt_coex_cmd - bt coex configuration command
|
||||
* @mode: enum %iwl_bt_coex_mode
|
||||
* @enabled_modules: enum %iwl_bt_coex_enabled_modules
|
||||
* @max_kill: max count of Tx retries due to kill from PTA
|
||||
* @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
|
||||
* should be set by default
|
||||
* @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
|
||||
* should be set by default
|
||||
* @bt4_antenna_isolation_thr: antenna threshold value
|
||||
* @bt4_tx_tx_delta_freq_thr: TxTx delta frequency
|
||||
* @bt4_tx_rx_max_freq0: TxRx max frequency
|
||||
* @multiprio_lut: multi priority LUT configuration
|
||||
* @mplut_prio_boost: BT priority boost registers
|
||||
* @decision_lut: PTA decision LUT, per Prio-Ch
|
||||
*
|
||||
* The structure is used for the BT_COEX command.
|
||||
*/
|
||||
struct iwl_bt_coex_cmd {
|
||||
__le32 mode;
|
||||
__le32 enabled_modules;
|
||||
|
||||
__le32 max_kill;
|
||||
__le32 override_primary_lut;
|
||||
__le32 override_secondary_lut;
|
||||
__le32 bt4_antenna_isolation_thr;
|
||||
|
||||
__le32 bt4_tx_tx_delta_freq_thr;
|
||||
__le32 bt4_tx_rx_max_freq0;
|
||||
|
||||
__le32 multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE];
|
||||
__le32 mplut_prio_boost[BT_COEX_BOOST_SIZE];
|
||||
|
||||
__le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE];
|
||||
} __packed; /* BT_COEX_CMD_API_S_VER_6 */
|
||||
|
||||
/**
|
||||
@ -279,29 +255,6 @@ struct iwl_bt_coex_corun_lut_update_cmd {
|
||||
__le32 corun_lut40[BT_COEX_CORUN_LUT_SIZE];
|
||||
} __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_sw_boost - SW boost values
|
||||
* @wifi_tx_prio_boost: SW boost of wifi tx priority
|
||||
* @wifi_rx_prio_boost: SW boost of wifi rx priority
|
||||
* @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK.
|
||||
* @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS.
|
||||
*/
|
||||
struct iwl_bt_coex_sw_boost {
|
||||
__le32 wifi_tx_prio_boost;
|
||||
__le32 wifi_rx_prio_boost;
|
||||
__le32 kill_ack_msk;
|
||||
__le32 kill_cts_msk;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_sw_boost_update_cmd - command to update the SW boost
|
||||
* @boost_values: check struct %iwl_bt_coex_sw_boost - one for each channel
|
||||
* primary / secondary / low priority
|
||||
*/
|
||||
struct iwl_bt_coex_sw_boost_update_cmd {
|
||||
struct iwl_bt_coex_sw_boost boost_values[3];
|
||||
} __packed; /* BT_COEX_UPDATE_SW_BOOST_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_reduced_txp_update_cmd
|
||||
* @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the
|
||||
|
@ -212,6 +212,10 @@ enum {
|
||||
REPLY_RX_MPDU_CMD = 0xc1,
|
||||
BA_NOTIF = 0xc5,
|
||||
|
||||
/* Location Aware Regulatory */
|
||||
MCC_UPDATE_CMD = 0xc8,
|
||||
MCC_CHUB_UPDATE_CMD = 0xc9,
|
||||
|
||||
MARKER_CMD = 0xcb,
|
||||
|
||||
/* BT Coex */
|
||||
@ -362,7 +366,8 @@ enum {
|
||||
NVM_SECTION_TYPE_CALIBRATION = 4,
|
||||
NVM_SECTION_TYPE_PRODUCTION = 5,
|
||||
NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
|
||||
NVM_MAX_NUM_SECTIONS = 12,
|
||||
NVM_SECTION_TYPE_PHY_SKU = 12,
|
||||
NVM_MAX_NUM_SECTIONS = 13,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1442,7 +1447,19 @@ enum iwl_sf_scenario {
|
||||
#define SF_W_MARK_LEGACY 4096
|
||||
#define SF_W_MARK_SCAN 4096
|
||||
|
||||
/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
|
||||
/* SF Scenarios timers for default configuration (aligned to 32 uSec) */
|
||||
#define SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */
|
||||
#define SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */
|
||||
#define SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */
|
||||
#define SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */
|
||||
#define SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */
|
||||
#define SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */
|
||||
#define SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */
|
||||
#define SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */
|
||||
#define SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */
|
||||
#define SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */
|
||||
|
||||
/* SF Scenarios timers for BSS MAC configuration (aligned to 32 uSec) */
|
||||
#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */
|
||||
#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */
|
||||
#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */
|
||||
@ -1473,6 +1490,92 @@ struct iwl_sf_cfg_cmd {
|
||||
__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
|
||||
} __packed; /* SF_CFG_API_S_VER_2 */
|
||||
|
||||
/***********************************
|
||||
* Location Aware Regulatory (LAR) API - MCC updates
|
||||
***********************************/
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_update_cmd - Request the device to update geographic
|
||||
* regulatory profile according to the given MCC (Mobile Country Code).
|
||||
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
|
||||
* 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
|
||||
* MCC in the cmd response will be the relevant MCC in the NVM.
|
||||
* @mcc: given mobile country code
|
||||
* @source_id: the source from where we got the MCC, see iwl_mcc_source
|
||||
* @reserved: reserved for alignment
|
||||
*/
|
||||
struct iwl_mcc_update_cmd {
|
||||
__le16 mcc;
|
||||
u8 source_id;
|
||||
u8 reserved;
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_API_S */
|
||||
|
||||
/**
|
||||
* iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
|
||||
* Contains the new channel control profile map, if changed, and the new MCC
|
||||
* (mobile country code).
|
||||
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
|
||||
* @status: see &enum iwl_mcc_update_status
|
||||
* @mcc: the new applied MCC
|
||||
* @cap: capabilities for all channels which matches the MCC
|
||||
* @source_id: the MCC source, see iwl_mcc_source
|
||||
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
|
||||
* channels, depending on platform)
|
||||
* @channels: channel control data map, DWORD for each channel. Only the first
|
||||
* 16bits are used.
|
||||
*/
|
||||
struct iwl_mcc_update_resp {
|
||||
__le32 status;
|
||||
__le16 mcc;
|
||||
u8 cap;
|
||||
u8 source_id;
|
||||
__le32 n_channels;
|
||||
__le32 channels[0];
|
||||
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */
|
||||
|
||||
/**
|
||||
* struct iwl_mcc_chub_notif - chub notifies of mcc change
|
||||
* (MCC_CHUB_UPDATE_CMD = 0xc9)
|
||||
* The Chub (Communication Hub, CommsHUB) is a HW component that connects to
|
||||
* the cellular and connectivity cores that gets updates of the mcc, and
|
||||
* notifies the ucode directly of any mcc change.
|
||||
* The ucode requests the driver to request the device to update geographic
|
||||
* regulatory profile according to the given MCC (Mobile Country Code).
|
||||
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
|
||||
* 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
|
||||
* MCC in the cmd response will be the relevant MCC in the NVM.
|
||||
* @mcc: given mobile country code
|
||||
* @source_id: identity of the change originator, see iwl_mcc_source
|
||||
* @reserved1: reserved for alignment
|
||||
*/
|
||||
struct iwl_mcc_chub_notif {
|
||||
u16 mcc;
|
||||
u8 source_id;
|
||||
u8 reserved1;
|
||||
} __packed; /* LAR_MCC_NOTIFY_S */
|
||||
|
||||
enum iwl_mcc_update_status {
|
||||
MCC_RESP_NEW_CHAN_PROFILE,
|
||||
MCC_RESP_SAME_CHAN_PROFILE,
|
||||
MCC_RESP_INVALID,
|
||||
MCC_RESP_NVM_DISABLED,
|
||||
MCC_RESP_ILLEGAL,
|
||||
MCC_RESP_LOW_PRIORITY,
|
||||
};
|
||||
|
||||
enum iwl_mcc_source {
|
||||
MCC_SOURCE_OLD_FW = 0,
|
||||
MCC_SOURCE_ME = 1,
|
||||
MCC_SOURCE_BIOS = 2,
|
||||
MCC_SOURCE_3G_LTE_HOST = 3,
|
||||
MCC_SOURCE_3G_LTE_DEVICE = 4,
|
||||
MCC_SOURCE_WIFI = 5,
|
||||
MCC_SOURCE_RESERVED = 6,
|
||||
MCC_SOURCE_DEFAULT = 7,
|
||||
MCC_SOURCE_UNINITIALIZED = 8,
|
||||
MCC_SOURCE_GET_CURRENT = 0x10
|
||||
};
|
||||
|
||||
/* DTS measurements */
|
||||
|
||||
enum iwl_dts_measurement_flags {
|
||||
|
@ -739,6 +739,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* RTNL is not taken during Ct-kill, but we don't need to scan/Tx
|
||||
* anyway, so don't init MCC.
|
||||
*/
|
||||
if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) {
|
||||
ret = iwl_mvm_init_mcc(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
|
||||
ret = iwl_mvm_config_scan(mvm);
|
||||
if (ret)
|
||||
|
@ -86,6 +86,7 @@
|
||||
#include "iwl-fw-error-dump.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "iwl-nvm-parse.h"
|
||||
|
||||
static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
|
||||
{
|
||||
@ -301,6 +302,109 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
|
||||
const char *alpha2,
|
||||
enum iwl_mcc_source src_id,
|
||||
bool *changed)
|
||||
{
|
||||
struct ieee80211_regdomain *regd = NULL;
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mcc_update_resp *resp;
|
||||
|
||||
IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
|
||||
if (IS_ERR_OR_NULL(resp)) {
|
||||
IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
|
||||
PTR_RET(resp));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
*changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
|
||||
|
||||
regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
|
||||
__le32_to_cpu(resp->n_channels),
|
||||
resp->channels,
|
||||
__le16_to_cpu(resp->mcc));
|
||||
/* Store the return source id */
|
||||
src_id = resp->source_id;
|
||||
kfree(resp);
|
||||
if (IS_ERR_OR_NULL(regd)) {
|
||||
IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
|
||||
PTR_RET(regd));
|
||||
goto out;
|
||||
}
|
||||
|
||||
IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n",
|
||||
regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id);
|
||||
mvm->lar_regdom_set = true;
|
||||
mvm->mcc_src = src_id;
|
||||
|
||||
out:
|
||||
return regd;
|
||||
}
|
||||
|
||||
void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm)
|
||||
{
|
||||
bool changed;
|
||||
struct ieee80211_regdomain *regd;
|
||||
|
||||
if (!iwl_mvm_is_lar_supported(mvm))
|
||||
return;
|
||||
|
||||
regd = iwl_mvm_get_current_regdomain(mvm, &changed);
|
||||
if (!IS_ERR_OR_NULL(regd)) {
|
||||
/* only update the regulatory core if changed */
|
||||
if (changed)
|
||||
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
|
||||
|
||||
kfree(regd);
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
|
||||
bool *changed)
|
||||
{
|
||||
return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",
|
||||
iwl_mvm_is_wifi_mcc_supported(mvm) ?
|
||||
MCC_SOURCE_GET_CURRENT :
|
||||
MCC_SOURCE_OLD_FW, changed);
|
||||
}
|
||||
|
||||
int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
|
||||
{
|
||||
enum iwl_mcc_source used_src;
|
||||
struct ieee80211_regdomain *regd;
|
||||
const struct ieee80211_regdomain *r =
|
||||
rtnl_dereference(mvm->hw->wiphy->regd);
|
||||
|
||||
if (!r)
|
||||
return 0;
|
||||
|
||||
/* save the last source in case we overwrite it below */
|
||||
used_src = mvm->mcc_src;
|
||||
if (iwl_mvm_is_wifi_mcc_supported(mvm)) {
|
||||
/* Notify the firmware we support wifi location updates */
|
||||
regd = iwl_mvm_get_current_regdomain(mvm, NULL);
|
||||
if (!IS_ERR_OR_NULL(regd))
|
||||
kfree(regd);
|
||||
}
|
||||
|
||||
/* Now set our last stored MCC and source */
|
||||
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL);
|
||||
if (IS_ERR_OR_NULL(regd))
|
||||
return -EIO;
|
||||
|
||||
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
|
||||
kfree(regd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct ieee80211_hw *hw = mvm->hw;
|
||||
@ -356,8 +460,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
|
||||
if (iwl_mvm_is_lar_supported(mvm))
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
|
||||
else
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
@ -402,7 +510,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
|
||||
if ((mvm->fw->ucode_capa.capa[0] &
|
||||
IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
|
||||
(mvm->fw->ucode_capa.api[0] &
|
||||
IWL_UCODE_TLV_API_LQ_SS_PARAMS))
|
||||
hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
|
||||
}
|
||||
@ -1190,7 +1301,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
|
||||
|
||||
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
|
||||
iwl_mvm_d0i3_enable_tx(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
|
||||
ret);
|
||||
@ -1869,7 +1980,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
sizeof(mvmvif->beacon_stats));
|
||||
|
||||
/* add quota for this interface */
|
||||
ret = iwl_mvm_update_quotas(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, true, NULL);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm, "failed to update quotas\n");
|
||||
return;
|
||||
@ -1921,7 +2032,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
/* remove quota for this interface */
|
||||
ret = iwl_mvm_update_quotas(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update quotas\n");
|
||||
|
||||
@ -2040,7 +2151,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
/* power updated needs to be done before quotas */
|
||||
iwl_mvm_power_update_mac(mvm);
|
||||
|
||||
ret = iwl_mvm_update_quotas(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
if (ret)
|
||||
goto out_quota_failed;
|
||||
|
||||
@ -2106,7 +2217,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
|
||||
if (vif->p2p && mvm->p2p_device_vif)
|
||||
iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
|
||||
|
||||
iwl_mvm_update_quotas(mvm, NULL);
|
||||
iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, vif);
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
|
||||
@ -2245,6 +2356,12 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
|
||||
IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
@ -2271,7 +2388,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
iwl_mvm_cancel_scan(mvm);
|
||||
/* Due to a race condition, it's possible that mac80211 asks
|
||||
* us to stop a hw_scan when it's already stopped. This can
|
||||
* happen, for instance, if we stopped the scan ourselves,
|
||||
* called ieee80211_scan_completed() and the userspace called
|
||||
* cancel scan scan before ieee80211_scan_work() could run.
|
||||
* To handle that, simply return if the scan is not running.
|
||||
*/
|
||||
/* FIXME: for now, we ignore this race for UMAC scans, since
|
||||
* they don't set the scan_status.
|
||||
*/
|
||||
if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
|
||||
(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
|
||||
iwl_mvm_cancel_scan(mvm);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
@ -2313,25 +2442,35 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
unsigned long txqs = 0, tids = 0;
|
||||
int tid;
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
|
||||
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
|
||||
|
||||
if (tid_data->state != IWL_AGG_ON &&
|
||||
tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
|
||||
continue;
|
||||
|
||||
__set_bit(tid_data->txq_id, &txqs);
|
||||
|
||||
if (iwl_mvm_tid_queued(tid_data) == 0)
|
||||
continue;
|
||||
|
||||
__set_bit(tid, &tids);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case STA_NOTIFY_SLEEP:
|
||||
if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
|
||||
ieee80211_sta_block_awake(hw, sta, true);
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
|
||||
struct iwl_mvm_tid_data *tid_data;
|
||||
|
||||
tid_data = &mvmsta->tid_data[tid];
|
||||
if (tid_data->state != IWL_AGG_ON &&
|
||||
tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
|
||||
continue;
|
||||
if (iwl_mvm_tid_queued(tid_data) == 0)
|
||||
continue;
|
||||
for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT)
|
||||
ieee80211_sta_set_buffered(sta, tid, true);
|
||||
}
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
if (txqs)
|
||||
iwl_trans_freeze_txq_timer(mvm->trans, txqs, true);
|
||||
/*
|
||||
* The fw updates the STA to be asleep. Tx packets on the Tx
|
||||
* queues to this station will not be transmitted. The fw will
|
||||
@ -2341,11 +2480,15 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
case STA_NOTIFY_AWAKE:
|
||||
if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
|
||||
break;
|
||||
|
||||
if (txqs)
|
||||
iwl_trans_freeze_txq_timer(mvm->trans, txqs, false);
|
||||
iwl_mvm_sta_modify_ps_wake(mvm, sta);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
}
|
||||
|
||||
static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
|
||||
@ -2583,6 +2726,12 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
|
||||
IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!vif->bss_conf.idle) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
@ -2609,12 +2758,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
/* Due to a race condition, it's possible that mac80211 asks
|
||||
* us to stop a sched_scan when it's already stopped. This
|
||||
* can happen, for instance, if we stopped the scan ourselves,
|
||||
* called ieee80211_sched_scan_stopped() and the userspace called
|
||||
* stop sched scan scan before ieee80211_sched_scan_stopped_work()
|
||||
* could run. To handle this, simply return if the scan is
|
||||
* not running.
|
||||
*/
|
||||
/* FIXME: for now, we ignore this race for UMAC scans, since
|
||||
* they don't set the scan_status.
|
||||
*/
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
|
||||
!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_scan_offload_stop(mvm, false);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
iwl_mvm_wait_for_async_handlers(mvm);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
||||
@ -3127,14 +3293,14 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_MONITOR) {
|
||||
mvmvif->monitor_active = true;
|
||||
ret = iwl_mvm_update_quotas(mvm, NULL);
|
||||
ret = iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
if (ret)
|
||||
goto out_remove_binding;
|
||||
}
|
||||
|
||||
/* Handle binding during CSA */
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
iwl_mvm_update_quotas(mvm, NULL);
|
||||
iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
|
||||
}
|
||||
|
||||
@ -3158,7 +3324,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
|
||||
|
||||
iwl_mvm_update_quotas(mvm, NULL);
|
||||
iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
}
|
||||
|
||||
goto out;
|
||||
@ -3231,7 +3397,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
||||
break;
|
||||
}
|
||||
|
||||
iwl_mvm_update_quotas(mvm, disabled_vif);
|
||||
iwl_mvm_update_quotas(mvm, false, disabled_vif);
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
|
||||
out:
|
||||
@ -3423,7 +3589,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
|
||||
mvm->noa_duration = noa_duration;
|
||||
mvm->noa_vif = vif;
|
||||
|
||||
return iwl_mvm_update_quotas(mvm, NULL);
|
||||
return iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
|
||||
/* must be associated client vif - ignore authorized */
|
||||
if (!vif || vif->type != NL80211_IFTYPE_STATION ||
|
||||
|
@ -810,6 +810,9 @@ struct iwl_mvm {
|
||||
/* system time of last beacon (for AP/GO interface) */
|
||||
u32 ap_last_beacon_gp2;
|
||||
|
||||
bool lar_regdom_set;
|
||||
enum iwl_mcc_source mcc_src;
|
||||
|
||||
u8 low_latency_agg_frame_limit;
|
||||
|
||||
/* TDLS channel switch data */
|
||||
@ -910,6 +913,30 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
|
||||
(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
bool nvm_lar = mvm->nvm_data->lar_enabled;
|
||||
bool tlv_lar = mvm->fw->ucode_capa.capa[0] &
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
|
||||
|
||||
if (iwlwifi_mod_params.lar_disable)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Enable LAR only if it is supported by the FW (TLV) &&
|
||||
* enabled in the NVM
|
||||
*/
|
||||
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
||||
return nvm_lar && tlv_lar;
|
||||
else
|
||||
return tlv_lar;
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE;
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
|
||||
@ -921,6 +948,12 @@ static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm)
|
||||
IWL_MVM_BT_COEX_CORUNNING;
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_RRC) &&
|
||||
IWL_MVM_BT_COEX_RRC;
|
||||
}
|
||||
|
||||
extern const u8 iwl_mvm_ac_to_tx_fifo[];
|
||||
|
||||
struct iwl_rate_info {
|
||||
@ -1106,7 +1139,7 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
|
||||
/* Quota management */
|
||||
int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
||||
int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload,
|
||||
struct ieee80211_vif *disabled_vif);
|
||||
|
||||
/* Scanning */
|
||||
@ -1282,17 +1315,6 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
|
||||
enum iwl_bt_kill_msk {
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_MAX,
|
||||
};
|
||||
|
||||
extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
|
||||
extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
|
||||
extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX];
|
||||
|
||||
/* beacon filtering */
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
void
|
||||
@ -1389,6 +1411,23 @@ void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
|
||||
int iwl_mvm_get_temp(struct iwl_mvm *mvm);
|
||||
|
||||
/* Location Aware Regulatory */
|
||||
struct iwl_mcc_update_resp *
|
||||
iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
enum iwl_mcc_source src_id);
|
||||
int iwl_mvm_init_mcc(struct iwl_mvm *mvm);
|
||||
int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
|
||||
const char *alpha2,
|
||||
enum iwl_mcc_source src_id,
|
||||
bool *changed);
|
||||
struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
|
||||
bool *changed);
|
||||
int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm);
|
||||
|
||||
/* smart fifo */
|
||||
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
bool added_vif);
|
||||
|
@ -63,12 +63,16 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "mvm.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
#include "iwl-eeprom-read.h"
|
||||
#include "iwl-nvm-parse.h"
|
||||
#include "iwl-prph.h"
|
||||
|
||||
/* Default NVM size to read */
|
||||
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
|
||||
@ -262,7 +266,9 @@ static struct iwl_nvm_data *
|
||||
iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_nvm_section *sections = mvm->nvm_sections;
|
||||
const __le16 *hw, *sw, *calib, *regulatory, *mac_override;
|
||||
const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
|
||||
bool is_family_8000_a_step = false, lar_enabled;
|
||||
u32 mac_addr0, mac_addr1;
|
||||
|
||||
/* Checking for required sections */
|
||||
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
@ -286,22 +292,43 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
||||
"Can't parse mac_address, empty sections\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
|
||||
is_family_8000_a_step = true;
|
||||
|
||||
/* PHY_SKU section is mandatory in B0 */
|
||||
if (!is_family_8000_a_step &&
|
||||
!mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) {
|
||||
IWL_ERR(mvm,
|
||||
"Can't parse phy_sku in B0, empty sections\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(!mvm->cfg))
|
||||
return NULL;
|
||||
|
||||
/* read the mac address from WFMP registers */
|
||||
mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0);
|
||||
mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1);
|
||||
|
||||
hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
|
||||
sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
|
||||
calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
|
||||
regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
|
||||
mac_override =
|
||||
(const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
|
||||
phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data;
|
||||
|
||||
lar_enabled = !iwlwifi_mod_params.lar_disable &&
|
||||
(mvm->fw->ucode_capa.capa[0] &
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
|
||||
|
||||
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
|
||||
regulatory, mac_override,
|
||||
mvm->fw->valid_tx_ant,
|
||||
mvm->fw->valid_rx_ant);
|
||||
regulatory, mac_override, phy_sku,
|
||||
mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant,
|
||||
lar_enabled, is_family_8000_a_step,
|
||||
mac_addr0, mac_addr1);
|
||||
}
|
||||
|
||||
#define MAX_NVM_FILE_LEN 16384
|
||||
@ -570,3 +597,258 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iwl_mcc_update_resp *
|
||||
iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
||||
enum iwl_mcc_source src_id)
|
||||
{
|
||||
struct iwl_mcc_update_cmd mcc_update_cmd = {
|
||||
.mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]),
|
||||
.source_id = (u8)src_id,
|
||||
};
|
||||
struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
|
||||
struct iwl_rx_packet *pkt;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = MCC_UPDATE_CMD,
|
||||
.flags = CMD_WANT_SKB,
|
||||
.data = { &mcc_update_cmd },
|
||||
};
|
||||
|
||||
int ret;
|
||||
u32 status;
|
||||
int resp_len, n_channels;
|
||||
u16 mcc;
|
||||
|
||||
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
|
||||
|
||||
IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
|
||||
alpha2[0], alpha2[1], src_id);
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
pkt = cmd.resp_pkt;
|
||||
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n",
|
||||
pkt->hdr.flags);
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Extract MCC response */
|
||||
mcc_resp = (void *)pkt->data;
|
||||
status = le32_to_cpu(mcc_resp->status);
|
||||
|
||||
mcc = le16_to_cpu(mcc_resp->mcc);
|
||||
|
||||
/* W/A for a FW/NVM issue - returns 0x00 for the world domain */
|
||||
if (mcc == 0) {
|
||||
mcc = 0x3030; /* "00" - world */
|
||||
mcc_resp->mcc = cpu_to_le16(mcc);
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp->n_channels);
|
||||
IWL_DEBUG_LAR(mvm,
|
||||
"MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
|
||||
status, mcc, mcc >> 8, mcc & 0xff,
|
||||
!!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
|
||||
|
||||
resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
|
||||
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
|
||||
if (!resp_cp) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
iwl_free_resp(&cmd);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
return resp_cp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define WRD_METHOD "WRDD"
|
||||
#define WRDD_WIFI (0x07)
|
||||
#define WRDD_WIGIG (0x10)
|
||||
|
||||
static u32 iwl_mvm_wrdd_get_mcc(struct iwl_mvm *mvm, union acpi_object *wrdd)
|
||||
{
|
||||
union acpi_object *mcc_pkg, *domain_type, *mcc_value;
|
||||
u32 i;
|
||||
|
||||
if (wrdd->type != ACPI_TYPE_PACKAGE ||
|
||||
wrdd->package.count < 2 ||
|
||||
wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
wrdd->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_LAR(mvm, "Unsupported wrdd structure\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1 ; i < wrdd->package.count ; ++i) {
|
||||
mcc_pkg = &wrdd->package.elements[i];
|
||||
|
||||
if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
mcc_pkg->package.count < 2 ||
|
||||
mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
|
||||
mcc_pkg = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
domain_type = &mcc_pkg->package.elements[0];
|
||||
if (domain_type->integer.value == WRDD_WIFI)
|
||||
break;
|
||||
|
||||
mcc_pkg = NULL;
|
||||
}
|
||||
|
||||
if (mcc_pkg) {
|
||||
mcc_value = &mcc_pkg->package.elements[1];
|
||||
return mcc_value->integer.value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
|
||||
{
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
u32 mcc_val;
|
||||
struct pci_dev *pdev = to_pci_dev(mvm->dev);
|
||||
|
||||
root_handle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_LAR(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_LAR(mvm, "WRD method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call WRDD with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_LAR(mvm, "WRDC invocation failed (0x%x)\n", status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mcc_val = iwl_mvm_wrdd_get_mcc(mvm, wrdd.pointer);
|
||||
kfree(wrdd.pointer);
|
||||
if (!mcc_val)
|
||||
return -ENOENT;
|
||||
|
||||
mcc[0] = (mcc_val >> 8) & 0xff;
|
||||
mcc[1] = mcc_val & 0xff;
|
||||
mcc[2] = '\0';
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_ACPI */
|
||||
static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
|
||||
{
|
||||
bool tlv_lar;
|
||||
bool nvm_lar;
|
||||
int retval;
|
||||
struct ieee80211_regdomain *regd;
|
||||
char mcc[3];
|
||||
|
||||
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
|
||||
tlv_lar = mvm->fw->ucode_capa.capa[0] &
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
|
||||
nvm_lar = mvm->nvm_data->lar_enabled;
|
||||
if (tlv_lar != nvm_lar)
|
||||
IWL_INFO(mvm,
|
||||
"Conflict between TLV & NVM regarding enabling LAR (TLV = %s NVM =%s)\n",
|
||||
tlv_lar ? "enabled" : "disabled",
|
||||
nvm_lar ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
if (!iwl_mvm_is_lar_supported(mvm))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* During HW restart, only replay the last set MCC to FW. Otherwise,
|
||||
* queue an update to cfg80211 to retrieve the default alpha2 from FW.
|
||||
*/
|
||||
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
/* This should only be called during vif up and hold RTNL */
|
||||
return iwl_mvm_init_fw_regd(mvm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver regulatory hint for initial update, this also informs the
|
||||
* firmware we support wifi location updates.
|
||||
* Disallow scans that might crash the FW while the LAR regdomain
|
||||
* is not set.
|
||||
*/
|
||||
mvm->lar_regdom_set = false;
|
||||
|
||||
regd = iwl_mvm_get_current_regdomain(mvm, NULL);
|
||||
if (IS_ERR_OR_NULL(regd))
|
||||
return -EIO;
|
||||
|
||||
if (iwl_mvm_is_wifi_mcc_supported(mvm) &&
|
||||
!iwl_mvm_get_bios_mcc(mvm, mcc)) {
|
||||
kfree(regd);
|
||||
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
|
||||
MCC_SOURCE_BIOS, NULL);
|
||||
if (IS_ERR_OR_NULL(regd))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd);
|
||||
kfree(regd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int iwl_mvm_rx_chub_update_mcc(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_mcc_chub_notif *notif = (void *)pkt->data;
|
||||
enum iwl_mcc_source src;
|
||||
char mcc[3];
|
||||
struct ieee80211_regdomain *regd;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
|
||||
return 0;
|
||||
|
||||
mcc[0] = notif->mcc >> 8;
|
||||
mcc[1] = notif->mcc & 0xff;
|
||||
mcc[2] = '\0';
|
||||
src = notif->source_id;
|
||||
|
||||
IWL_DEBUG_LAR(mvm,
|
||||
"RX: received chub update mcc cmd (mcc '%s' src %d)\n",
|
||||
mcc, src);
|
||||
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL);
|
||||
if (IS_ERR_OR_NULL(regd))
|
||||
return 0;
|
||||
|
||||
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
|
||||
kfree(regd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -82,7 +82,6 @@
|
||||
#include "rs.h"
|
||||
#include "fw-api-scan.h"
|
||||
#include "time-event.h"
|
||||
#include "iwl-fw-error-dump.h"
|
||||
|
||||
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
|
||||
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
||||
@ -234,6 +233,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
|
||||
iwl_mvm_rx_ant_coupling_notif, true),
|
||||
|
||||
RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
|
||||
RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true),
|
||||
|
||||
RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
|
||||
|
||||
@ -358,6 +358,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
CMD(TDLS_CHANNEL_SWITCH_CMD),
|
||||
CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
|
||||
CMD(TDLS_CONFIG_CMD),
|
||||
CMD(MCC_UPDATE_CMD),
|
||||
};
|
||||
#undef CMD
|
||||
|
||||
@ -871,8 +872,8 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
|
||||
|
||||
/* start recording again if the firmware is not crashed */
|
||||
WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
|
||||
mvm->fw->dbg_dest_tlv &&
|
||||
iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
|
||||
mvm->fw->dbg_dest_tlv &&
|
||||
iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
@ -1270,6 +1271,10 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
|
||||
iwl_free_resp(&get_status_cmd);
|
||||
out:
|
||||
iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
|
||||
|
||||
/* the FW might have updated the regdomain */
|
||||
iwl_mvm_update_changed_regdom(mvm);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
|
||||
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
|
||||
|
||||
if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
|
||||
!mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif))
|
||||
!mvmvif->pm_enabled)
|
||||
return;
|
||||
|
||||
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
|
||||
@ -639,6 +639,10 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
|
||||
if (vifs->ap_vif)
|
||||
ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
|
||||
|
||||
/* don't allow PM if any TDLS stations exist */
|
||||
if (iwl_mvm_tdls_sta_count(mvm, NULL))
|
||||
return;
|
||||
|
||||
/* enable PM on bss if bss stand alone */
|
||||
if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
|
||||
bss_mvmvif->pm_enabled = true;
|
||||
|
@ -172,6 +172,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
|
||||
}
|
||||
|
||||
int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
||||
bool force_update,
|
||||
struct ieee80211_vif *disabled_vif)
|
||||
{
|
||||
struct iwl_time_quota_cmd cmd = {};
|
||||
@ -309,7 +310,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
||||
"zero quota on binding %d\n", i);
|
||||
}
|
||||
|
||||
if (!send) {
|
||||
if (!send && !force_update) {
|
||||
/* don't send a practically unchanged command, the firmware has
|
||||
* to re-initialize a lot of state and that can have an adverse
|
||||
* impact on it
|
||||
|
@ -1065,6 +1065,37 @@ static inline bool rs_rate_column_match(struct rs_rate *a,
|
||||
&& ant_match;
|
||||
}
|
||||
|
||||
static inline enum rs_column rs_get_column_from_rate(struct rs_rate *rate)
|
||||
{
|
||||
if (is_legacy(rate)) {
|
||||
if (rate->ant == ANT_A)
|
||||
return RS_COLUMN_LEGACY_ANT_A;
|
||||
|
||||
if (rate->ant == ANT_B)
|
||||
return RS_COLUMN_LEGACY_ANT_B;
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (is_siso(rate)) {
|
||||
if (rate->ant == ANT_A || rate->stbc || rate->bfer)
|
||||
return rate->sgi ? RS_COLUMN_SISO_ANT_A_SGI :
|
||||
RS_COLUMN_SISO_ANT_A;
|
||||
|
||||
if (rate->ant == ANT_B)
|
||||
return rate->sgi ? RS_COLUMN_SISO_ANT_B_SGI :
|
||||
RS_COLUMN_SISO_ANT_B;
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (is_mimo(rate))
|
||||
return rate->sgi ? RS_COLUMN_MIMO2_SGI : RS_COLUMN_MIMO2;
|
||||
|
||||
err:
|
||||
return RS_COLUMN_INVALID;
|
||||
}
|
||||
|
||||
static u8 rs_get_tid(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
u8 tid = IWL_MAX_TID_COUNT;
|
||||
@ -1106,18 +1137,44 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
/* Disable last tx check if we are debugging with fixed rate */
|
||||
if (lq_sta->pers.dbg_fixed_rate) {
|
||||
IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* This packet was aggregated but doesn't carry status info */
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||
return;
|
||||
|
||||
rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate);
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
/* Disable last tx check if we are debugging with fixed rate but
|
||||
* update tx stats */
|
||||
if (lq_sta->pers.dbg_fixed_rate) {
|
||||
int index = tx_resp_rate.index;
|
||||
enum rs_column column;
|
||||
int attempts, success;
|
||||
|
||||
column = rs_get_column_from_rate(&tx_resp_rate);
|
||||
if (WARN_ONCE(column == RS_COLUMN_INVALID,
|
||||
"Can't map rate 0x%x to column",
|
||||
tx_resp_hwrate))
|
||||
return;
|
||||
|
||||
if (info->flags & IEEE80211_TX_STAT_AMPDU) {
|
||||
attempts = info->status.ampdu_len;
|
||||
success = info->status.ampdu_ack_len;
|
||||
} else {
|
||||
attempts = info->status.rates[0].count;
|
||||
success = !!(info->flags & IEEE80211_TX_STAT_ACK);
|
||||
}
|
||||
|
||||
lq_sta->pers.tx_stats[column][index].total += attempts;
|
||||
lq_sta->pers.tx_stats[column][index].success += success;
|
||||
|
||||
IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n",
|
||||
tx_resp_hwrate, success, attempts);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (time_after(jiffies,
|
||||
(unsigned long)(lq_sta->last_tx +
|
||||
(IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
|
||||
@ -1142,7 +1199,6 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
table = &lq_sta->lq;
|
||||
lq_hwrate = le32_to_cpu(table->rs_table[0]);
|
||||
rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate);
|
||||
rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate);
|
||||
|
||||
/* Here we actually compare this rate to the latest LQ command */
|
||||
if (!rs_rate_equal(&tx_resp_rate, &lq_rate, allow_ant_mismatch)) {
|
||||
@ -3343,16 +3399,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
||||
(is_legacy(rate)) ? "legacy" :
|
||||
is_vht(rate) ? "VHT" : "HT");
|
||||
if (!is_legacy(rate)) {
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
desc += sprintf(buff + desc, " %s",
|
||||
(is_siso(rate)) ? "SISO" : "MIMO2");
|
||||
desc += sprintf(buff+desc, " %s",
|
||||
(is_ht20(rate)) ? "20MHz" :
|
||||
(is_ht40(rate)) ? "40MHz" :
|
||||
(is_ht80(rate)) ? "80Mhz" : "BAD BW");
|
||||
desc += sprintf(buff+desc, " %s %s %s\n",
|
||||
(rate->sgi) ? "SGI" : "NGI",
|
||||
(rate->ldpc) ? "LDPC" : "BCC",
|
||||
(lq_sta->is_agg) ? "AGG on" : "");
|
||||
desc += sprintf(buff + desc, " %s",
|
||||
(is_ht20(rate)) ? "20MHz" :
|
||||
(is_ht40(rate)) ? "40MHz" :
|
||||
(is_ht80(rate)) ? "80Mhz" : "BAD BW");
|
||||
desc += sprintf(buff + desc, " %s %s %s\n",
|
||||
(rate->sgi) ? "SGI" : "NGI",
|
||||
(rate->ldpc) ? "LDPC" : "BCC",
|
||||
(lq_sta->is_agg) ? "AGG on" : "");
|
||||
}
|
||||
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
|
||||
lq_sta->last_rate_n_flags);
|
||||
@ -3373,13 +3429,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
||||
ss_params = le32_to_cpu(lq_sta->lq.ss_params);
|
||||
desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n",
|
||||
(ss_params & LQ_SS_PARAMS_VALID) ?
|
||||
"VALID," : "INVALID",
|
||||
"VALID" : "INVALID",
|
||||
(ss_params & LQ_SS_BFER_ALLOWED) ?
|
||||
"BFER," : "",
|
||||
", BFER" : "",
|
||||
(ss_params & LQ_SS_STBC_1SS_ALLOWED) ?
|
||||
"STBC," : "",
|
||||
", STBC" : "",
|
||||
(ss_params & LQ_SS_FORCE) ?
|
||||
"FORCE" : "");
|
||||
", FORCE" : "");
|
||||
desc += sprintf(buff+desc,
|
||||
"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
|
||||
lq_sta->lq.initial_rate_index[0],
|
||||
|
@ -587,8 +587,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
|
||||
if (mvm->scan_status == IWL_MVM_SCAN_NONE)
|
||||
return 0;
|
||||
|
||||
if (iwl_mvm_is_radio_killed(mvm))
|
||||
if (iwl_mvm_is_radio_killed(mvm)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
|
||||
scan_done_notif,
|
||||
@ -600,16 +602,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
|
||||
IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
|
||||
sched ? "offloaded " : "", ret);
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
|
||||
sched ? "offloaded " : "");
|
||||
|
||||
ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
out:
|
||||
/*
|
||||
* Clear the scan status so the next scan requests will succeed. This
|
||||
* also ensures the Rx handler doesn't do anything, as the scan was
|
||||
@ -619,7 +619,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
|
||||
if (mvm->scan_status == IWL_MVM_SCAN_OS)
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
|
||||
out:
|
||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||
|
||||
if (notify) {
|
||||
@ -629,7 +628,7 @@ out:
|
||||
ieee80211_scan_completed(mvm->hw, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
|
||||
|
@ -99,7 +99,35 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
|
||||
|
||||
/*
|
||||
* Aging and idle timeouts for the different possible scenarios
|
||||
* in SF_FULL_ON state.
|
||||
* in default configuration
|
||||
*/
|
||||
static const
|
||||
__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
|
||||
{
|
||||
cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF),
|
||||
cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF)
|
||||
},
|
||||
{
|
||||
cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF),
|
||||
cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF)
|
||||
},
|
||||
{
|
||||
cpu_to_le32(SF_MCAST_AGING_TIMER_DEF),
|
||||
cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF)
|
||||
},
|
||||
{
|
||||
cpu_to_le32(SF_BA_AGING_TIMER_DEF),
|
||||
cpu_to_le32(SF_BA_IDLE_TIMER_DEF)
|
||||
},
|
||||
{
|
||||
cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF),
|
||||
cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF)
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Aging and idle timeouts for the different possible scenarios
|
||||
* in single BSS MAC configuration.
|
||||
*/
|
||||
static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
|
||||
{
|
||||
@ -124,7 +152,8 @@ static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
|
||||
static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
|
||||
struct iwl_sf_cfg_cmd *sf_cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
int i, j, watermark;
|
||||
@ -163,24 +192,38 @@ static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
|
||||
cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
|
||||
}
|
||||
}
|
||||
BUILD_BUG_ON(sizeof(sf_full_timeout) !=
|
||||
sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES);
|
||||
|
||||
memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
|
||||
sizeof(sf_full_timeout));
|
||||
if (sta || IWL_UCODE_API(mvm->fw->ucode_ver) < 13) {
|
||||
BUILD_BUG_ON(sizeof(sf_full_timeout) !=
|
||||
sizeof(__le32) * SF_NUM_SCENARIO *
|
||||
SF_NUM_TIMEOUT_TYPES);
|
||||
|
||||
memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
|
||||
sizeof(sf_full_timeout));
|
||||
} else {
|
||||
BUILD_BUG_ON(sizeof(sf_full_timeout_def) !=
|
||||
sizeof(__le32) * SF_NUM_SCENARIO *
|
||||
SF_NUM_TIMEOUT_TYPES);
|
||||
|
||||
memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
|
||||
sizeof(sf_full_timeout_def));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
|
||||
enum iwl_sf_state new_state)
|
||||
{
|
||||
struct iwl_sf_cfg_cmd sf_cmd = {
|
||||
.state = cpu_to_le32(new_state),
|
||||
.state = cpu_to_le32(SF_FULL_ON),
|
||||
};
|
||||
struct ieee80211_sta *sta;
|
||||
int ret = 0;
|
||||
|
||||
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF &&
|
||||
mvm->cfg->disable_dummy_notification)
|
||||
if (IWL_UCODE_API(mvm->fw->ucode_ver) < 13)
|
||||
sf_cmd.state = cpu_to_le32(new_state);
|
||||
|
||||
if (mvm->cfg->disable_dummy_notification)
|
||||
sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
|
||||
|
||||
/*
|
||||
@ -192,6 +235,8 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
|
||||
|
||||
switch (new_state) {
|
||||
case SF_UNINIT:
|
||||
if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 13)
|
||||
iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
|
||||
break;
|
||||
case SF_FULL_ON:
|
||||
if (sta_id == IWL_MVM_STATION_COUNT) {
|
||||
@ -206,11 +251,11 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
iwl_mvm_fill_sf_command(&sf_cmd, sta);
|
||||
iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case SF_INIT_OFF:
|
||||
iwl_mvm_fill_sf_command(&sf_cmd, NULL);
|
||||
iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
|
||||
|
@ -273,7 +273,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
||||
else
|
||||
sta_id = mvm_sta->sta_id;
|
||||
|
||||
if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
|
||||
if (sta_id == IWL_MVM_STATION_COUNT)
|
||||
return -ENOSPC;
|
||||
|
||||
spin_lock_init(&mvm_sta->lock);
|
||||
@ -1681,9 +1681,6 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_DISABLE_STA_TX))
|
||||
return;
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
|
||||
|
@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
|
||||
struct iwl_time_event_notif *notif)
|
||||
{
|
||||
if (!le32_to_cpu(notif->status)) {
|
||||
if (te_data->vif->type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_connection_loss(te_data->vif);
|
||||
IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
|
||||
iwl_mvm_te_clear_data(mvm, te_data);
|
||||
return;
|
||||
@ -261,17 +263,23 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
|
||||
"TE ended - current time %lu, estimated end %lu\n",
|
||||
jiffies, te_data->end_jiffies);
|
||||
|
||||
if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
switch (te_data->vif->type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
ieee80211_remain_on_channel_expired(mvm->hw);
|
||||
iwl_mvm_roc_finished(mvm);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/*
|
||||
* By now, we should have finished association
|
||||
* and know the dtim period.
|
||||
*/
|
||||
iwl_mvm_te_check_disconnect(mvm, te_data->vif,
|
||||
"No association and the time event is over already...");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* By now, we should have finished association
|
||||
* and know the dtim period.
|
||||
*/
|
||||
iwl_mvm_te_check_disconnect(mvm, te_data->vif,
|
||||
"No association and the time event is over already...");
|
||||
iwl_mvm_te_clear_data(mvm, te_data);
|
||||
} else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
|
||||
te_data->running = true;
|
||||
@ -750,8 +758,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
|
||||
* request
|
||||
*/
|
||||
list_for_each_entry(te_data, &mvm->time_event_list, list) {
|
||||
if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
|
||||
te_data->running) {
|
||||
if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
|
||||
is_p2p = true;
|
||||
goto remove_te;
|
||||
@ -766,10 +773,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
|
||||
* request
|
||||
*/
|
||||
list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
|
||||
if (te_data->running) {
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
|
||||
goto remove_te;
|
||||
}
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
|
||||
goto remove_te;
|
||||
}
|
||||
|
||||
remove_te:
|
||||
|
@ -857,7 +857,7 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
|
||||
mvmvif->low_latency = value;
|
||||
|
||||
res = iwl_mvm_update_quotas(mvm, NULL);
|
||||
res = iwl_mvm_update_quotas(mvm, false, NULL);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
|
@ -413,10 +413,35 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
||||
|
||||
/* 8000 Series */
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)},
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
{0}
|
||||
|
@ -217,6 +217,8 @@ struct iwl_pcie_txq_scratch_buf {
|
||||
* @active: stores if queue is active
|
||||
* @ampdu: true if this queue is an ampdu queue for an specific RA/TID
|
||||
* @wd_timeout: queue watchdog timeout (jiffies) - per queue
|
||||
* @frozen: tx stuck queue timer is frozen
|
||||
* @frozen_expiry_remainder: remember how long until the timer fires
|
||||
*
|
||||
* A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
|
||||
* descriptors) and required locking structures.
|
||||
@ -228,9 +230,11 @@ struct iwl_txq {
|
||||
dma_addr_t scratchbufs_dma;
|
||||
struct iwl_pcie_txq_entry *entries;
|
||||
spinlock_t lock;
|
||||
unsigned long frozen_expiry_remainder;
|
||||
struct timer_list stuck_timer;
|
||||
struct iwl_trans_pcie *trans_pcie;
|
||||
bool need_update;
|
||||
bool frozen;
|
||||
u8 active;
|
||||
bool ampdu;
|
||||
unsigned long wd_timeout;
|
||||
|
@ -682,6 +682,43 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver Takes the ownership on secure machine before FW load
|
||||
* and prevent race with the BT load.
|
||||
* W/A for ROM bug. (should be remove in the next Si step)
|
||||
*/
|
||||
static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans)
|
||||
{
|
||||
u32 val, loop = 1000;
|
||||
|
||||
/* Check the RSA semaphore is accessible - if not, we are in trouble */
|
||||
val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0);
|
||||
if (val & (BIT(1) | BIT(17))) {
|
||||
IWL_ERR(trans,
|
||||
"can't access the RSA semaphore it is write protected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* take ownership on the AUX IF */
|
||||
iwl_write_prph(trans, WFPM_CTRL_REG, WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK);
|
||||
iwl_write_prph(trans, AUX_MISC_MASTER1_EN, AUX_MISC_MASTER1_EN_SBE_MSK);
|
||||
|
||||
do {
|
||||
iwl_write_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS, 0x1);
|
||||
val = iwl_read_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS);
|
||||
if (val == 0x1) {
|
||||
iwl_write_prph(trans, RSA_ENABLE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
udelay(10);
|
||||
loop--;
|
||||
} while (loop > 0);
|
||||
|
||||
IWL_ERR(trans, "Failed to take ownership on secure machine\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans,
|
||||
const struct fw_img *image,
|
||||
int cpu,
|
||||
@ -901,6 +938,11 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
|
||||
if (trans->dbg_dest_tlv)
|
||||
iwl_pcie_apply_destination(trans);
|
||||
|
||||
/* TODO: remove in the next Si step */
|
||||
ret = iwl_pcie_rsa_race_bug_wa(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* configure the ucode to be ready to get the secured image */
|
||||
/* release CPU reset */
|
||||
iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT);
|
||||
@ -1462,6 +1504,60 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_trans_pcie_freeze_txq_timer(struct iwl_trans *trans,
|
||||
unsigned long txqs,
|
||||
bool freeze)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int queue;
|
||||
|
||||
for_each_set_bit(queue, &txqs, BITS_PER_LONG) {
|
||||
struct iwl_txq *txq = &trans_pcie->txq[queue];
|
||||
unsigned long now;
|
||||
|
||||
spin_lock_bh(&txq->lock);
|
||||
|
||||
now = jiffies;
|
||||
|
||||
if (txq->frozen == freeze)
|
||||
goto next_queue;
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(trans, "%s TXQ %d\n",
|
||||
freeze ? "Freezing" : "Waking", queue);
|
||||
|
||||
txq->frozen = freeze;
|
||||
|
||||
if (txq->q.read_ptr == txq->q.write_ptr)
|
||||
goto next_queue;
|
||||
|
||||
if (freeze) {
|
||||
if (unlikely(time_after(now,
|
||||
txq->stuck_timer.expires))) {
|
||||
/*
|
||||
* The timer should have fired, maybe it is
|
||||
* spinning right now on the lock.
|
||||
*/
|
||||
goto next_queue;
|
||||
}
|
||||
/* remember how long until the timer fires */
|
||||
txq->frozen_expiry_remainder =
|
||||
txq->stuck_timer.expires - now;
|
||||
del_timer(&txq->stuck_timer);
|
||||
goto next_queue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake a non-empty queue -> arm timer with the
|
||||
* remainder before it froze
|
||||
*/
|
||||
mod_timer(&txq->stuck_timer,
|
||||
now + txq->frozen_expiry_remainder);
|
||||
|
||||
next_queue:
|
||||
spin_unlock_bh(&txq->lock);
|
||||
}
|
||||
}
|
||||
|
||||
#define IWL_FLUSH_WAIT_MS 2000
|
||||
|
||||
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
|
||||
@ -1713,7 +1809,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
||||
int ret;
|
||||
size_t bufsz;
|
||||
|
||||
bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues;
|
||||
bufsz = sizeof(char) * 75 * trans->cfg->base_params->num_of_queues;
|
||||
|
||||
if (!trans_pcie->txq)
|
||||
return -EAGAIN;
|
||||
@ -1726,11 +1822,11 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
||||
txq = &trans_pcie->txq[cnt];
|
||||
q = &txq->q;
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d%s\n",
|
||||
"hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d frozen=%d%s\n",
|
||||
cnt, q->read_ptr, q->write_ptr,
|
||||
!!test_bit(cnt, trans_pcie->queue_used),
|
||||
!!test_bit(cnt, trans_pcie->queue_stopped),
|
||||
txq->need_update,
|
||||
txq->need_update, txq->frozen,
|
||||
(cnt == trans_pcie->cmd_queue ? " HCMD" : ""));
|
||||
}
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
@ -1961,24 +2057,25 @@ static const struct {
|
||||
{ .start = 0x00a01c7c, .end = 0x00a01c7c },
|
||||
{ .start = 0x00a01c28, .end = 0x00a01c54 },
|
||||
{ .start = 0x00a01c5c, .end = 0x00a01c5c },
|
||||
{ .start = 0x00a01c84, .end = 0x00a01c84 },
|
||||
{ .start = 0x00a01c60, .end = 0x00a01cdc },
|
||||
{ .start = 0x00a01ce0, .end = 0x00a01d0c },
|
||||
{ .start = 0x00a01d18, .end = 0x00a01d20 },
|
||||
{ .start = 0x00a01d2c, .end = 0x00a01d30 },
|
||||
{ .start = 0x00a01d40, .end = 0x00a01d5c },
|
||||
{ .start = 0x00a01d80, .end = 0x00a01d80 },
|
||||
{ .start = 0x00a01d98, .end = 0x00a01d98 },
|
||||
{ .start = 0x00a01d98, .end = 0x00a01d9c },
|
||||
{ .start = 0x00a01da8, .end = 0x00a01da8 },
|
||||
{ .start = 0x00a01db8, .end = 0x00a01df4 },
|
||||
{ .start = 0x00a01dc0, .end = 0x00a01dfc },
|
||||
{ .start = 0x00a01e00, .end = 0x00a01e2c },
|
||||
{ .start = 0x00a01e40, .end = 0x00a01e60 },
|
||||
{ .start = 0x00a01e68, .end = 0x00a01e6c },
|
||||
{ .start = 0x00a01e74, .end = 0x00a01e74 },
|
||||
{ .start = 0x00a01e84, .end = 0x00a01e90 },
|
||||
{ .start = 0x00a01e9c, .end = 0x00a01ec4 },
|
||||
{ .start = 0x00a01ed0, .end = 0x00a01ed0 },
|
||||
{ .start = 0x00a01f00, .end = 0x00a01f14 },
|
||||
{ .start = 0x00a01f44, .end = 0x00a01f58 },
|
||||
{ .start = 0x00a01f80, .end = 0x00a01fa8 },
|
||||
{ .start = 0x00a01fb0, .end = 0x00a01fbc },
|
||||
{ .start = 0x00a01ff8, .end = 0x00a01ffc },
|
||||
{ .start = 0x00a01ed0, .end = 0x00a01ee0 },
|
||||
{ .start = 0x00a01f00, .end = 0x00a01f1c },
|
||||
{ .start = 0x00a01f44, .end = 0x00a01ffc },
|
||||
{ .start = 0x00a02000, .end = 0x00a02048 },
|
||||
{ .start = 0x00a02068, .end = 0x00a020f0 },
|
||||
{ .start = 0x00a02100, .end = 0x00a02118 },
|
||||
@ -2305,6 +2402,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
|
||||
.dbgfs_register = iwl_trans_pcie_dbgfs_register,
|
||||
|
||||
.wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty,
|
||||
.freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer,
|
||||
|
||||
.write8 = iwl_trans_pcie_write8,
|
||||
.write32 = iwl_trans_pcie_write32,
|
||||
@ -2423,10 +2521,45 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
||||
* "dash" value). To keep hw_rev backwards compatible - we'll store it
|
||||
* in the old format.
|
||||
*/
|
||||
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
|
||||
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
trans->hw_rev = (trans->hw_rev & 0xfff0) |
|
||||
(CSR_HW_REV_STEP(trans->hw_rev << 2) << 2);
|
||||
|
||||
/*
|
||||
* in-order to recognize C step driver should read chip version
|
||||
* id located at the AUX bus MISC address space.
|
||||
*/
|
||||
iwl_set_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
|
||||
udelay(2);
|
||||
|
||||
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||
25000);
|
||||
if (ret < 0) {
|
||||
IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n");
|
||||
goto out_pci_disable_msi;
|
||||
}
|
||||
|
||||
if (iwl_trans_grab_nic_access(trans, false, &flags)) {
|
||||
u32 hw_step;
|
||||
|
||||
hw_step = __iwl_read_prph(trans, WFPM_CTRL_REG);
|
||||
hw_step |= ENABLE_WFPM;
|
||||
__iwl_write_prph(trans, WFPM_CTRL_REG, hw_step);
|
||||
hw_step = __iwl_read_prph(trans, AUX_MISC_REG);
|
||||
hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF;
|
||||
if (hw_step == 0x3)
|
||||
trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) |
|
||||
(SILICON_C_STEP << 2);
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
}
|
||||
}
|
||||
|
||||
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
|
||||
snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
|
||||
"PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
|
||||
|
@ -725,33 +725,50 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
|
||||
iwl_pcie_tx_start(trans, 0);
|
||||
}
|
||||
|
||||
static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
int ch, ret;
|
||||
u32 mask = 0;
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, false, &flags))
|
||||
goto out;
|
||||
|
||||
/* Stop each Tx DMA channel */
|
||||
for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
|
||||
iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
|
||||
mask |= FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch);
|
||||
}
|
||||
|
||||
/* Wait for DMA channels to be idle */
|
||||
ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000);
|
||||
if (ret < 0)
|
||||
IWL_ERR(trans,
|
||||
"Failing on timeout while stopping DMA channel %d [0x%08x]\n",
|
||||
ch, iwl_read32(trans, FH_TSSR_TX_STATUS_REG));
|
||||
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
|
||||
out:
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_pcie_tx_stop - Stop all Tx DMA channels
|
||||
*/
|
||||
int iwl_pcie_tx_stop(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int ch, txq_id, ret;
|
||||
int txq_id;
|
||||
|
||||
/* Turn off all Tx DMA fifos */
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
|
||||
iwl_scd_deactivate_fifos(trans);
|
||||
|
||||
/* Stop each Tx DMA channel, and wait for it to be idle */
|
||||
for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
|
||||
iwl_write_direct32(trans,
|
||||
FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
|
||||
ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
|
||||
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
|
||||
if (ret < 0)
|
||||
IWL_ERR(trans,
|
||||
"Failing on timeout while stopping DMA channel %d [0x%08x]\n",
|
||||
ch,
|
||||
iwl_read_direct32(trans,
|
||||
FH_TSSR_TX_STATUS_REG));
|
||||
}
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
/* Turn off all Tx DMA channels */
|
||||
iwl_pcie_tx_stop_fh(trans);
|
||||
|
||||
/*
|
||||
* This function can be called before the op_mode disabled the
|
||||
@ -912,9 +929,18 @@ error:
|
||||
|
||||
static inline void iwl_pcie_txq_progress(struct iwl_txq *txq)
|
||||
{
|
||||
lockdep_assert_held(&txq->lock);
|
||||
|
||||
if (!txq->wd_timeout)
|
||||
return;
|
||||
|
||||
/*
|
||||
* station is asleep and we send data - that must
|
||||
* be uAPSD or PS-Poll. Don't rearm the timer.
|
||||
*/
|
||||
if (txq->frozen)
|
||||
return;
|
||||
|
||||
/*
|
||||
* if empty delete timer, otherwise move timer forward
|
||||
* since we're making progress on this queue
|
||||
@ -1248,6 +1274,9 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
|
||||
SCD_TX_STTS_QUEUE_OFFSET(txq_id);
|
||||
static const u32 zero_val[4] = {};
|
||||
|
||||
trans_pcie->txq[txq_id].frozen_expiry_remainder = 0;
|
||||
trans_pcie->txq[txq_id].frozen = false;
|
||||
|
||||
/*
|
||||
* Upon HW Rfkill - we stop the device, and then stop the queues
|
||||
* in the op_mode. Just for the sake of the simplicity of the op_mode,
|
||||
|
Loading…
Reference in New Issue
Block a user