Commit 5f4ef719 authored by John W. Linville's avatar John W. Linville
parents 855df36d c47af22a
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#include "commands.h" #include "commands.h"
#include "power.h" #include "power.h"
static bool force_cam;
module_param(force_cam, bool, 0644);
MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)");
/* /*
* Setting power level allows the card to go to sleep when not busy. * Setting power level allows the card to go to sleep when not busy.
* *
...@@ -288,6 +292,11 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, ...@@ -288,6 +292,11 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS; bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
int dtimper; int dtimper;
if (force_cam) {
iwl_power_sleep_cam_cmd(priv, cmd);
return;
}
dtimper = priv->hw->conf.ps_dtim_period ?: 1; dtimper = priv->hw->conf.ps_dtim_period ?: 1;
if (priv->wowlan) if (priv->wowlan)
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 8 #define IWL8000_UCODE_API_MAX 9
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 8 #define IWL8000_UCODE_API_OK 8
...@@ -119,10 +119,9 @@ const struct iwl_cfg iwl8260_2ac_cfg = { ...@@ -119,10 +119,9 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
.ht_params = &iwl8000_ht_params, .ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION, .nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
}; };
const struct iwl_cfg iwl8260_n_cfg = { const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.name = "Intel(R) Dual Band Wireless-AC 8260", .name = "Intel(R) Dual Band Wireless-AC 8260",
.fw_name_pre = IWL8000_FW_PRE, .fw_name_pre = IWL8000_FW_PRE,
IWL_DEVICE_8000, IWL_DEVICE_8000,
......
...@@ -337,7 +337,7 @@ extern const struct iwl_cfg iwl7265_2ac_cfg; ...@@ -337,7 +337,7 @@ extern const struct iwl_cfg iwl7265_2ac_cfg;
extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_2n_cfg;
extern const struct iwl_cfg iwl7265_n_cfg; extern const struct iwl_cfg iwl7265_n_cfg;
extern const struct iwl_cfg iwl8260_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg;
extern const struct iwl_cfg iwl8260_n_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */ #endif /* CONFIG_IWLMVM */
#endif /* __IWL_CONFIG_H__ */ #endif /* __IWL_CONFIG_H__ */
...@@ -155,6 +155,8 @@ static struct iwlwifi_opmode_table { ...@@ -155,6 +155,8 @@ static struct iwlwifi_opmode_table {
[MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL }, [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL },
}; };
#define IWL_DEFAULT_SCAN_CHANNELS 40
/* /*
* struct fw_sec: Just for the image parsing proccess. * struct fw_sec: Just for the image parsing proccess.
* For the fw storage we are using struct fw_desc. * For the fw storage we are using struct fw_desc.
...@@ -565,6 +567,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, ...@@ -565,6 +567,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
} }
drv->fw.ucode_ver = le32_to_cpu(ucode->ver); drv->fw.ucode_ver = le32_to_cpu(ucode->ver);
memcpy(drv->fw.human_readable, ucode->human_readable,
sizeof(drv->fw.human_readable));
build = le32_to_cpu(ucode->build); build = le32_to_cpu(ucode->build);
if (build) if (build)
...@@ -819,6 +823,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, ...@@ -819,6 +823,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len)) if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
goto invalid_tlv_len; goto invalid_tlv_len;
break; break;
case IWL_UCODE_TLV_N_SCAN_CHANNELS:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
capa->n_scan_channels =
le32_to_cpup((__le32 *)tlv_data);
break;
default: default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break; break;
...@@ -973,6 +983,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) ...@@ -973,6 +983,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH;
fw->ucode_capa.standard_phy_calibration_size = fw->ucode_capa.standard_phy_calibration_size =
IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
if (!api_ok) if (!api_ok)
api_ok = api_max; api_ok = api_max;
...@@ -1394,3 +1405,7 @@ module_param_named(power_level, iwlwifi_mod_params.power_level, ...@@ -1394,3 +1405,7 @@ module_param_named(power_level, iwlwifi_mod_params.power_level,
int, S_IRUGO); int, S_IRUGO);
MODULE_PARM_DESC(power_level, MODULE_PARM_DESC(power_level,
"default power save level (range from 1 - 5, default: 1)"); "default power save level (range from 1 - 5, default: 1)");
module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO);
MODULE_PARM_DESC(dbgm,
"firmware monitor - to debug FW (default: false - needs lots of memory)");
...@@ -779,7 +779,6 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ...@@ -779,7 +779,6 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
if (cfg->ht_params->ht40_bands & BIT(band)) { if (cfg->ht_params->ht40_bands & BIT(band)) {
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
ht_info->mcs.rx_mask[4] = 0x01;
max_bit_rate = MAX_BIT_RATE_40_MHZ; max_bit_rate = MAX_BIT_RATE_40_MHZ;
} }
......
...@@ -74,12 +74,17 @@ ...@@ -74,12 +74,17 @@
* @IWL_FW_ERROR_DUMP_RXF: * @IWL_FW_ERROR_DUMP_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
* &struct iwl_fw_error_dump_txcmd packets * &struct iwl_fw_error_dump_txcmd packets
* @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info
* info on the device / firmware.
* @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor
*/ */
enum iwl_fw_error_dump_type { enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_SRAM = 0, IWL_FW_ERROR_DUMP_SRAM = 0,
IWL_FW_ERROR_DUMP_REG = 1, IWL_FW_ERROR_DUMP_REG = 1,
IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_RXF = 2,
IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_TXCMD = 3,
IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4,
IWL_FW_ERROR_DUMP_FW_MONITOR = 5,
IWL_FW_ERROR_DUMP_MAX, IWL_FW_ERROR_DUMP_MAX,
}; };
...@@ -120,13 +125,50 @@ struct iwl_fw_error_dump_txcmd { ...@@ -120,13 +125,50 @@ struct iwl_fw_error_dump_txcmd {
u8 data[]; u8 data[];
} __packed; } __packed;
enum iwl_fw_error_dump_family {
IWL_FW_ERROR_DUMP_FAMILY_7 = 7,
IWL_FW_ERROR_DUMP_FAMILY_8 = 8,
};
/**
* struct iwl_fw_error_dump_info - info on the device / firmware
* @device_family: the family of the device (7 / 8)
* @hw_step: the step of the device
* @fw_human_readable: human readable FW version
* @dev_human_readable: name of the device
* @bus_human_readable: name of the bus used
*/
struct iwl_fw_error_dump_info {
__le32 device_family;
__le32 hw_step;
u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ];
u8 dev_human_readable[64];
u8 bus_human_readable[8];
} __packed;
/**
* struct iwl_fw_error_fw_mon - FW monitor data
* @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer
* @fw_mon_base_ptr: base pointer of the data
* @fw_mon_cycle_cnt: number of wrap arounds
* @reserved: for future use
* @data: captured data
*/
struct iwl_fw_error_fw_mon {
__le32 fw_mon_wr_ptr;
__le32 fw_mon_base_ptr;
__le32 fw_mon_cycle_cnt;
__le32 reserved[3];
u8 data[];
} __packed;
/** /**
* iwl_mvm_fw_error_next_data - advance fw error dump data pointer * iwl_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block * @data: previous data block
* Returns: next data block * Returns: next data block
*/ */
static inline struct iwl_fw_error_dump_data * static inline struct iwl_fw_error_dump_data *
iwl_mvm_fw_error_next_data(struct iwl_fw_error_dump_data *data) iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
{ {
return (void *)(data->data + le32_to_cpu(data->len)); return (void *)(data->data + le32_to_cpu(data->len));
} }
......
...@@ -128,6 +128,7 @@ enum iwl_ucode_tlv_type { ...@@ -128,6 +128,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_CSCHEME = 28, IWL_UCODE_TLV_CSCHEME = 28,
IWL_UCODE_TLV_API_CHANGES_SET = 29, IWL_UCODE_TLV_API_CHANGES_SET = 29,
IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30,
IWL_UCODE_TLV_N_SCAN_CHANNELS = 31,
}; };
struct iwl_ucode_tlv { struct iwl_ucode_tlv {
...@@ -137,6 +138,7 @@ struct iwl_ucode_tlv { ...@@ -137,6 +138,7 @@ struct iwl_ucode_tlv {
}; };
#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 #define IWL_TLV_UCODE_MAGIC 0x0a4c5749
#define FW_VER_HUMAN_READABLE_SZ 64
struct iwl_tlv_ucode_header { struct iwl_tlv_ucode_header {
/* /*
...@@ -147,7 +149,7 @@ struct iwl_tlv_ucode_header { ...@@ -147,7 +149,7 @@ struct iwl_tlv_ucode_header {
*/ */
__le32 zero; __le32 zero;
__le32 magic; __le32 magic;
u8 human_readable[64]; u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
__le32 ver; /* major/minor/API/serial */ __le32 ver; /* major/minor/API/serial */
__le32 build; __le32 build;
__le64 ignore; __le64 ignore;
......
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "iwl-fw-file.h"
/** /**
* enum iwl_ucode_tlv_flag - ucode API flags * enum iwl_ucode_tlv_flag - ucode API flags
* @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
...@@ -117,11 +119,15 @@ enum iwl_ucode_tlv_flag { ...@@ -117,11 +119,15 @@ enum iwl_ucode_tlv_flag {
/** /**
* enum iwl_ucode_tlv_api - ucode api * enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
* @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification
* @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
*/ */
enum iwl_ucode_tlv_api { enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1),
IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
}; };
/** /**
...@@ -178,6 +184,7 @@ enum iwl_ucode_sec { ...@@ -178,6 +184,7 @@ enum iwl_ucode_sec {
struct iwl_ucode_capabilities { struct iwl_ucode_capabilities {
u32 max_probe_length; u32 max_probe_length;
u32 n_scan_channels;
u32 standard_phy_calibration_size; u32 standard_phy_calibration_size;
u32 flags; u32 flags;
u32 api[IWL_API_ARRAY_SIZE]; u32 api[IWL_API_ARRAY_SIZE];
...@@ -311,6 +318,7 @@ struct iwl_fw { ...@@ -311,6 +318,7 @@ struct iwl_fw {
bool mvm_fw; bool mvm_fw;
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
}; };
#endif /* __iwl_fw_h__ */ #endif /* __iwl_fw_h__ */
...@@ -103,6 +103,7 @@ enum iwl_disable_11n { ...@@ -103,6 +103,7 @@ enum iwl_disable_11n {
* @power_level: power level, default = 1 * @power_level: power level, default = 1
* @debug_level: levels are IWL_DL_* * @debug_level: levels are IWL_DL_*
* @ant_coupling: antenna coupling in dB, default = 0 * @ant_coupling: antenna coupling in dB, default = 0
* @fw_monitor: allow to use firmware monitor
*/ */
struct iwl_mod_params { struct iwl_mod_params {
int sw_crypto; int sw_crypto;
...@@ -120,6 +121,7 @@ struct iwl_mod_params { ...@@ -120,6 +121,7 @@ struct iwl_mod_params {
int ant_coupling; int ant_coupling;
char *nvm_file; char *nvm_file;
bool uapsd_disable; bool uapsd_disable;
bool fw_monitor;
}; };
#endif /* #__iwl_modparams_h__ */ #endif /* #__iwl_modparams_h__ */
...@@ -174,7 +174,9 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { ...@@ -174,7 +174,9 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
* @NVM_CHANNEL_IBSS: usable as an IBSS channel * @NVM_CHANNEL_IBSS: usable as an IBSS channel
* @NVM_CHANNEL_ACTIVE: active scanning allowed * @NVM_CHANNEL_ACTIVE: active scanning allowed
* @NVM_CHANNEL_RADAR: radar detection required * @NVM_CHANNEL_RADAR: radar detection required
* @NVM_CHANNEL_DFS: dynamic freq selection candidate * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed
* @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS
* on same channel on 2.4 or same UNII band on 5.2
* @NVM_CHANNEL_WIDE: 20 MHz channel okay (?) * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
* @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
* @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
...@@ -185,7 +187,8 @@ enum iwl_nvm_channel_flags { ...@@ -185,7 +187,8 @@ enum iwl_nvm_channel_flags {
NVM_CHANNEL_IBSS = BIT(1), NVM_CHANNEL_IBSS = BIT(1),
NVM_CHANNEL_ACTIVE = BIT(3), NVM_CHANNEL_ACTIVE = BIT(3),
NVM_CHANNEL_RADAR = BIT(4), NVM_CHANNEL_RADAR = BIT(4),
NVM_CHANNEL_DFS = BIT(7), NVM_CHANNEL_INDOOR_ONLY = BIT(5),
NVM_CHANNEL_GO_CONCURRENT = BIT(6),
NVM_CHANNEL_WIDE = BIT(8), NVM_CHANNEL_WIDE = BIT(8),
NVM_CHANNEL_40MHZ = BIT(9), NVM_CHANNEL_40MHZ = BIT(9),
NVM_CHANNEL_80MHZ = BIT(10), NVM_CHANNEL_80MHZ = BIT(10),
...@@ -273,6 +276,16 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ...@@ -273,6 +276,16 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
if (ch_flags & NVM_CHANNEL_RADAR) if (ch_flags & NVM_CHANNEL_RADAR)
channel->flags |= IEEE80211_CHAN_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 */ /* Initialize regulatory-based run-time data */
/* /*
...@@ -282,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ...@@ -282,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->max_power = DEFAULT_MAX_TX_POWER; channel->max_power = DEFAULT_MAX_TX_POWER;
is_5ghz = channel->band == IEEE80211_BAND_5GHZ; is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
IWL_DEBUG_EEPROM(dev, IWL_DEBUG_EEPROM(dev,
"Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
channel->hw_value, channel->hw_value,
is_5ghz ? "5.2" : "2.4", is_5ghz ? "5.2" : "2.4",
CHECK_AND_PRINT_I(VALID), CHECK_AND_PRINT_I(VALID),
...@@ -290,7 +303,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ...@@ -290,7 +303,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(ACTIVE),
CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(RADAR),
CHECK_AND_PRINT_I(WIDE), CHECK_AND_PRINT_I(WIDE),
CHECK_AND_PRINT_I(DFS), CHECK_AND_PRINT_I(INDOOR_ONLY),
CHECK_AND_PRINT_I(GO_CONCURRENT),
ch_flags, ch_flags,
channel->max_power, channel->max_power,
((ch_flags & NVM_CHANNEL_IBSS) && ((ch_flags & NVM_CHANNEL_IBSS) &&
...@@ -462,7 +476,8 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg, ...@@ -462,7 +476,8 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
data->hw_addr[5] = hw_addr[4]; data->hw_addr[5] = hw_addr[4];
} }
static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, static void iwl_set_hw_address_family_8000(struct device *dev,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, struct iwl_nvm_data *data,
const __le16 *mac_override, const __le16 *mac_override,
const __le16 *nvm_hw) const __le16 *nvm_hw)
...@@ -481,10 +496,14 @@ static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, ...@@ -481,10 +496,14 @@ static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg,
data->hw_addr[4] = hw_addr[5]; data->hw_addr[4] = hw_addr[5];
data->hw_addr[5] = hw_addr[4]; data->hw_addr[5] = hw_addr[4];
if (is_valid_ether_addr(hw_addr)) if (is_valid_ether_addr(data->hw_addr))
return; return;
IWL_ERR_DEV(dev,
"mac address from nvm override section is not valid\n");
} }
if (nvm_hw) {
/* take the MAC address from the OTP */ /* take the MAC address from the OTP */
hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000); hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000);
data->hw_addr[0] = hw_addr[3]; data->hw_addr[0] = hw_addr[3];
...@@ -495,6 +514,10 @@ static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, ...@@ -495,6 +514,10 @@ static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg,
hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000); hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000);
data->hw_addr[4] = hw_addr[1]; data->hw_addr[4] = hw_addr[1];
data->hw_addr[5] = hw_addr[0]; data->hw_addr[5] = hw_addr[0];
return;
}
IWL_ERR_DEV(dev, "mac address is not found\n");
} }
struct iwl_nvm_data * struct iwl_nvm_data *
...@@ -556,7 +579,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, ...@@ -556,7 +579,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
rx_chains); rx_chains);
} else { } else {
/* MAC address in family 8000 */ /* MAC address in family 8000 */
iwl_set_hw_address_family_8000(cfg, data, mac_override, nvm_hw); iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
nvm_hw);
iwl_init_sbands(dev, cfg, data, regulatory, iwl_init_sbands(dev, cfg, data, regulatory,
sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
......
...@@ -359,4 +359,10 @@ enum secure_load_status_reg { ...@@ -359,4 +359,10 @@ enum secure_load_status_reg {
#define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10)
#define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c)
/* FW monitor */
#define MON_BUFF_BASE_ADDR (0xa03c3c)
#define MON_BUFF_END_ADDR (0xa03c40)
#define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48)
#endif /* __iwl_prph_h__ */ #endif /* __iwl_prph_h__ */
...@@ -100,12 +100,13 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { ...@@ -100,12 +100,13 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
#undef EVENT_PRIO_ANT #undef EVENT_PRIO_ANT
#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
#define BT_ANTENNA_COUPLING_THRESHOLD (30) #define BT_ANTENNA_COUPLING_THRESHOLD (30)
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
{ {
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
return 0;
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0,
sizeof(struct iwl_bt_coex_prio_tbl_cmd), sizeof(struct iwl_bt_coex_prio_tbl_cmd),
&iwl_bt_prio_tbl); &iwl_bt_prio_tbl);
...@@ -535,7 +536,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) ...@@ -535,7 +536,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
if (!chanctx_conf || if (!chanctx_conf ||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
rcu_read_unlock(); rcu_read_unlock();
return BT_COEX_LOOSE_LUT; return BT_COEX_INVALID_LUT;
} }
ret = BT_COEX_TX_DIS_LUT; ret = BT_COEX_TX_DIS_LUT;
...@@ -578,6 +579,29 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -578,6 +579,29 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
return -ENOMEM; return -ENOMEM;
cmd.data[0] = bt_cmd; cmd.data[0] = bt_cmd;
lockdep_assert_held(&mvm->mutex);
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
switch (mvm->bt_force_ant_mode) {
case BT_FORCE_ANT_AUTO:
flags = BT_COEX_AUTO;
break;
case BT_FORCE_ANT_BT:
flags = BT_COEX_BT;
break;
case BT_FORCE_ANT_WIFI:
flags = BT_COEX_WIFI;
break;
default:
WARN_ON(1);
flags = 0;
}
bt_cmd->flags = cpu_to_le32(flags);
bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE);
goto send_cmd;
}
bt_cmd->max_kill = 5; bt_cmd->max_kill = 5;
bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
...@@ -642,6 +666,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -642,6 +666,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
bt_cmd->kill_cts_msk = bt_cmd->kill_cts_msk =
cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
send_cmd:
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
...@@ -780,9 +805,9 @@ void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, ...@@ -780,9 +805,9 @@ void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
mvmvif->bf_data.last_bt_coex_event = rssi; mvmvif->bf_data.last_bt_coex_event = rssi;
mvmvif->bf_data.bt_coex_max_thold = mvmvif->bf_data.bt_coex_max_thold =
enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0; enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0;
mvmvif->bf_data.bt_coex_min_thold = mvmvif->bf_data.bt_coex_min_thold =
enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0; enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0;
} }
/* must be called under rcu_read_lock */ /* must be called under rcu_read_lock */
...@@ -919,7 +944,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -919,7 +944,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* if the RSSI isn't valid, fake it is very low */ /* if the RSSI isn't valid, fake it is very low */
if (!ave_rssi) if (!ave_rssi)
ave_rssi = -100; ave_rssi = -100;
if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) { if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
...@@ -930,7 +955,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -930,7 +955,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
* the iteration, if one interface's rssi isn't good enough, * the iteration, if one interface's rssi isn't good enough,
* bt_kill_msk will be set to default values. * bt_kill_msk will be set to default values.
*/ */
} else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) { } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
...@@ -955,6 +980,10 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) ...@@ -955,6 +980,10 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
struct iwl_bt_coex_ci_cmd cmd = {}; struct iwl_bt_coex_ci_cmd cmd = {};
u8 ci_bw_idx; u8 ci_bw_idx;
/* Ignore updates if we are in force mode */
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
return;
rcu_read_lock(); rcu_read_lock();
ieee80211_iterate_active_interfaces_atomic( ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL, mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
...@@ -1121,6 +1150,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -1121,6 +1150,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* Ignore updates if we are in force mode */
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
return;
/* /*
* Rssi update while not associated - can happen since the statistics * Rssi update while not associated - can happen since the statistics
* are handled asynchronously * are handled asynchronously
...@@ -1177,9 +1210,12 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, ...@@ -1177,9 +1210,12 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
BT_HIGH_TRAFFIC) BT_HIGH_TRAFFIC)
return LINK_QUAL_AGG_TIME_LIMIT_DEF; return LINK_QUAL_AGG_TIME_LIMIT_DEF;
if (mvm->last_bt_notif.ttc_enabled)
return LINK_QUAL_AGG_TIME_LIMIT_DEF;
lut_type = iwl_get_coex_type(mvm, mvmsta->vif); lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
if (lut_type == BT_COEX_LOOSE_LUT) if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT)
return LINK_QUAL_AGG_TIME_LIMIT_DEF; return LINK_QUAL_AGG_TIME_LIMIT_DEF;
/* tight coex, high bt traffic, reduce AGG time limit */ /* tight coex, high bt traffic, reduce AGG time limit */
...@@ -1190,18 +1226,29 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, ...@@ -1190,18 +1226,29 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
enum iwl_bt_coex_lut_type lut_type;
if (mvm->last_bt_notif.ttc_enabled)
return true;
if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
BT_HIGH_TRAFFIC) BT_HIGH_TRAFFIC)
return true; return true;
/* /*
* In Tight, BT can't Rx while we Tx, so use both antennas since BT is * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
* already killed. * since BT is already killed.
* In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
* Tx. * we Tx.
* When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO.
*/ */
return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
return lut_type != BT_COEX_LOOSE_LUT;
}
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
{
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF;
} }
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
...@@ -1274,6 +1321,10 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, ...@@ -1274,6 +1321,10 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* Ignore updates if we are in force mode */
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
return 0;
if (ant_isolation == mvm->last_ant_isol) if (ant_isolation == mvm->last_ant_isol)
return 0; return 0;
......
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
#define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_PS_SNOOZE_WINDOW 50
#define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25
#define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64
#define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62
#define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65
#define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_CORUNNING 1
#define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_MPLUT 1
......
...@@ -455,6 +455,43 @@ iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, ...@@ -455,6 +455,43 @@ iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
return count; return count;
} }
static ssize_t
iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
static const char * const modes_str[BT_FORCE_ANT_MAX] = {
[BT_FORCE_ANT_DIS] = "dis",
[BT_FORCE_ANT_AUTO] = "auto",
[BT_FORCE_ANT_BT] = "bt",
[BT_FORCE_ANT_WIFI] = "wifi",
};
int ret, bt_force_ant_mode;
for (bt_force_ant_mode = 0;
bt_force_ant_mode < ARRAY_SIZE(modes_str);
bt_force_ant_mode++) {
if (!strcmp(buf, modes_str[bt_force_ant_mode]))
break;
}
if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
return -EINVAL;
ret = 0;
mutex_lock(&mvm->mutex);
if (mvm->bt_force_ant_mode == bt_force_ant_mode)
goto out;
mvm->bt_force_ant_mode = bt_force_ant_mode;
IWL_DEBUG_COEX(mvm, "Force mode: %s\n",
modes_str[mvm->bt_force_ant_mode]);
ret = iwl_send_bt_init_conf(mvm);
out:
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
#define PRINT_STATS_LE32(_str, _val) \ #define PRINT_STATS_LE32(_str, _val) \
pos += scnprintf(buf + pos, bufsz - pos, \ pos += scnprintf(buf + pos, bufsz - pos, \
fmt_table, _str, \ fmt_table, _str, \
...@@ -1101,6 +1138,7 @@ MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); ...@@ -1101,6 +1138,7 @@ MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
...@@ -1142,6 +1180,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) ...@@ -1142,6 +1180,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
S_IWUSR | S_IRUSR); S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
......
...@@ -76,6 +76,9 @@ ...@@ -76,6 +76,9 @@
* @BT_COEX_2W: * @BT_COEX_2W:
* @BT_COEX_3W: * @BT_COEX_3W:
* @BT_COEX_NW: * @BT_COEX_NW:
* @BT_COEX_AUTO:
* @BT_COEX_BT: Antenna is for BT (manufacuring tests)
* @BT_COEX_WIFI: Antenna is for BT (manufacuring tests)
* @BT_COEX_SYNC2SCO: * @BT_COEX_SYNC2SCO:
* @BT_COEX_CORUNNING: * @BT_COEX_CORUNNING:
* @BT_COEX_MPLUT: * @BT_COEX_MPLUT:
...@@ -89,6 +92,9 @@ enum iwl_bt_coex_flags { ...@@ -89,6 +92,9 @@ enum iwl_bt_coex_flags {
BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, BT_COEX_2W = 0x1 << BT_COEX_MODE_POS,
BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, BT_COEX_3W = 0x2 << BT_COEX_MODE_POS,
BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, BT_COEX_NW = 0x3 << BT_COEX_MODE_POS,
BT_COEX_AUTO = 0x5 << BT_COEX_MODE_POS,
BT_COEX_BT = 0x6 << BT_COEX_MODE_POS,
BT_COEX_WIFI = 0x7 << BT_COEX_MODE_POS,
BT_COEX_SYNC2SCO = BIT(7), BT_COEX_SYNC2SCO = BIT(7),
BT_COEX_CORUNNING = BIT(8), BT_COEX_CORUNNING = BIT(8),
BT_COEX_MPLUT = BIT(9), BT_COEX_MPLUT = BIT(9),
...@@ -299,6 +305,7 @@ enum iwl_bt_activity_grading { ...@@ -299,6 +305,7 @@ enum iwl_bt_activity_grading {
* @bt_traffic_load: load of BT traffic * @bt_traffic_load: load of BT traffic
* @bt_agg_traffic_load: aggregated load of BT traffic * @bt_agg_traffic_load: aggregated load of BT traffic
* @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
* @ttc_enabled: true if ttc has been enabled by the firmware
* @primary_ch_lut: LUT used for primary channel * @primary_ch_lut: LUT used for primary channel
* @secondary_ch_lut: LUT used for secondary channel * @secondary_ch_lut: LUT used for secondary channel
* @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
...@@ -311,7 +318,8 @@ struct iwl_bt_coex_profile_notif { ...@@ -311,7 +318,8 @@ struct iwl_bt_coex_profile_notif {
u8 bt_traffic_load; u8 bt_traffic_load;
u8 bt_agg_traffic_load; u8 bt_agg_traffic_load;
u8 bt_ci_compliance; u8 bt_ci_compliance;
u8 reserved[3]; u8 ttc_enabled;
__le16 reserved;
__le32 primary_ch_lut; __le32 primary_ch_lut;
__le32 secondary_ch_lut; __le32 secondary_ch_lut;
......
...@@ -336,7 +336,7 @@ struct iwl_beacon_filter_cmd { ...@@ -336,7 +336,7 @@ struct iwl_beacon_filter_cmd {
#define IWL_BF_DEBUG_FLAG_D0I3 0 #define IWL_BF_DEBUG_FLAG_D0I3 0
#define IWL_BF_ESCAPE_TIMER_DEFAULT 50 #define IWL_BF_ESCAPE_TIMER_DEFAULT 50
#define IWL_BF_ESCAPE_TIMER_D0I3 1024 #define IWL_BF_ESCAPE_TIMER_D0I3 0
#define IWL_BF_ESCAPE_TIMER_MAX 1024 #define IWL_BF_ESCAPE_TIMER_MAX 1024
#define IWL_BF_ESCAPE_TIMER_MIN 0 #define IWL_BF_ESCAPE_TIMER_MIN 0
......
...@@ -169,19 +169,13 @@ enum iwl_scan_type { ...@@ -169,19 +169,13 @@ enum iwl_scan_type {
SCAN_TYPE_DISCOVERY_FORCED = 6, SCAN_TYPE_DISCOVERY_FORCED = 6,
}; /* SCAN_ACTIVITY_TYPE_E_VER_1 */ }; /* SCAN_ACTIVITY_TYPE_E_VER_1 */
/**
* Maximal number of channels to scan
* it should be equal to:
* max(IWL_NUM_CHANNELS, IWL_NUM_CHANNELS_FAMILY_8000)
*/
#define MAX_NUM_SCAN_CHANNELS 50
/** /**
* struct iwl_scan_cmd - scan request command * struct iwl_scan_cmd - scan request command
* ( SCAN_REQUEST_CMD = 0x80 ) * ( SCAN_REQUEST_CMD = 0x80 )
* @len: command length in bytes * @len: command length in bytes
* @scan_flags: scan flags from SCAN_FLAGS_* * @scan_flags: scan flags from SCAN_FLAGS_*
* @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS) * @channel_count: num of channels in channel list
* (1 - ucode_capa.n_scan_channels)
* @quiet_time: in msecs, dwell this time for active scan on quiet channels * @quiet_time: in msecs, dwell this time for active scan on quiet channels
* @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than
* this number of packets were received (typically 1) * this number of packets were received (typically 1)
...@@ -345,7 +339,7 @@ struct iwl_scan_results_notif { ...@@ -345,7 +339,7 @@ struct iwl_scan_results_notif {
* @last_channel: last channel that was scanned * @last_channel: last channel that was scanned
* @tsf_low: TSF timer (lower half) in usecs * @tsf_low: TSF timer (lower half) in usecs
* @tsf_high: TSF timer (higher half) in usecs * @tsf_high: TSF timer (higher half) in usecs
* @results: all scan results, only "scanned_channels" of them are valid * @results: array of scan results, only "scanned_channels" of them are valid
*/ */
struct iwl_scan_complete_notif { struct iwl_scan_complete_notif {
u8 scanned_channels; u8 scanned_channels;
...@@ -354,11 +348,10 @@ struct iwl_scan_complete_notif { ...@@ -354,11 +348,10 @@ struct iwl_scan_complete_notif {
u8 last_channel; u8 last_channel;
__le32 tsf_low; __le32 tsf_low;
__le32 tsf_high; __le32 tsf_high;
struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS]; struct iwl_scan_results_notif results[];
} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ } __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */
/* scan offload */ /* scan offload */
#define IWL_MAX_SCAN_CHANNELS 40
#define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_MAX_BLACKLIST_LEN 64
#define IWL_SCAN_SHORT_BLACKLIST_LEN 16 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16
#define IWL_SCAN_MAX_PROFILES 11 #define IWL_SCAN_MAX_PROFILES 11
...@@ -423,36 +416,24 @@ enum iwl_scan_offload_channel_flags { ...@@ -423,36 +416,24 @@ enum iwl_scan_offload_channel_flags {
IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25),
}; };
/** /* channel configuration for struct iwl_scan_offload_cfg. Each channels needs:
* iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S * __le32 type: bitmap; bits 1-20 are for directed scan to i'th ssid and
* @type: bitmap - see enum iwl_scan_offload_channel_flags. * see enum iwl_scan_offload_channel_flags.
* 0: passive (0) or active (1) scan. * __le16 channel_number: channel number 1-13 etc.
* 1-20: directed scan to i'th ssid. * __le16 iter_count: repetition count for the channel.
* 22: channel width configuation - 1 for narrow. * __le32 iter_interval: interval between two innteration on one channel.
* 24: full scan. * u8 active_dwell.
* 25: partial scan. * u8 passive_dwell.
* @channel_number: channel number 1-13 etc.
* @iter_count: repetition count for the channel.
* @iter_interval: interval between two innteration on one channel.
* @dwell_time: entry 0 - active scan, entry 1 - passive scan.
*/ */
struct iwl_scan_channel_cfg { #define IWL_SCAN_CHAN_SIZE 14
__le32 type[IWL_MAX_SCAN_CHANNELS];
__le16 channel_number[IWL_MAX_SCAN_CHANNELS];
__le16 iter_count[IWL_MAX_SCAN_CHANNELS];
__le32 iter_interval[IWL_MAX_SCAN_CHANNELS];
u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2];
} __packed;
/** /**
* iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S
* @scan_cmd: scan command fixed part * @scan_cmd: scan command fixed part
* @channel_cfg: scan channel configuration * @data: scan channel configuration and probe request frames
* @data: probe request frames (one per band)
*/ */
struct iwl_scan_offload_cfg { struct iwl_scan_offload_cfg {
struct iwl_scan_offload_cmd scan_cmd; struct iwl_scan_offload_cmd scan_cmd;
struct iwl_scan_channel_cfg channel_cfg;
u8 data[0]; u8 data[0];
} __packed; } __packed;
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
* enum iwl_sta_flags - flags for the ADD_STA host command * enum iwl_sta_flags - flags for the ADD_STA host command
* @STA_FLG_REDUCED_TX_PWR_CTRL: * @STA_FLG_REDUCED_TX_PWR_CTRL:
* @STA_FLG_REDUCED_TX_PWR_DATA: * @STA_FLG_REDUCED_TX_PWR_DATA:
* @STA_FLG_FLG_ANT_MSK: Antenna selection * @STA_FLG_DISABLE_TX: set if TX should be disabled
* @STA_FLG_PS: set if STA is in Power Save * @STA_FLG_PS: set if STA is in Power Save
* @STA_FLG_INVALID: set if STA is invalid * @STA_FLG_INVALID: set if STA is invalid
* @STA_FLG_DLP_EN: Direct Link Protocol is enabled * @STA_FLG_DLP_EN: Direct Link Protocol is enabled
...@@ -91,10 +91,7 @@ enum iwl_sta_flags { ...@@ -91,10 +91,7 @@ enum iwl_sta_flags {
STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3),
STA_FLG_REDUCED_TX_PWR_DATA = BIT(6), STA_FLG_REDUCED_TX_PWR_DATA = BIT(6),
STA_FLG_FLG_ANT_A = (1 << 4), STA_FLG_DISABLE_TX = BIT(4),
STA_FLG_FLG_ANT_B = (2 << 4),
STA_FLG_FLG_ANT_MSK = (STA_FLG_FLG_ANT_A |
STA_FLG_FLG_ANT_B),
STA_FLG_PS = BIT(8), STA_FLG_PS = BIT(8),
STA_FLG_DRAIN_FLOW = BIT(12), STA_FLG_DRAIN_FLOW = BIT(12),
......
...@@ -548,6 +548,20 @@ struct iwl_beacon_notif { ...@@ -548,6 +548,20 @@ struct iwl_beacon_notif {
__le32 ibss_mgr_status; __le32 ibss_mgr_status;
} __packed; } __packed;
/**
* struct iwl_extended_beacon_notif - notifies about beacon transmission
* @beacon_notify_hdr: tx response command associated with the beacon
* @tsf: last beacon tsf
* @ibss_mgr_status: whether IBSS is manager
* @gp2: last beacon time in gp2
*/
struct iwl_extended_beacon_notif {
struct iwl_mvm_tx_resp beacon_notify_hdr;
__le64 tsf;
__le32 ibss_mgr_status;
__le32 gp2;
} __packed; /* BEACON_NTFY_API_S_VER_5 */
/** /**
* enum iwl_dump_control - dump (flush) control flags * enum iwl_dump_control - dump (flush) control flags
* @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
......
...@@ -904,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, ...@@ -904,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
struct iwl_mac_beacon_cmd beacon_cmd = {}; struct iwl_mac_beacon_cmd beacon_cmd = {};
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
u32 beacon_skb_len; u32 beacon_skb_len;
u32 rate; u32 rate, tx_flags;
if (WARN_ON(!beacon)) if (WARN_ON(!beacon))
return -EINVAL; return -EINVAL;
...@@ -914,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, ...@@ -914,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
/* TODO: for now the beacon template id is set to be the mac context id. /* TODO: for now the beacon template id is set to be the mac context id.
* Might be better to handle it as another resource ... */ * Might be better to handle it as another resource ... */
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
info = IEEE80211_SKB_CB(beacon);
/* Set up TX command fields */ /* Set up TX command fields */
beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
TX_CMD_FLG_BT_DIS | tx_flags |=
TX_CMD_FLG_TSF); iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<
TX_CMD_FLG_BT_PRIO_POS;
beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
mvm->mgmt_last_antenna_idx = mvm->mgmt_last_antenna_idx =
iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
...@@ -931,8 +934,6 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, ...@@ -931,8 +934,6 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
RATE_MCS_ANT_POS); RATE_MCS_ANT_POS);
info = IEEE80211_SKB_CB(beacon);
if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) { if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {
rate = IWL_FIRST_OFDM_RATE; rate = IWL_FIRST_OFDM_RATE;
} else { } else {
...@@ -1205,19 +1206,31 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, ...@@ -1205,19 +1206,31 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
struct iwl_device_cmd *cmd) struct iwl_device_cmd *cmd)
{ {
struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_beacon_notif *beacon = (void *)pkt->data; struct iwl_mvm_tx_resp *beacon_notify_hdr;
u16 status __maybe_unused = u64 tsf;
le16_to_cpu(beacon->beacon_notify_hdr.status.status);
u32 rate __maybe_unused =
le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) {
status & TX_STATUS_MSK, struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
beacon->beacon_notify_hdr.failure_frame,
le64_to_cpu(beacon->tsf), beacon_notify_hdr = &beacon->beacon_notify_hdr;
rate); tsf = le64_to_cpu(beacon->tsf);
mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
} else {
struct iwl_beacon_notif *beacon = (void *)pkt->data;
beacon_notify_hdr = &beacon->beacon_notify_hdr;
tsf = le64_to_cpu(beacon->tsf);
}
IWL_DEBUG_RX(mvm,
"beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n",
le16_to_cpu(beacon_notify_hdr->status.status) &
TX_STATUS_MSK,
beacon_notify_hdr->failure_frame, tsf,
mvm->ap_last_beacon_gp2,
le32_to_cpu(beacon_notify_hdr->initial_rate));
if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) {
if (!ieee80211_csa_is_complete(mvm->csa_vif)) { if (!ieee80211_csa_is_complete(mvm->csa_vif)) {
......
...@@ -374,6 +374,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -374,6 +374,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_P2P_GO_OPPPS; NL80211_FEATURE_P2P_GO_OPPPS;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
...@@ -688,6 +689,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) ...@@ -688,6 +689,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
iwl_mvm_restart_cleanup(mvm); iwl_mvm_restart_cleanup(mvm);
ret = iwl_mvm_up(mvm); ret = iwl_mvm_up(mvm);
if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
/* Something went wrong - we need to finish some cleanup
* that normally iwl_mvm_mac_restart_complete() below
* would do.
*/
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
iwl_mvm_d0i3_enable_tx(mvm, NULL);
}
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
return ret; return ret;
...@@ -1464,6 +1475,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, ...@@ -1464,6 +1475,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
mvmvif->ap_ibss_active = false; mvmvif->ap_ibss_active = false;
mvm->ap_last_beacon_gp2 = 0;
iwl_mvm_bt_coex_vif_change(mvm); iwl_mvm_bt_coex_vif_change(mvm);
...@@ -1543,7 +1555,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, ...@@ -1543,7 +1555,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req = &hw_req->req; struct cfg80211_scan_request *req = &hw_req->req;
int ret; int ret;
if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) if (req->n_channels == 0 ||
req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
return -EINVAL; return -EINVAL;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
......
...@@ -235,6 +235,15 @@ enum iwl_mvm_ref_type { ...@@ -235,6 +235,15 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_COUNT, IWL_MVM_REF_COUNT,
}; };
enum iwl_bt_force_ant_mode {
BT_FORCE_ANT_DIS = 0,
BT_FORCE_ANT_AUTO,
BT_FORCE_ANT_BT,
BT_FORCE_ANT_WIFI,
BT_FORCE_ANT_MAX,
};
/** /**
* struct iwl_mvm_vif_bf_data - beacon filtering related data * struct iwl_mvm_vif_bf_data - beacon filtering related data
* @bf_enabled: indicates if beacon filtering is enabled * @bf_enabled: indicates if beacon filtering is enabled
...@@ -629,6 +638,7 @@ struct iwl_mvm { ...@@ -629,6 +638,7 @@ struct iwl_mvm {
u32 last_ant_isol; u32 last_ant_isol;
u8 last_corun_lut; u8 last_corun_lut;
u8 bt_tx_prio; u8 bt_tx_prio;
enum iwl_bt_force_ant_mode bt_force_ant_mode;
/* Thermal Throttling and CTkill */ /* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle; struct iwl_mvm_tt_mgmt thermal_throttle;
...@@ -648,6 +658,9 @@ struct iwl_mvm { ...@@ -648,6 +658,9 @@ struct iwl_mvm {
bool ps_disabled; bool ps_disabled;
struct ieee80211_vif *csa_vif; struct ieee80211_vif *csa_vif;
/* system time of last beacon (for AP/GO interface) */
u32 ap_last_beacon_gp2;
}; };
/* Extract MVM priv from op_mode and _hw */ /* Extract MVM priv from op_mode and _hw */
...@@ -963,6 +976,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, ...@@ -963,6 +976,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm);
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
enum ieee80211_band band); enum ieee80211_band band);
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
......
...@@ -69,7 +69,9 @@ ...@@ -69,7 +69,9 @@
/* Default NVM size to read */ /* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE 7000 #define IWL_MAX_NVM_SECTION_SIZE 0x1b58
#define IWL_MAX_NVM_8000A_SECTION_SIZE 0xffc
#define IWL_MAX_NVM_8000B_SECTION_SIZE 0x1ffc
#define NVM_WRITE_OPCODE 1 #define NVM_WRITE_OPCODE 1
#define NVM_READ_OPCODE 0 #define NVM_READ_OPCODE 0
...@@ -219,7 +221,7 @@ static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section, ...@@ -219,7 +221,7 @@ static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section,
* without overflowing, so no check is needed. * without overflowing, so no check is needed.
*/ */
static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
u8 *data) u8 *data, u32 size_read)
{ {
u16 length, offset = 0; u16 length, offset = 0;
int ret; int ret;
...@@ -231,6 +233,13 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, ...@@ -231,6 +233,13 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
/* Read the NVM until exhausted (reading less than requested) */ /* Read the NVM until exhausted (reading less than requested) */
while (ret == length) { while (ret == length) {
/* Check no memory assumptions fail and cause an overflow */
if ((size_read + offset + length) >
mvm->cfg->base_params->eeprom_size) {
IWL_ERR(mvm, "EEPROM size is too small for NVM\n");
return -ENOBUFS;
}
ret = iwl_nvm_read_chunk(mvm, section, offset, length, data); ret = iwl_nvm_read_chunk(mvm, section, offset, length, data);
if (ret < 0) { if (ret < 0) {
IWL_DEBUG_EEPROM(mvm->trans->dev, IWL_DEBUG_EEPROM(mvm->trans->dev,
...@@ -326,6 +335,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) ...@@ -326,6 +335,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
u8 data[]; u8 data[];
} *file_sec; } *file_sec;
const u8 *eof, *temp; const u8 *eof, *temp;
int max_section_size;
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12) #define NVM_WORD2_ID(x) (x >> 12)
...@@ -334,6 +344,14 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) ...@@ -334,6 +344,14 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
/* Maximal size depends on HW family and step */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */
max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
else /* Family 8000 B-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
/* /*
* Obtain NVM image via request_firmware. Since we already used * Obtain NVM image via request_firmware. Since we already used
* request_firmware_nowait() for the firmware binary load and only * request_firmware_nowait() for the firmware binary load and only
...@@ -392,7 +410,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) ...@@ -392,7 +410,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
le16_to_cpu(file_sec->word1)); le16_to_cpu(file_sec->word1));
} }
if (section_size > IWL_MAX_NVM_SECTION_SIZE) { if (section_size > max_section_size) {
IWL_ERR(mvm, "ERROR - section too large (%d)\n", IWL_ERR(mvm, "ERROR - section too large (%d)\n",
section_size); section_size);
ret = -EINVAL; ret = -EINVAL;
...@@ -459,6 +477,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) ...@@ -459,6 +477,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
{ {
int ret, section; int ret, section;
u32 size_read = 0;
u8 *nvm_buffer, *temp; u8 *nvm_buffer, *temp;
if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
...@@ -475,9 +494,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) ...@@ -475,9 +494,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
return -ENOMEM; return -ENOMEM;
for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) { for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) {
/* we override the constness for initial read */ /* we override the constness for initial read */
ret = iwl_nvm_read_section(mvm, section, nvm_buffer); ret = iwl_nvm_read_section(mvm, section, nvm_buffer,
size_read);
if (ret < 0) if (ret < 0)
continue; continue;
size_read += ret;
temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
if (!temp) { if (!temp) {
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -504,7 +504,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -504,7 +504,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
scan_size = sizeof(struct iwl_scan_cmd) + scan_size = sizeof(struct iwl_scan_cmd) +
mvm->fw->ucode_capa.max_probe_length + mvm->fw->ucode_capa.max_probe_length +
(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)); (mvm->fw->ucode_capa.n_scan_channels *
sizeof(struct iwl_scan_channel));
mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
if (!mvm->scan_cmd) if (!mvm->scan_cmd)
goto out_free; goto out_free;
...@@ -826,6 +827,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -826,6 +827,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{ {
struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
u32 file_len; u32 file_len;
u32 trans_len; u32 trans_len;
...@@ -834,10 +836,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -834,10 +836,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
if (mvm->fw_error_dump) if (mvm->fw_error_dump)
return; return;
file_len = mvm->fw_error_sram_len + file_len = sizeof(*dump_file) +
sizeof(*dump_data) * 3 +
mvm->fw_error_sram_len +
mvm->fw_error_rxf_len + mvm->fw_error_rxf_len +
sizeof(*dump_file) + sizeof(*dump_info);
sizeof(*dump_data) * 2;
trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0);
if (trans_len) if (trans_len)
...@@ -852,11 +855,27 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -852,11 +855,27 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
dump_file->file_len = cpu_to_le32(file_len); dump_file->file_len = cpu_to_le32(file_len);
dump_data = (void *)dump_file->data; dump_data = (void *)dump_file->data;
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
dump_data->len = cpu_to_le32(sizeof(*dump_info));
dump_info = (void *) dump_data->data;
dump_info->device_family =
mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ?
cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) :
cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8);
memcpy(dump_info->fw_human_readable, mvm->fw->human_readable,
sizeof(dump_info->fw_human_readable));
strncpy(dump_info->dev_human_readable, mvm->cfg->name,
sizeof(dump_info->dev_human_readable));
strncpy(dump_info->bus_human_readable, mvm->dev->bus->name,
sizeof(dump_info->bus_human_readable));
dump_data = iwl_fw_error_next_data(dump_data);
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len);
memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len);
dump_data = iwl_mvm_fw_error_next_data(dump_data); dump_data = iwl_fw_error_next_data(dump_data);
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM);
dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); dump_data->len = cpu_to_le32(mvm->fw_error_sram_len);
...@@ -876,7 +895,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -876,7 +895,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
mvm->fw_error_sram_len = 0; mvm->fw_error_sram_len = 0;
if (trans_len) { if (trans_len) {
void *buf = iwl_mvm_fw_error_next_data(dump_data); void *buf = iwl_fw_error_next_data(dump_data);
u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf,
trans_len); trans_len);
dump_data = (void *)((u8 *)buf + real_trans_len); dump_data = (void *)((u8 *)buf + real_trans_len);
......
...@@ -275,7 +275,7 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, ...@@ -275,7 +275,7 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
int n_ssids, int n_ssids, u32 flags,
struct iwl_mvm_scan_params *params) struct iwl_mvm_scan_params *params)
{ {
bool global_bound = false; bool global_bound = false;
...@@ -297,6 +297,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, ...@@ -297,6 +297,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
params->max_out_time = 250; params->max_out_time = 250;
} }
if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
params->max_out_time = 200;
not_bound: not_bound:
for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
...@@ -333,16 +336,14 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, ...@@ -333,16 +336,14 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n"); IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
mvm->scan_status = IWL_MVM_SCAN_OS; mvm->scan_status = IWL_MVM_SCAN_OS;
memset(cmd, 0, sizeof(struct iwl_scan_cmd) + memset(cmd, 0, ksize(cmd));
mvm->fw->ucode_capa.max_probe_length +
(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
cmd->channel_count = (u8)req->n_channels; cmd->channel_count = (u8)req->n_channels;
cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, &params); iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, &params);
cmd->max_out_time = cpu_to_le32(params.max_out_time); cmd->max_out_time = cpu_to_le32(params.max_out_time);
cmd->suspend_time = cpu_to_le32(params.suspend_time); cmd->suspend_time = cpu_to_le32(params.suspend_time);
if (params.passive_fragmented) if (params.passive_fragmented)
...@@ -597,9 +598,7 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, ...@@ -597,9 +598,7 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
struct iwl_scan_offload_cmd *scan, struct iwl_scan_offload_cmd *scan,
struct iwl_mvm_scan_params *params) struct iwl_mvm_scan_params *params)
{ {
scan->channel_count = scan->channel_count = req->n_channels;
mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
...@@ -676,68 +675,50 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, ...@@ -676,68 +675,50 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
static void iwl_build_channel_cfg(struct iwl_mvm *mvm, static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req, struct cfg80211_sched_scan_request *req,
struct iwl_scan_channel_cfg *channels, u8 *channels_buffer,
enum ieee80211_band band, enum ieee80211_band band,
int *head, int *tail, int *head,
u32 ssid_bitmap, u32 ssid_bitmap,
struct iwl_mvm_scan_params *params) struct iwl_mvm_scan_params *params)
{ {
struct ieee80211_supported_band *s_band; u32 n_channels = mvm->fw->ucode_capa.n_scan_channels;
int n_channels = req->n_channels; __le32 *type = (__le32 *)channels_buffer;
int i, j, index = 0; __le16 *channel_number = (__le16 *)(type + n_channels);
bool partial; __le16 *iter_count = channel_number + n_channels;
__le32 *iter_interval = (__le32 *)(iter_count + n_channels);
/* u8 *active_dwell = (u8 *)(iter_interval + n_channels);
* We have to configure all supported channels, even if we don't want to u8 *passive_dwell = active_dwell + n_channels;
* scan on them, but we have to send channels in the order that we want int i, index = 0;
* to scan. So add requested channels to head of the list and others to
* the end. for (i = 0; i < req->n_channels; i++) {
*/ struct ieee80211_channel *chan = req->channels[i];
s_band = &mvm->nvm_data->bands[band];
if (chan->band != band)
continue;
for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
partial = false;
for (j = 0; j < n_channels; j++)
if (s_band->channels[i].center_freq ==
req->channels[j]->center_freq) {
index = *head; index = *head;
(*head)++; (*head)++;
/*
* Channels that came with the request will be
* in partial scan .
*/
partial = true;
break;
}
if (!partial) {
index = *tail;
(*tail)--;
}
channels->channel_number[index] =
cpu_to_le16(ieee80211_frequency_to_channel(
s_band->channels[i].center_freq));
channels->dwell_time[index][0] = params->dwell[band].active;
channels->dwell_time[index][1] = params->dwell[band].passive;
channels->iter_count[index] = cpu_to_le16(1); channel_number[index] = cpu_to_le16(chan->hw_value);
channels->iter_interval[index] = 0; active_dwell[index] = params->dwell[band].active;
passive_dwell[index] = params->dwell[band].passive;
iter_count[index] = cpu_to_le16(1);
iter_interval[index] = 0;
if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR)) if (!(chan->flags & IEEE80211_CHAN_NO_IR))
channels->type[index] |= type[index] |=
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE); cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
channels->type[index] |= type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL |
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL); IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
if (partial)
channels->type[index] |=
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
if (s_band->channels[i].flags & IEEE80211_CHAN_NO_HT40) if (chan->flags & IEEE80211_CHAN_NO_HT40)
channels->type[index] |= type[index] |=
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW); cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW);
/* scan for all SSIDs from req->ssids */ /* scan for all SSIDs from req->ssids */
channels->type[index] |= cpu_to_le32(ssid_bitmap); type[index] |= cpu_to_le32(ssid_bitmap);
} }
} }
...@@ -749,10 +730,10 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, ...@@ -749,10 +730,10 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
int head = 0; int head = 0;
int tail = band_2ghz + band_5ghz - 1;
u32 ssid_bitmap; u32 ssid_bitmap;
int cmd_len; int cmd_len;
int ret; int ret;
u8 *probes;
struct iwl_scan_offload_cfg *scan_cfg; struct iwl_scan_offload_cfg *scan_cfg;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
...@@ -763,13 +744,17 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, ...@@ -763,13 +744,17 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
cmd_len = sizeof(struct iwl_scan_offload_cfg) + cmd_len = sizeof(struct iwl_scan_offload_cfg) +
mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE +
2 * SCAN_OFFLOAD_PROBE_REQ_SIZE; 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE;
scan_cfg = kzalloc(cmd_len, GFP_KERNEL); scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
if (!scan_cfg) if (!scan_cfg)
return -ENOMEM; return -ENOMEM;
iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, &params); probes = scan_cfg->data +
mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE;
iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params); iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params);
scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
...@@ -779,19 +764,19 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, ...@@ -779,19 +764,19 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
iwl_scan_offload_build_tx_cmd(mvm, vif, ies, iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
IEEE80211_BAND_2GHZ, IEEE80211_BAND_2GHZ,
&scan_cfg->scan_cmd.tx_cmd[0], &scan_cfg->scan_cmd.tx_cmd[0],
scan_cfg->data); probes);
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, iwl_build_channel_cfg(mvm, req, scan_cfg->data,
IEEE80211_BAND_2GHZ, &head, &tail, IEEE80211_BAND_2GHZ, &head,
ssid_bitmap, &params); ssid_bitmap, &params);
} }
if (band_5ghz) { if (band_5ghz) {
iwl_scan_offload_build_tx_cmd(mvm, vif, ies, iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
IEEE80211_BAND_5GHZ, IEEE80211_BAND_5GHZ,
&scan_cfg->scan_cmd.tx_cmd[1], &scan_cfg->scan_cmd.tx_cmd[1],
scan_cfg->data + probes +
SCAN_OFFLOAD_PROBE_REQ_SIZE); SCAN_OFFLOAD_PROBE_REQ_SIZE);
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, iwl_build_channel_cfg(mvm, req, scan_cfg->data,
IEEE80211_BAND_5GHZ, &head, &tail, IEEE80211_BAND_5GHZ, &head,
ssid_bitmap, &params); ssid_bitmap, &params);
} }
......
...@@ -1448,3 +1448,23 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, ...@@ -1448,3 +1448,23 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
return 0; return 0;
} }
void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta, bool disable)
{
struct iwl_mvm_add_sta_cmd cmd = {
.add_modify = STA_MODE_MODIFY,
.sta_id = mvmsta->sta_id,
.station_flags = disable ? cpu_to_le32(STA_FLG_DISABLE_TX) : 0,
.station_flags_msk = cpu_to_le32(STA_FLG_DISABLE_TX),
.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
};
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);
}
...@@ -404,5 +404,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, ...@@ -404,5 +404,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
bool agg); bool agg);
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool drain); bool drain);
void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta, bool disable);
#endif /* __sta_h__ */ #endif /* __sta_h__ */
...@@ -205,7 +205,13 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, ...@@ -205,7 +205,13 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
mvm->mgmt_last_antenna_idx = mvm->mgmt_last_antenna_idx =
iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
mvm->mgmt_last_antenna_idx); mvm->mgmt_last_antenna_idx);
rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
if (info->band == IEEE80211_BAND_2GHZ &&
!iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS;
else
rate_flags =
BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
/* Set CCK flag as needed */ /* Set CCK flag as needed */
if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
......
...@@ -260,6 +260,9 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) ...@@ -260,6 +260,9 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @wd_timeout: queue watchdog timeout (jiffies) * @wd_timeout: queue watchdog timeout (jiffies)
* @reg_lock: protect hw register access * @reg_lock: protect hw register access
* @cmd_in_flight: true when we have a host command in flight * @cmd_in_flight: true when we have a host command in flight
* @fw_mon_phys: physical address of the buffer for the firmware monitor
* @fw_mon_page: points to the first page of the buffer for the firmware monitor
* @fw_mon_size: size of the buffer for the firmware monitor
*/ */
struct iwl_trans_pcie { struct iwl_trans_pcie {
struct iwl_rxq rxq; struct iwl_rxq rxq;
...@@ -312,6 +315,10 @@ struct iwl_trans_pcie { ...@@ -312,6 +315,10 @@ struct iwl_trans_pcie {
/*protect hw register */ /*protect hw register */
spinlock_t reg_lock; spinlock_t reg_lock;
bool cmd_in_flight; bool cmd_in_flight;
dma_addr_t fw_mon_phys;
struct page *fw_mon_page;
u32 fw_mon_size;
}; };
#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
......
...@@ -76,6 +76,68 @@ ...@@ -76,6 +76,68 @@
#include "iwl-fw-error-dump.h" #include "iwl-fw-error-dump.h"
#include "internal.h" #include "internal.h"
static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (!trans_pcie->fw_mon_page)
return;
dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys,
trans_pcie->fw_mon_size, DMA_FROM_DEVICE);
__free_pages(trans_pcie->fw_mon_page,
get_order(trans_pcie->fw_mon_size));
trans_pcie->fw_mon_page = NULL;
trans_pcie->fw_mon_phys = 0;
trans_pcie->fw_mon_size = 0;
}
static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct page *page;
dma_addr_t phys;
u32 size;
u8 power;
if (trans_pcie->fw_mon_page) {
dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys,
trans_pcie->fw_mon_size,
DMA_FROM_DEVICE);
return;
}
phys = 0;
for (power = 26; power >= 11; power--) {
int order;
size = BIT(power);
order = get_order(size);
page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO,
order);
if (!page)
continue;
phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order,
DMA_FROM_DEVICE);
if (dma_mapping_error(trans->dev, phys)) {
__free_pages(page, order);
continue;
}
IWL_INFO(trans,
"Allocated 0x%08x bytes (order %d) for firmware monitor.\n",
size, order);
break;
}
if (!page)
return;
trans_pcie->fw_mon_page = page;
trans_pcie->fw_mon_phys = phys;
trans_pcie->fw_mon_size = size;
}
static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
{ {
iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG,
...@@ -675,6 +737,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, ...@@ -675,6 +737,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image) const struct fw_img *image)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret = 0; int ret = 0;
int first_ucode_section; int first_ucode_section;
...@@ -733,6 +796,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, ...@@ -733,6 +796,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
return ret; return ret;
} }
/* supported for 7000 only for the moment */
if (iwlwifi_mod_params.fw_monitor &&
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
iwl_pcie_alloc_fw_monitor(trans);
if (trans_pcie->fw_mon_size) {
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
trans_pcie->fw_mon_phys >> 4);
iwl_write_prph(trans, MON_BUFF_END_ADDR,
(trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size) >> 4);
}
}
/* release CPU reset */ /* release CPU reset */
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT);
...@@ -1126,6 +1203,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) ...@@ -1126,6 +1203,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
if (trans_pcie->napi.poll) if (trans_pcie->napi.poll)
netif_napi_del(&trans_pcie->napi); netif_napi_del(&trans_pcie->napi);
iwl_pcie_free_fw_monitor(trans);
kfree(trans); kfree(trans);
} }
...@@ -1494,10 +1573,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, ...@@ -1494,10 +1573,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
txq = &trans_pcie->txq[cnt]; txq = &trans_pcie->txq[cnt];
q = &txq->q; q = &txq->q;
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"hwq %.2d: read=%u write=%u use=%d stop=%d\n", "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d%s\n",
cnt, q->read_ptr, q->write_ptr, cnt, q->read_ptr, q->write_ptr,
!!test_bit(cnt, trans_pcie->queue_used), !!test_bit(cnt, trans_pcie->queue_used),
!!test_bit(cnt, trans_pcie->queue_stopped)); !!test_bit(cnt, trans_pcie->queue_stopped),
txq->need_update,
(cnt == trans_pcie->cmd_queue ? " HCMD" : ""));
} }
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);
...@@ -1519,6 +1600,10 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, ...@@ -1519,6 +1600,10 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
rxq->read); rxq->read);
pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
rxq->write); rxq->write);
pos += scnprintf(buf + pos, bufsz - pos, "write_actual: %u\n",
rxq->write_actual);
pos += scnprintf(buf + pos, bufsz - pos, "need_update: %d\n",
rxq->need_update);
pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
rxq->free_count); rxq->free_count);
if (rxq->rb_stts) { if (rxq->rb_stts) {
...@@ -1698,10 +1783,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, ...@@ -1698,10 +1783,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
u32 len; u32 len;
int i, ptr; int i, ptr;
len = sizeof(*data) +
cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
if (trans_pcie->fw_mon_page)
len += sizeof(*data) + sizeof(struct iwl_fw_error_fw_mon) +
trans_pcie->fw_mon_size;
if (!buf) if (!buf)
return sizeof(*data) + return len;
cmdq->q.n_window * (sizeof(*txcmd) +
TFD_MAX_PAYLOAD_SIZE);
len = 0; len = 0;
data = buf; data = buf;
...@@ -1729,7 +1819,40 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, ...@@ -1729,7 +1819,40 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
spin_unlock_bh(&cmdq->lock); spin_unlock_bh(&cmdq->lock);
data->len = cpu_to_le32(len); data->len = cpu_to_le32(len);
return sizeof(*data) + len; len += sizeof(*data);
if (trans_pcie->fw_mon_page) {
struct iwl_fw_error_fw_mon *fw_mon_data;
data = iwl_fw_error_next_data(data);
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
data->len = cpu_to_le32(trans_pcie->fw_mon_size +
sizeof(*fw_mon_data));
fw_mon_data = (void *)data->data;
fw_mon_data->fw_mon_wr_ptr =
cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR));
fw_mon_data->fw_mon_cycle_cnt =
cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT));
fw_mon_data->fw_mon_base_ptr =
cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR));
/*
* The firmware is now asserted, it won't write anything to
* the buffer. CPU can take ownership to fetch the data.
* The buffer will be handed back to the device before the
* firmware will be restarted.
*/
dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys,
trans_pcie->fw_mon_size,
DMA_FROM_DEVICE);
memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page),
trans_pcie->fw_mon_size);
len += sizeof(*data) + sizeof(*fw_mon_data) +
trans_pcie->fw_mon_size;
}
return len;
} }
#else #else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
...@@ -1870,6 +1993,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -1870,6 +1993,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
} }
trans->hw_rev = iwl_read32(trans, CSR_HW_REV); trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
/*
* In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have
* changed, and now the revision step also includes bit 0-1 (no more
* "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)
trans->hw_rev = (trans->hw_rev & 0xfff0) |
((trans->hw_rev << 2) & 0xc);
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
"PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
......
...@@ -1438,6 +1438,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, ...@@ -1438,6 +1438,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
trans_pcie->cmd_in_flight = false; trans_pcie->cmd_in_flight = false;
IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
idx = -EIO; idx = -EIO;
goto out; goto out;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment