瀏覽代碼

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

John W. Linville 11 年之前
父節點
當前提交
5f4ef7197d
共有 31 個文件被更改,包括 609 次插入177 次删除
  1. 9 0
      drivers/net/wireless/iwlwifi/dvm/power.c
  2. 2 3
      drivers/net/wireless/iwlwifi/iwl-8000.c
  3. 1 1
      drivers/net/wireless/iwlwifi/iwl-config.h
  4. 15 0
      drivers/net/wireless/iwlwifi/iwl-drv.c
  5. 0 1
      drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
  6. 44 2
      drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
  7. 4 2
      drivers/net/wireless/iwlwifi/iwl-fw-file.h
  8. 8 0
      drivers/net/wireless/iwlwifi/iwl-fw.h
  9. 2 0
      drivers/net/wireless/iwlwifi/iwl-modparams.h
  10. 40 16
      drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
  11. 6 0
      drivers/net/wireless/iwlwifi/iwl-prph.h
  12. 64 13
      drivers/net/wireless/iwlwifi/mvm/coex.c
  13. 2 0
      drivers/net/wireless/iwlwifi/mvm/constants.h
  14. 39 0
      drivers/net/wireless/iwlwifi/mvm/debugfs.c
  15. 9 1
      drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
  16. 1 1
      drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
  17. 14 33
      drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
  18. 2 5
      drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
  19. 14 0
      drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
  20. 29 16
      drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
  21. 14 1
      drivers/net/wireless/iwlwifi/mvm/mac80211.c
  22. 14 0
      drivers/net/wireless/iwlwifi/mvm/mvm.h
  23. 25 4
      drivers/net/wireless/iwlwifi/mvm/nvm.c
  24. 25 6
      drivers/net/wireless/iwlwifi/mvm/ops.c
  25. 50 65
      drivers/net/wireless/iwlwifi/mvm/scan.c
  26. 20 0
      drivers/net/wireless/iwlwifi/mvm/sta.c
  27. 2 0
      drivers/net/wireless/iwlwifi/mvm/sta.h
  28. 7 1
      drivers/net/wireless/iwlwifi/mvm/tx.c
  29. 7 0
      drivers/net/wireless/iwlwifi/pcie/internal.h
  30. 139 6
      drivers/net/wireless/iwlwifi/pcie/trans.c
  31. 1 0
      drivers/net/wireless/iwlwifi/pcie/tx.c

+ 9 - 0
drivers/net/wireless/iwlwifi/dvm/power.c

@@ -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,
 	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)

+ 2 - 3
drivers/net/wireless/iwlwifi/iwl-8000.c

@@ -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 = {
 	.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,

+ 1 - 1
drivers/net/wireless/iwlwifi/iwl-config.h

@@ -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__ */

+ 15 - 0
drivers/net/wireless/iwlwifi/iwl-drv.c

@@ -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,
 	}
 	}
 
 
 	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,
 			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)
 	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,
 		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)");

+ 0 - 1
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c

@@ -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;
 	}
 	}
 
 

+ 44 - 2
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h

@@ -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 {
 	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));
 }
 }

+ 4 - 2
drivers/net/wireless/iwlwifi/iwl-fw-file.h

@@ -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 {
@@ -136,7 +137,8 @@ struct iwl_ucode_tlv {
 	u8 data[0];
 	u8 data[0];
 };
 };
 
 
-#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 {
 	 */
 	 */
 	__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;

+ 8 - 0
drivers/net/wireless/iwlwifi/iwl-fw.h

@@ -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 {
 /**
 /**
  * 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 {
 
 
 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 {
 	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__ */

+ 2 - 0
drivers/net/wireless/iwlwifi/iwl-modparams.h

@@ -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 {
 	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__ */

+ 40 - 16
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c

@@ -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 {
 	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,
 		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,
 		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,
 				 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,
 	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,20 +496,28 @@ 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");
 	}
 	}
 
 
-	/* take the MAC address from the OTP */
-	hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_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];
+	if (nvm_hw) {
+		/* take the MAC address from the OTP */
+		hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_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];
+
+		hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000);
+		data->hw_addr[4] = hw_addr[1];
+		data->hw_addr[5] = hw_addr[0];
+		return;
+	}
 
 
-	hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000);
-	data->hw_addr[4] = hw_addr[1];
-	data->hw_addr[5] = hw_addr[0];
+	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,
 				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,

+ 6 - 0
drivers/net/wireless/iwlwifi/iwl-prph.h

@@ -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__ */

+ 64 - 13
drivers/net/wireless/iwlwifi/mvm/coex.c

@@ -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)
 	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)
 		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)
 	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,
 
 
 	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,
 	/* 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,
 		 * 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)
 	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,
 
 
 	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,
 	    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,
 				     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
-	 * already killed.
-	 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we
-	 * Tx.
+	 * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas
+	 * since BT is already killed.
+	 * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while
+	 * 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,
 
 
 	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;
 
 

+ 2 - 0
drivers/net/wireless/iwlwifi/mvm/constants.h

@@ -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

+ 39 - 0
drivers/net/wireless/iwlwifi/mvm/debugfs.c

@@ -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);
 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)
 	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);

+ 9 - 1
drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h

@@ -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 {
 	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 {
  * @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 {
 	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;

+ 1 - 1
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h

@@ -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
 
 

+ 14 - 33
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h

@@ -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 {
  * @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 {
 	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 {
 	IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL	= BIT(25),
 	IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL	= BIT(25),
 };
 };
 
 
-/**
- * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S
- * @type:		bitmap - see enum iwl_scan_offload_channel_flags.
- *			0:	passive (0) or active (1) scan.
- *			1-20:	directed scan to i'th ssid.
- *			22:	channel width configuation - 1 for narrow.
- *			24:	full scan.
- *			25:	partial scan.
- * @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.
+/* channel configuration for struct iwl_scan_offload_cfg. Each channels needs:
+ * __le32 type:	bitmap; bits 1-20 are for directed scan to i'th ssid and
+ *	see enum iwl_scan_offload_channel_flags.
+ * __le16 channel_number: channel number 1-13 etc.
+ * __le16 iter_count: repetition count for the channel.
+ * __le32 iter_interval: interval between two innteration on one channel.
+ * u8 active_dwell.
+ * u8 passive_dwell.
  */
  */
-struct iwl_scan_channel_cfg {
-	__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;
+#define IWL_SCAN_CHAN_SIZE 14
 
 
 /**
 /**
  * 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:		probe request frames (one per band)
+ * @data:		scan channel configuration and probe request frames
  */
  */
 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;
 
 

+ 2 - 5
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h

@@ -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 {
 	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_FLG_ANT_B		= (2 << 4),
-	STA_FLG_FLG_ANT_MSK		= (STA_FLG_FLG_ANT_A |
-					   STA_FLG_FLG_ANT_B),
+	STA_FLG_DISABLE_TX		= BIT(4),
 
 
 	STA_FLG_PS			= BIT(8),
 	STA_FLG_PS			= BIT(8),
 	STA_FLG_DRAIN_FLOW		= BIT(12),
 	STA_FLG_DRAIN_FLOW		= BIT(12),

+ 14 - 0
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h

@@ -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

+ 29 - 16
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c

@@ -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,
 	/* 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_CMD_FLG_BT_DIS  |
-					     TX_CMD_FLG_TSF);
+	tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
+	tx_flags |=
+		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,
 		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,
 			    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;
-	u16 status __maybe_unused =
-		le16_to_cpu(beacon->beacon_notify_hdr.status.status);
-	u32 rate __maybe_unused =
-		le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
+	struct iwl_mvm_tx_resp *beacon_notify_hdr;
+	u64 tsf;
 
 
 	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",
-		     status & TX_STATUS_MSK,
-		     beacon->beacon_notify_hdr.failure_frame,
-		     le64_to_cpu(beacon->tsf),
-		     rate);
+	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) {
+		struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
+
+		beacon_notify_hdr = &beacon->beacon_notify_hdr;
+		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)) {

+ 14 - 1
drivers/net/wireless/iwlwifi/mvm/mac80211.c

@@ -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)
 		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,
 	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,
 	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);

+ 14 - 0
drivers/net/wireless/iwlwifi/mvm/mvm.h

@@ -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 {
 	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 {
 	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,
 				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,

+ 25 - 4
drivers/net/wireless/iwlwifi/mvm/nvm.c

@@ -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,
  * 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,
 
 
 	/* 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)
 		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)
 
 
 	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)
 						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)
 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)
 			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;

+ 25 - 6
drivers/net/wireless/iwlwifi/mvm/ops.c

@@ -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)
 {
 {
 	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)
 	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_data) * 2;
+		   sizeof(*dump_info);
 
 
 	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)
 	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)
 	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);

+ 50 - 65
drivers/net/wireless/iwlwifi/mvm/scan.c

@@ -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,
 		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,
 
 
 	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) +
-	       mvm->fw->ucode_capa.max_probe_length +
-	       (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
+	memset(cmd, 0, ksize(cmd));
 
 
 	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,
 			       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 =
-		mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
-		mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
+	scan->channel_count = req->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,
 
 
 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;
-	int n_channels = req->n_channels;
-	int i, j, index = 0;
-	bool partial;
+	u32 n_channels = mvm->fw->ucode_capa.n_scan_channels;
+	__le32 *type = (__le32 *)channels_buffer;
+	__le16 *channel_number = (__le16 *)(type + n_channels);
+	__le16 *iter_count = channel_number + n_channels;
+	__le32 *iter_interval = (__le32 *)(iter_count + n_channels);
+	u8 *active_dwell = (u8 *)(iter_interval + n_channels);
+	u8 *passive_dwell = active_dwell + n_channels;
+	int i, index = 0;
+
+	for (i = 0; i < req->n_channels; i++) {
+		struct ieee80211_channel *chan = req->channels[i];
+
+		if (chan->band != band)
+			continue;
 
 
-	/*
-	 * We have to configure all supported channels, even if we don't want to
-	 * scan on them, but we have to send channels in the order that we want
-	 * to scan. So add requested channels to head of the list and others to
-	 * the end.
-	*/
-	s_band = &mvm->nvm_data->bands[band];
-
-	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;
-				(*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;
+		index = *head;
+		(*head)++;
+
+		channel_number[index] = cpu_to_le16(chan->hw_value);
+		active_dwell[index] = params->dwell[band].active;
+		passive_dwell[index] = params->dwell[band].passive;
 
 
-		channels->iter_count[index] = cpu_to_le16(1);
-		channels->iter_interval[index] = 0;
+		iter_count[index] = cpu_to_le16(1);
+		iter_interval[index] = 0;
 
 
-		if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))
-			channels->type[index] |=
+		if (!(chan->flags & IEEE80211_CHAN_NO_IR))
+			type[index] |=
 				cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
 				cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
 
 
-		channels->type[index] |=
-				cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL);
-		if (partial)
-			channels->type[index] |=
-				cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
+		type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL |
+					   IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
 
 
-		if (s_band->channels[i].flags & IEEE80211_CHAN_NO_HT40)
-			channels->type[index] |=
+		if (chan->flags & IEEE80211_CHAN_NO_HT40)
+			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,
 	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,
 	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,
 		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);
-		iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
-				      IEEE80211_BAND_2GHZ, &head, &tail,
+					      probes);
+		iwl_build_channel_cfg(mvm, req, scan_cfg->data,
+				      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,
-				      IEEE80211_BAND_5GHZ, &head, &tail,
+		iwl_build_channel_cfg(mvm, req, scan_cfg->data,
+				      IEEE80211_BAND_5GHZ, &head,
 				      ssid_bitmap, &params);
 				      ssid_bitmap, &params);
 	}
 	}
 
 

+ 20 - 0
drivers/net/wireless/iwlwifi/mvm/sta.c

@@ -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);
+}

+ 2 - 0
drivers/net/wireless/iwlwifi/mvm/sta.h

@@ -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__ */

+ 7 - 1
drivers/net/wireless/iwlwifi/mvm/tx.c

@@ -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))

+ 7 - 0
drivers/net/wireless/iwlwifi/pcie/internal.h

@@ -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 {
 	/*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) \

+ 139 - 6
drivers/net/wireless/iwlwifi/pcie/trans.c

@@ -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,
 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,
 			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)
 	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,
 		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,
 						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,
 	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) +
-		       cmdq->q.n_window * (sizeof(*txcmd) +
-					   TFD_MAX_PAYLOAD_SIZE);
+		return len;
 
 
 	len = 0;
 	len = 0;
 	data = buf;
 	data = buf;
@@ -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,
 	}
 	}
 
 
 	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);

+ 1 - 0
drivers/net/wireless/iwlwifi/pcie/tx.c

@@ -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;
 		}
 		}