diff options
Diffstat (limited to 'drivers/net/wireless')
259 files changed, 12084 insertions, 3253 deletions
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 9729e6941635..c04fb00e7930 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -11,7 +11,8 @@ ath10k_core-y += mac.o \  		 wmi-tlv.o \  		 bmi.o \  		 hw.o \ -		 p2p.o +		 p2p.o \ +		 swap.o  ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o  ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 31a990635490..df7c7616533b 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -178,7 +178,7 @@ struct bmi_target_info {  };  /* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ) +#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ)  #define BMI_CE_NUM_TO_TARG 0  #define BMI_CE_NUM_TO_HOST 1 diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e508c65b6ba8..cf28fbebaedc 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -452,6 +452,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,  {  	struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;  	unsigned int nentries_mask = dest_ring->nentries_mask; +	struct ath10k *ar = ce_state->ar;  	unsigned int sw_index = dest_ring->sw_index;  	struct ce_desc *base = dest_ring->base_addr_owner_space; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0eddb204d85b..5c903e15dd65 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -21,7 +21,7 @@  #include "hif.h"  /* Maximum number of Copy Engine's supported */ -#define CE_COUNT_MAX 8 +#define CE_COUNT_MAX 12  #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096  /* Descriptor rings must be aligned to this boundary */ @@ -38,8 +38,13 @@ struct ath10k_ce_pipe;  #define CE_DESC_FLAGS_GATHER         (1 << 0)  #define CE_DESC_FLAGS_BYTE_SWAP      (1 << 1) -#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC -#define CE_DESC_FLAGS_META_DATA_LSB  2 + +/* Following desc flags are used in QCA99X0 */ +#define CE_DESC_FLAGS_HOST_INT_DIS	(1 << 2) +#define CE_DESC_FLAGS_TGT_INT_DIS	(1 << 3) + +#define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask +#define CE_DESC_FLAGS_META_DATA_LSB  ar->hw_values->ce_desc_meta_data_lsb  struct ce_desc {  	__le32 addr; @@ -423,8 +428,10 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)  #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask)) -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB		8 -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK		0x0000ff00 +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ +				ar->regs->ce_wrap_intr_sum_host_msi_lsb +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ +				ar->regs->ce_wrap_intr_sum_host_msi_mask  #define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \  	(((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \  		CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 59496a90ad5e..b87b98617073 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -31,16 +31,19 @@  #include "wmi-ops.h"  unsigned int ath10k_debug_mask; +static unsigned int ath10k_cryptmode_param;  static bool uart_print;  static bool skip_otp;  module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); +module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);  module_param(uart_print, bool, 0644);  module_param(skip_otp, bool, 0644);  MODULE_PARM_DESC(debug_mask, "Debugging mask");  MODULE_PARM_DESC(uart_print, "Uart target debugging");  MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");  static const struct ath10k_hw_params ath10k_hw_params_list[] = {  	{ @@ -49,6 +52,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  		.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,  		.uart_pin = 7,  		.has_shifted_cc_wraparound = true, +		.otp_exe_param = 0, +		.channel_counters_freq_hz = 88000,  		.fw = {  			.dir = QCA988X_HW_2_0_FW_DIR,  			.fw = QCA988X_HW_2_0_FW_FILE, @@ -63,6 +68,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  		.name = "qca6174 hw2.1",  		.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,  		.uart_pin = 6, +		.otp_exe_param = 0, +		.channel_counters_freq_hz = 88000,  		.fw = {  			.dir = QCA6174_HW_2_1_FW_DIR,  			.fw = QCA6174_HW_2_1_FW_FILE, @@ -77,6 +84,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  		.name = "qca6174 hw3.0",  		.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,  		.uart_pin = 6, +		.otp_exe_param = 0, +		.channel_counters_freq_hz = 88000,  		.fw = {  			.dir = QCA6174_HW_3_0_FW_DIR,  			.fw = QCA6174_HW_3_0_FW_FILE, @@ -91,6 +100,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  		.name = "qca6174 hw3.2",  		.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,  		.uart_pin = 6, +		.otp_exe_param = 0, +		.channel_counters_freq_hz = 88000,  		.fw = {  			/* uses same binaries as hw3.0 */  			.dir = QCA6174_HW_3_0_FW_DIR, @@ -101,8 +112,69 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,  		},  	}, +	{ +		.id = QCA99X0_HW_2_0_DEV_VERSION, +		.name = "qca99x0 hw2.0", +		.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, +		.uart_pin = 7, +		.otp_exe_param = 0x00000700, +		.continuous_frag_desc = true, +		.channel_counters_freq_hz = 150000, +		.fw = { +			.dir = QCA99X0_HW_2_0_FW_DIR, +			.fw = QCA99X0_HW_2_0_FW_FILE, +			.otp = QCA99X0_HW_2_0_OTP_FILE, +			.board = QCA99X0_HW_2_0_BOARD_DATA_FILE, +			.board_size = QCA99X0_BOARD_DATA_SZ, +			.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, +		}, +	}, +}; + +static const char *const ath10k_core_fw_feature_str[] = { +	[ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx", +	[ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x", +	[ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx", +	[ATH10K_FW_FEATURE_NO_P2P] = "no-p2p", +	[ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2", +	[ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps", +	[ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan", +	[ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp", +	[ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad", +	[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",  }; +static unsigned int ath10k_core_get_fw_feature_str(char *buf, +						   size_t buf_len, +						   enum ath10k_fw_features feat) +{ +	if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) || +	    WARN_ON(!ath10k_core_fw_feature_str[feat])) { +		return scnprintf(buf, buf_len, "bit%d", feat); +	} + +	return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]); +} + +void ath10k_core_get_fw_features_str(struct ath10k *ar, +				     char *buf, +				     size_t buf_len) +{ +	unsigned int len = 0; +	int i; + +	for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { +		if (test_bit(i, ar->fw_features)) { +			if (len > 0) +				len += scnprintf(buf + len, buf_len - len, ","); + +			len += ath10k_core_get_fw_feature_str(buf + len, +							      buf_len - len, +							      i); +		} +	} +} +  static void ath10k_send_suspend_complete(struct ath10k *ar)  {  	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); @@ -164,6 +236,17 @@ static int ath10k_init_configure_target(struct ath10k *ar)  		return ret;  	} +	/* Some devices have a special sanity check that verifies the PCI +	 * Device ID is written to this host interest var. It is known to be +	 * required to boot QCA6164. +	 */ +	ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext, +				 ar->dev_id); +	if (ret) { +		ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret); +		return ret; +	} +  	return 0;  } @@ -355,6 +438,7 @@ out:  static int ath10k_download_and_run_otp(struct ath10k *ar)  {  	u32 result, address = ar->hw_params.patch_load_addr; +	u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;  	int ret;  	ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); @@ -380,7 +464,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)  		return ret;  	} -	ret = ath10k_bmi_execute(ar, address, 0, &result); +	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);  	if (ret) {  		ath10k_err(ar, "could not execute otp (%d)\n", ret);  		return ret; @@ -412,6 +496,13 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)  		data = ar->firmware_data;  		data_len = ar->firmware_len;  		mode_name = "normal"; +		ret = ath10k_swap_code_seg_configure(ar, +				ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); +		if (ret) { +			ath10k_err(ar, "failed to configure fw code swap: %d\n", +				   ret); +			return ret; +		}  		break;  	case ATH10K_FIRMWARE_MODE_UTF:  		data = ar->testmode.utf->data; @@ -451,6 +542,8 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)  	if (!IS_ERR(ar->cal_file))  		release_firmware(ar->cal_file); +	ath10k_swap_code_seg_release(ar); +  	ar->board = NULL;  	ar->board_data = NULL;  	ar->board_len = 0; @@ -464,6 +557,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)  	ar->firmware_len = 0;  	ar->cal_file = NULL; +  }  static int ath10k_fetch_cal_file(struct ath10k *ar) @@ -737,6 +831,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)  			ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",  				   ar->htt.op_version);  			break; +		case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE: +			ath10k_dbg(ar, ATH10K_DBG_BOOT, +				   "found fw code swap image ie (%zd B)\n", +				   ie_len); +			ar->swap.firmware_codeswap_data = data; +			ar->swap.firmware_codeswap_len = ie_len; +			break;  		default:  			ath10k_warn(ar, "Unknown FW IE: %u\n",  				    le32_to_cpu(hdr->id)); @@ -991,6 +1092,46 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)  		return -EINVAL;  	} +	ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI; +	switch (ath10k_cryptmode_param) { +	case ATH10K_CRYPT_MODE_HW: +		clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); +		clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); +		break; +	case ATH10K_CRYPT_MODE_SW: +		if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, +			      ar->fw_features)) { +			ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware"); +			return -EINVAL; +		} + +		set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); +		set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); +		break; +	default: +		ath10k_info(ar, "invalid cryptmode: %d\n", +			    ath10k_cryptmode_param); +		return -EINVAL; +	} + +	ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; +	ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; + +	if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { +		ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW; + +		/* Workaround: +		 * +		 * Firmware A-MSDU aggregation breaks with RAW Tx encap mode +		 * and causes enormous performance issues (malformed frames, +		 * etc). +		 * +		 * Disabling A-MSDU makes RAW mode stable with heavy traffic +		 * albeit a bit slower compared to regular operation. +		 */ +		ar->htt.max_num_amsdu = 1; +	} +  	/* Backwards compatibility for firmwares without  	 * ATH10K_FW_IE_WMI_OP_VERSION.  	 */ @@ -1014,6 +1155,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)  		ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;  		ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |  			WMI_STAT_PEER; +		ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;  		break;  	case ATH10K_FW_WMI_OP_VERSION_10_1:  	case ATH10K_FW_WMI_OP_VERSION_10_2: @@ -1023,6 +1165,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)  		ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;  		ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;  		ar->fw_stats_req_mask = WMI_STAT_PEER; +		ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;  		break;  	case ATH10K_FW_WMI_OP_VERSION_TLV:  		ar->max_num_peers = TARGET_TLV_NUM_PEERS; @@ -1033,6 +1176,17 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)  		ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;  		ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |  			WMI_STAT_PEER; +		ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; +		break; +	case ATH10K_FW_WMI_OP_VERSION_10_4: +		ar->max_num_peers = TARGET_10_4_NUM_PEERS; +		ar->max_num_stations = TARGET_10_4_NUM_STATIONS; +		ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; +		ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; +		ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; +		ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; +		ar->fw_stats_req_mask = WMI_STAT_PEER; +		ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM;  		break;  	case ATH10K_FW_WMI_OP_VERSION_UNSET:  	case ATH10K_FW_WMI_OP_VERSION_MAX: @@ -1056,6 +1210,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)  		case ATH10K_FW_WMI_OP_VERSION_TLV:  			ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV;  			break; +		case ATH10K_FW_WMI_OP_VERSION_10_4:  		case ATH10K_FW_WMI_OP_VERSION_UNSET:  		case ATH10K_FW_WMI_OP_VERSION_MAX:  			WARN_ON(1); @@ -1272,13 +1427,13 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)  void ath10k_core_stop(struct ath10k *ar)  {  	lockdep_assert_held(&ar->conf_mutex); +	ath10k_debug_stop(ar);  	/* try to suspend target */  	if (ar->state != ATH10K_STATE_RESTARTING &&  	    ar->state != ATH10K_STATE_UTF)  		ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); -	ath10k_debug_stop(ar);  	ath10k_hif_stop(ar);  	ath10k_htt_tx_free(&ar->htt);  	ath10k_htt_rx_free(&ar->htt); @@ -1330,6 +1485,13 @@ static int ath10k_core_probe_fw(struct ath10k *ar)  		goto err_free_firmware_files;  	} +	ret = ath10k_swap_code_seg_init(ar); +	if (ret) { +		ath10k_err(ar, "failed to initialize code swap segment: %d\n", +			   ret); +		goto err_free_firmware_files; +	} +  	mutex_lock(&ar->conf_mutex);  	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); @@ -1470,9 +1632,15 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,  	switch (hw_rev) {  	case ATH10K_HW_QCA988X:  		ar->regs = &qca988x_regs; +		ar->hw_values = &qca988x_values;  		break;  	case ATH10K_HW_QCA6174:  		ar->regs = &qca6174_regs; +		ar->hw_values = &qca6174_values; +		break; +	case ATH10K_HW_QCA99X0: +		ar->regs = &qca99x0_regs; +		ar->hw_values = &qca99x0_values;  		break;  	default:  		ath10k_err(ar, "unsupported core hardware revision %d\n", @@ -1497,6 +1665,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,  	if (!ar->workqueue)  		goto err_free_mac; +	ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq"); +	if (!ar->workqueue_aux) +		goto err_free_wq; +  	mutex_init(&ar->conf_mutex);  	spin_lock_init(&ar->data_lock); @@ -1517,10 +1689,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,  	ret = ath10k_debug_create(ar);  	if (ret) -		goto err_free_wq; +		goto err_free_aux_wq;  	return ar; +err_free_aux_wq: +	destroy_workqueue(ar->workqueue_aux);  err_free_wq:  	destroy_workqueue(ar->workqueue); @@ -1536,6 +1710,9 @@ void ath10k_core_destroy(struct ath10k *ar)  	flush_workqueue(ar->workqueue);  	destroy_workqueue(ar->workqueue); +	flush_workqueue(ar->workqueue_aux); +	destroy_workqueue(ar->workqueue_aux); +  	ath10k_debug_destroy(ar);  	ath10k_mac_destroy(ar);  } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78094f23c9dd..12542144fe12 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -36,6 +36,7 @@  #include "spectral.h"  #include "thermal.h"  #include "wow.h" +#include "swap.h"  #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)  #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -91,6 +92,7 @@ struct ath10k_skb_cb {  		u8 tid;  		u16 freq;  		bool is_offchan; +		bool nohwcrypt;  		struct ath10k_htt_txbuf *txbuf;  		u32 txbuf_paddr;  	} __packed htt; @@ -151,6 +153,7 @@ struct ath10k_wmi {  	const struct wmi_ops *ops;  	u32 num_mem_chunks; +	u32 rx_decap_mode;  	struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];  }; @@ -327,8 +330,8 @@ struct ath10k_vif {  			u32 uapsd;  		} sta;  		struct { -			/* 127 stations; wmi limit */ -			u8 tim_bitmap[16]; +			/* 512 stations */ +			u8 tim_bitmap[64];  			u8 tim_len;  			u32 ssid_len;  			u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -340,6 +343,7 @@ struct ath10k_vif {  	} u;  	bool use_cts_prot; +	bool nohwcrypt;  	int num_legacy_stations;  	int txpower;  	struct wmi_wmm_params_all_arg wmm_params; @@ -381,9 +385,6 @@ struct ath10k_debug {  	u32 reg_addr;  	u32 nf_cal_period; -	u8 htt_max_amsdu; -	u8 htt_max_ampdu; -  	struct ath10k_fw_crash_data *fw_crash_data;  }; @@ -452,16 +453,21 @@ enum ath10k_fw_features {  	ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6,  	/* Don't trust error code from otp.bin */ -	ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, +	ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7,  	/* Some firmware revisions pad 4th hw address to 4 byte boundary making  	 * it 8 bytes long in Native Wifi Rx decap.  	 */ -	ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, +	ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8,  	/* Firmware supports bypassing PLL setting on init. */  	ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, +	/* Raw mode support. If supported, FW supports receiving and trasmitting +	 * frames in raw mode. +	 */ +	ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10, +  	/* keep last */  	ATH10K_FW_FEATURE_COUNT,  }; @@ -475,6 +481,15 @@ enum ath10k_dev_flags {  	 * waiters should immediately cancel instead of waiting for a time out.  	 */  	ATH10K_FLAG_CRASH_FLUSH, + +	/* Use Raw mode instead of native WiFi Tx/Rx encap mode. +	 * Raw mode supports both hardware and software crypto. Native WiFi only +	 * supports hardware crypto. +	 */ +	ATH10K_FLAG_RAW_MODE, + +	/* Disable HW crypto engine */ +	ATH10K_FLAG_HW_CRYPTO_DISABLED,  };  enum ath10k_cal_mode { @@ -483,6 +498,13 @@ enum ath10k_cal_mode {  	ATH10K_CAL_MODE_DT,  }; +enum ath10k_crypt_mode { +	/* Only use hardware crypto engine */ +	ATH10K_CRYPT_MODE_HW, +	/* Only use software crypto engine */ +	ATH10K_CRYPT_MODE_SW, +}; +  static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)  {  	switch (mode) { @@ -532,6 +554,7 @@ struct ath10k {  	u8 mac_addr[ETH_ALEN];  	enum ath10k_hw_rev hw_rev; +	u16 dev_id;  	u32 chip_id;  	u32 target_version;  	u8 fw_version_major; @@ -545,6 +568,7 @@ struct ath10k {  	u32 ht_cap_info;  	u32 vht_cap_info;  	u32 num_rf_chains; +	u32 max_spatial_stream;  	/* protected by conf_mutex */  	bool ani_enabled; @@ -560,6 +584,7 @@ struct ath10k {  	struct completion target_suspend;  	const struct ath10k_hw_regs *regs; +	const struct ath10k_hw_values *hw_values;  	struct ath10k_bmi bmi;  	struct ath10k_wmi wmi;  	struct ath10k_htc htc; @@ -570,6 +595,7 @@ struct ath10k {  		const char *name;  		u32 patch_load_addr;  		int uart_pin; +		u32 otp_exe_param;  		/* This is true if given HW chip has a quirky Cycle Counter  		 * wraparound which resets to 0x7fffffff instead of 0. All @@ -578,6 +604,14 @@ struct ath10k {  		 */  		bool has_shifted_cc_wraparound; +		/* Some of chip expects fragment descriptor to be continuous +		 * memory for any TX operation. Set continuous_frag_desc flag +		 * for the hardware which have such requirement. +		 */ +		bool continuous_frag_desc; + +		u32 channel_counters_freq_hz; +  		struct ath10k_hw_params_fw {  			const char *dir;  			const char *fw; @@ -602,6 +636,12 @@ struct ath10k {  	const struct firmware *cal_file; +	struct { +		const void *firmware_codeswap_data; +		size_t firmware_codeswap_len; +		struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; +	} swap; +  	char spec_board_id[100];  	bool spec_board_loaded; @@ -617,6 +657,7 @@ struct ath10k {  		bool is_roc;  		int vdev_id;  		int roc_freq; +		bool roc_notify;  	} scan;  	struct { @@ -656,6 +697,8 @@ struct ath10k {  	struct completion vdev_setup_done;  	struct workqueue_struct *workqueue; +	/* Auxiliary workqueue */ +	struct workqueue_struct *workqueue_aux;  	/* prevents concurrent FW reconfiguration */  	struct mutex conf_mutex; @@ -675,6 +718,11 @@ struct ath10k {  	int max_num_stations;  	int max_num_vdevs;  	int max_num_tdls_vdevs; +	int num_active_peers; +	int num_tids; + +	struct work_struct svc_rdy_work; +	struct sk_buff *svc_rdy_skb;  	struct work_struct offchan_tx_work;  	struct sk_buff_head offchan_tx_queue; @@ -749,6 +797,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,  				  enum ath10k_hw_rev hw_rev,  				  const struct ath10k_hif_ops *hif_ops);  void ath10k_core_destroy(struct ath10k *ar); +void ath10k_core_get_fw_features_str(struct ath10k *ar, +				     char *buf, +				     size_t max_len);  int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode);  int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8fa606a9c4dd..bf033f46f8aa 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,11 @@ EXPORT_SYMBOL(ath10k_info);  void ath10k_print_driver_info(struct ath10k *ar)  { -	ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", +	char fw_features[128] = {}; + +	ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); + +	ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n",  		    ar->hw_params.name,  		    ar->target_version,  		    ar->chip_id, @@ -137,8 +141,12 @@ void ath10k_print_driver_info(struct ath10k *ar)  		    ar->htt.target_version_major,  		    ar->htt.target_version_minor,  		    ar->wmi.op_version, +		    ar->htt.op_version,  		    ath10k_cal_mode_str(ar->cal_mode), -		    ar->max_num_stations); +		    ar->max_num_stations, +		    test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), +		    !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags), +		    fw_features);  	ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",  		    config_enabled(CONFIG_ATH10K_DEBUG),  		    config_enabled(CONFIG_ATH10K_DEBUGFS), @@ -315,7 +323,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)  	ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);  	if (ret) {  		ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); -		goto unlock; +		goto free;  	}  	/* Stat data may exceed htc-wmi buffer limit. In such case firmware @@ -378,7 +386,6 @@ free:  	ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);  	ath10k_debug_fw_stats_peers_free(&stats.peers); -unlock:  	spin_unlock_bh(&ar->data_lock);  } @@ -1357,12 +1364,8 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,  	mutex_lock(&ar->conf_mutex); -	if (ar->debug.htt_max_amsdu) -		amsdu = ar->debug.htt_max_amsdu; - -	if (ar->debug.htt_max_ampdu) -		ampdu = ar->debug.htt_max_ampdu; - +	amsdu = ar->htt.max_num_amsdu; +	ampdu = ar->htt.max_num_ampdu;  	mutex_unlock(&ar->conf_mutex);  	len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); @@ -1396,8 +1399,8 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,  		goto out;  	res = count; -	ar->debug.htt_max_amsdu = amsdu; -	ar->debug.htt_max_ampdu = ampdu; +	ar->htt.max_num_amsdu = amsdu; +	ar->htt.max_num_ampdu = ampdu;  out:  	mutex_unlock(&ar->conf_mutex); @@ -1899,9 +1902,6 @@ void ath10k_debug_stop(struct ath10k *ar)  	if (ar->debug.htt_stats_mask != 0)  		cancel_delayed_work(&ar->debug.htt_stats_dwork); -	ar->debug.htt_max_amsdu = 0; -	ar->debug.htt_max_ampdu = 0; -  	ath10k_wmi_pdev_pktlog_disable(ar);  } diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 85bfa2acb801..32d9ff1b19dc 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -145,8 +145,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,  	skb_cb->eid = eid;  	skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);  	ret = dma_mapping_error(dev, skb_cb->paddr); -	if (ret) +	if (ret) { +		ret = -EIO;  		goto err_credits; +	}  	sg_item.transfer_id = ep->eid;  	sg_item.transfer_context = skb; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6da6ef26143a..3e6ba63dfdff 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -102,6 +102,43 @@ static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = {  	[HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,  }; +static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { +	[HTT_10_4_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF, +	[HTT_10_4_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND, +	[HTT_10_4_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH, +	[HTT_10_4_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP, +	[HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP, +	[HTT_10_4_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA, +	[HTT_10_4_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA, +	[HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND, +	[HTT_10_4_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG, +	[HTT_10_4_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF, +	[HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND, +	[HTT_10_4_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND, +	[HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND, +	[HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND] = +				HTT_T2H_MSG_TYPE_TX_INSPECT_IND, +	[HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] = +				HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION, +	[HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE, +	[HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] = +				HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND, +	[HTT_10_4_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND, +	[HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] = +				HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND, +	[HTT_10_4_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, +	[HTT_10_4_T2H_MSG_TYPE_EN_STATS] = HTT_T2H_MSG_TYPE_EN_STATS, +	[HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF, +	[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] = +				HTT_T2H_MSG_TYPE_TX_FETCH_IND, +	[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] = +				HTT_T2H_MSG_TYPE_TX_FETCH_CONF, +	[HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] = +				HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, +	[HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] = +				HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, +}; +  int ath10k_htt_connect(struct ath10k_htt *htt)  {  	struct ath10k_htc_svc_conn_req conn_req; @@ -147,6 +184,10 @@ int ath10k_htt_init(struct ath10k *ar)  		2; /* ip4 dscp or ip6 priority */  	switch (ar->htt.op_version) { +	case ATH10K_FW_HTT_OP_VERSION_10_4: +		ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types; +		ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS; +		break;  	case ATH10K_FW_HTT_OP_VERSION_10_1:  		ar->htt.t2h_msg_types = htt_10x_t2h_msg_types;  		ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS; @@ -205,8 +246,31 @@ int ath10k_htt_setup(struct ath10k_htt *htt)  	}  	status = ath10k_htt_verify_version(htt); +	if (status) { +		ath10k_warn(ar, "failed to verify htt version: %d\n", +			    status); +		return status; +	} + +	status = ath10k_htt_send_frag_desc_bank_cfg(htt);  	if (status)  		return status; -	return ath10k_htt_send_rx_ring_cfg_ll(htt); +	status = ath10k_htt_send_rx_ring_cfg_ll(htt); +	if (status) { +		ath10k_warn(ar, "failed to setup rx ring: %d\n", +			    status); +		return status; +	} + +	status = ath10k_htt_h2t_aggr_cfg_msg(htt, +					     htt->max_num_ampdu, +					     htt->max_num_amsdu); +	if (status) { +		ath10k_warn(ar, "failed to setup amsdu/ampdu limit: %d\n", +			    status); +		return status; +	} + +	return 0;  } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7e8a0d835663..573187512895 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -83,10 +83,39 @@ struct htt_ver_req {   * around the mask + shift defs.   */  struct htt_data_tx_desc_frag { -	__le32 paddr; -	__le32 len; +	union { +		struct double_word_addr { +			__le32 paddr; +			__le32 len; +		} __packed dword_addr; +		struct triple_word_addr { +			__le32 paddr_lo; +			__le16 paddr_hi; +			__le16 len_16; +		} __packed tword_addr; +	} __packed;  } __packed; +struct htt_msdu_ext_desc { +	__le32 tso_flag[3]; +	__le16 ip_identification; +	u8 flags; +	u8 reserved; +	struct htt_data_tx_desc_frag frags[6]; +}; + +#define	HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE		BIT(0) +#define	HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE	BIT(1) +#define	HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE	BIT(2) +#define	HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE	BIT(3) +#define	HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE	BIT(4) + +#define HTT_MSDU_CHECKSUM_ENABLE (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE \ +				 | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE \ +				 | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE \ +				 | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ +				 | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) +  enum htt_data_tx_desc_flags0 {  	HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0,  	HTT_DATA_TX_DESC_FLAGS0_NO_AGGR         = 1 << 1, @@ -255,6 +284,9 @@ struct htt_aggr_conf {  } __packed;  #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +struct htt_mgmt_tx_desc_qca99x0 { +	__le32 rate; +} __packed;  struct htt_mgmt_tx_desc {  	u8 pad[sizeof(u32) - sizeof(struct htt_cmd_hdr)]; @@ -263,6 +295,9 @@ struct htt_mgmt_tx_desc {  	__le32 len;  	__le32 vdev_id;  	u8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; +	union { +		struct htt_mgmt_tx_desc_qca99x0 qca99x0; +	} __packed;  } __packed;  enum htt_mgmt_tx_status { @@ -349,6 +384,38 @@ enum htt_tlv_t2h_msg_type {  	HTT_TLV_T2H_NUM_MSGS  }; +enum htt_10_4_t2h_msg_type { +	HTT_10_4_T2H_MSG_TYPE_VERSION_CONF           = 0x0, +	HTT_10_4_T2H_MSG_TYPE_RX_IND                 = 0x1, +	HTT_10_4_T2H_MSG_TYPE_RX_FLUSH               = 0x2, +	HTT_10_4_T2H_MSG_TYPE_PEER_MAP               = 0x3, +	HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP             = 0x4, +	HTT_10_4_T2H_MSG_TYPE_RX_ADDBA               = 0x5, +	HTT_10_4_T2H_MSG_TYPE_RX_DELBA               = 0x6, +	HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND           = 0x7, +	HTT_10_4_T2H_MSG_TYPE_PKTLOG                 = 0x8, +	HTT_10_4_T2H_MSG_TYPE_STATS_CONF             = 0x9, +	HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND            = 0xa, +	HTT_10_4_T2H_MSG_TYPE_SEC_IND                = 0xb, +	HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND          = 0xc, +	HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND         = 0xd, +	HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND      = 0xe, +	HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE            = 0xf, +	HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND   = 0x10, +	HTT_10_4_T2H_MSG_TYPE_RX_PN_IND              = 0x11, +	HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x12, +	HTT_10_4_T2H_MSG_TYPE_TEST                   = 0x13, +	HTT_10_4_T2H_MSG_TYPE_EN_STATS               = 0x14, +	HTT_10_4_T2H_MSG_TYPE_AGGR_CONF              = 0x15, +	HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND           = 0x16, +	HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF          = 0x17, +	HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD         = 0x18, +	/* 0x19 to 0x2f are reserved */ +	HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND     = 0x30, +	/* keep this last */ +	HTT_10_4_T2H_NUM_MSGS +}; +  enum htt_t2h_msg_type {  	HTT_T2H_MSG_TYPE_VERSION_CONF,  	HTT_T2H_MSG_TYPE_RX_IND, @@ -375,6 +442,10 @@ enum htt_t2h_msg_type {  	HTT_T2H_MSG_TYPE_AGGR_CONF,  	HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,  	HTT_T2H_MSG_TYPE_TEST, +	HTT_T2H_MSG_TYPE_EN_STATS, +	HTT_T2H_MSG_TYPE_TX_FETCH_IND, +	HTT_T2H_MSG_TYPE_TX_FETCH_CONF, +	HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,  	/* keep this last */  	HTT_T2H_NUM_MSGS  }; @@ -1325,6 +1396,8 @@ struct ath10k_htt {  	u8 target_version_minor;  	struct completion target_version_received;  	enum ath10k_fw_htt_op_version op_version; +	u8 max_num_amsdu; +	u8 max_num_ampdu;  	const enum htt_t2h_msg_type *t2h_msg_types;  	u32 t2h_msg_types_max; @@ -1430,6 +1503,11 @@ struct ath10k_htt {  	/* rx_status template */  	struct ieee80211_rx_status rx_status; + +	struct { +		dma_addr_t paddr; +		struct htt_msdu_ext_desc *vaddr; +	} frag_desc;  };  #define RX_HTT_HDR_STATUS_LEN 64 @@ -1482,6 +1560,12 @@ struct htt_rx_desc {  #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7	/* 2^7 = 128 */  #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) +/* These values are default in most firmware revisions and apparently are a + * sweet spot performance wise. + */ +#define ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT 3 +#define ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT 64 +  int ath10k_htt_connect(struct ath10k_htt *htt);  int ath10k_htt_init(struct ath10k *ar);  int ath10k_htt_setup(struct ath10k_htt *htt); @@ -1497,6 +1581,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);  void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);  int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);  int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt);  int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);  int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,  				u8 max_subfrms_ampdu, diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 89eb16b30fc4..1b7a04366256 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -368,7 +368,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  		msdu_len_invalid = !!(__le32_to_cpu(rx_desc->attention.flags)  					& (RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR |  					   RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR)); -		msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), +		msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.common.info0),  			      RX_MSDU_START_INFO0_MSDU_LENGTH);  		msdu_chained = rx_desc->frag_info.ring2_more_count; @@ -394,7 +394,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  			msdu_chaining = 1;  		} -		last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & +		last_msdu = __le32_to_cpu(rx_desc->msdu_end.common.info0) &  				RX_MSDU_END_INFO0_LAST_MSDU;  		trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, @@ -740,7 +740,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)  	    __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID))  		return NULL; -	if (!(rxd->msdu_end.info0 & +	if (!(rxd->msdu_end.common.info0 &  	      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)))  		return NULL; @@ -991,9 +991,9 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,  	bool is_last;  	rxd = (void *)msdu->data - sizeof(*rxd); -	is_first = !!(rxd->msdu_end.info0 & +	is_first = !!(rxd->msdu_end.common.info0 &  		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); -	is_last = !!(rxd->msdu_end.info0 & +	is_last = !!(rxd->msdu_end.common.info0 &  		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));  	/* Delivered decapped frame: @@ -1017,9 +1017,8 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,  	skb_trim(msdu, msdu->len - FCS_LEN);  	/* In most cases this will be true for sniffed frames. It makes sense -	 * to deliver them as-is without stripping the crypto param. This would -	 * also make sense for software based decryption (which is not -	 * implemented in ath10k). +	 * to deliver them as-is without stripping the crypto param. This is +	 * necessary for software based decryption.  	 *  	 * If there's no error then the frame is decrypted. At least that is  	 * the case for frames that come in via fragmented rx indication. @@ -1104,9 +1103,9 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar,  	rxd = (void *)msdu->data - sizeof(*rxd);  	hdr = (void *)rxd->rx_hdr_status; -	is_first = !!(rxd->msdu_end.info0 & +	is_first = !!(rxd->msdu_end.common.info0 &  		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); -	is_last = !!(rxd->msdu_end.info0 & +	is_last = !!(rxd->msdu_end.common.info0 &  		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));  	is_amsdu = !(is_first && is_last); @@ -1201,7 +1200,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar,  {  	struct htt_rx_desc *rxd;  	enum rx_msdu_decap_format decap; -	struct ieee80211_hdr *hdr;  	/* First msdu's decapped header:  	 * [802.11 header] <-- padded to 4 bytes long @@ -1215,8 +1213,7 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar,  	 */  	rxd = (void *)msdu->data - sizeof(*rxd); -	hdr = (void *)rxd->rx_hdr_status; -	decap = MS(__le32_to_cpu(rxd->msdu_start.info1), +	decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1),  		   RX_MSDU_START_INFO1_DECAP_FORMAT);  	switch (decap) { @@ -1246,7 +1243,7 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)  	rxd = (void *)skb->data - sizeof(*rxd);  	flags = __le32_to_cpu(rxd->attention.flags); -	info = __le32_to_cpu(rxd->msdu_start.info1); +	info = __le32_to_cpu(rxd->msdu_start.common.info1);  	is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO);  	is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO); @@ -1439,7 +1436,7 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar,  	first = skb_peek(amsdu);  	rxd = (void *)first->data - sizeof(*rxd); -	decap = MS(__le32_to_cpu(rxd->msdu_start.info1), +	decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1),  		   RX_MSDU_START_INFO1_DECAP_FORMAT);  	if (!chained) @@ -1633,8 +1630,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,  	__le16 msdu_id;  	int i; -	lockdep_assert_held(&htt->tx_lock); -  	switch (status) {  	case HTT_DATA_TX_STATUS_NO_ACK:  		tx_done.no_ack = true; @@ -1759,14 +1754,14 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,  		__skb_queue_tail(amsdu, msdu);  		rxd = (void *)msdu->data - sizeof(*rxd); -		if (rxd->msdu_end.info0 & +		if (rxd->msdu_end.common.info0 &  		    __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))  			break;  	}  	msdu = skb_peek_tail(amsdu);  	rxd = (void *)msdu->data - sizeof(*rxd); -	if (!(rxd->msdu_end.info0 & +	if (!(rxd->msdu_end.common.info0 &  	      __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) {  		skb_queue_splice_init(amsdu, list);  		return -EAGAIN; @@ -2000,15 +1995,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  			break;  		} -		spin_lock_bh(&htt->tx_lock);  		ath10k_txrx_tx_unref(htt, &tx_done); -		spin_unlock_bh(&htt->tx_lock);  		break;  	}  	case HTT_T2H_MSG_TYPE_TX_COMPL_IND: -		spin_lock_bh(&htt->tx_lock); -		__skb_queue_tail(&htt->tx_compl_q, skb); -		spin_unlock_bh(&htt->tx_lock); +		skb_queue_tail(&htt->tx_compl_q, skb);  		tasklet_schedule(&htt->txrx_compl_task);  		return;  	case HTT_T2H_MSG_TYPE_SEC_IND: { @@ -2074,6 +2065,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  		break;  	case HTT_T2H_MSG_TYPE_CHAN_CHANGE:  		break; +	case HTT_T2H_MSG_TYPE_AGGR_CONF: +		break; +	case HTT_T2H_MSG_TYPE_EN_STATS: +	case HTT_T2H_MSG_TYPE_TX_FETCH_IND: +	case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: +	case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND:  	default:  		ath10k_warn(ar, "htt event (%d) not handled\n",  			    resp->hdr.msg_type); @@ -2093,12 +2090,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)  	struct htt_resp *resp;  	struct sk_buff *skb; -	spin_lock_bh(&htt->tx_lock); -	while ((skb = __skb_dequeue(&htt->tx_compl_q))) { +	while ((skb = skb_dequeue(&htt->tx_compl_q))) {  		ath10k_htt_rx_frm_tx_compl(htt->ar, skb);  		dev_kfree_skb_any(skb);  	} -	spin_unlock_bh(&htt->tx_lock);  	spin_lock_bh(&htt->rx_ring.lock);  	while ((skb = __skb_dequeue(&htt->rx_compl_q))) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a60ef7d1d5fc..43aa5e2d1b87 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -63,7 +63,8 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)  	lockdep_assert_held(&htt->tx_lock); -	ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); +	ret = idr_alloc(&htt->pending_tx, skb, 0, +			htt->max_num_pending_tx, GFP_ATOMIC);  	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); @@ -84,6 +85,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)  int ath10k_htt_tx_alloc(struct ath10k_htt *htt)  {  	struct ath10k *ar = htt->ar; +	int ret, size;  	ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",  		   htt->max_num_pending_tx); @@ -94,11 +96,31 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)  	htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev,  				       sizeof(struct ath10k_htt_txbuf), 4, 0);  	if (!htt->tx_pool) { -		idr_destroy(&htt->pending_tx); -		return -ENOMEM; +		ret = -ENOMEM; +		goto free_idr_pending_tx; +	} + +	if (!ar->hw_params.continuous_frag_desc) +		goto skip_frag_desc_alloc; + +	size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); +	htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, +						  &htt->frag_desc.paddr, +						  GFP_DMA); +	if (!htt->frag_desc.vaddr) { +		ath10k_warn(ar, "failed to alloc fragment desc memory\n"); +		ret = -ENOMEM; +		goto free_tx_pool;  	} +skip_frag_desc_alloc:  	return 0; + +free_tx_pool: +	dma_pool_destroy(htt->tx_pool); +free_idr_pending_tx: +	idr_destroy(&htt->pending_tx); +	return ret;  }  static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) @@ -112,18 +134,25 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)  	tx_done.discard = 1;  	tx_done.msdu_id = msdu_id; -	spin_lock_bh(&htt->tx_lock);  	ath10k_txrx_tx_unref(htt, &tx_done); -	spin_unlock_bh(&htt->tx_lock);  	return 0;  }  void ath10k_htt_tx_free(struct ath10k_htt *htt)  { +	int size; +  	idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);  	idr_destroy(&htt->pending_tx);  	dma_pool_destroy(htt->tx_pool); + +	if (htt->frag_desc.vaddr) { +		size = htt->max_num_pending_tx * +				  sizeof(struct htt_msdu_ext_desc); +		dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr, +				  htt->frag_desc.paddr); +	}  }  void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) @@ -201,6 +230,49 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)  	return 0;  } +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) +{ +	struct ath10k *ar = htt->ar; +	struct sk_buff *skb; +	struct htt_cmd *cmd; +	int ret, size; + +	if (!ar->hw_params.continuous_frag_desc) +		return 0; + +	if (!htt->frag_desc.paddr) { +		ath10k_warn(ar, "invalid frag desc memory\n"); +		return -EINVAL; +	} + +	size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg); +	skb = ath10k_htc_alloc_skb(ar, size); +	if (!skb) +		return -ENOMEM; + +	skb_put(skb, size); +	cmd = (struct htt_cmd *)skb->data; +	cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; +	cmd->frag_desc_bank_cfg.info = 0; +	cmd->frag_desc_bank_cfg.num_banks = 1; +	cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); +	cmd->frag_desc_bank_cfg.bank_base_addrs[0] = +				__cpu_to_le32(htt->frag_desc.paddr); +	cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0; +	cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = +				__cpu_to_le16(htt->max_num_pending_tx - 1); + +	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); +	if (ret) { +		ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", +			    ret); +		dev_kfree_skb_any(skb); +		return ret; +	} + +	return 0; +} +  int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)  {  	struct ath10k *ar = htt->ar; @@ -355,12 +427,11 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	spin_lock_bh(&htt->tx_lock);  	res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); +	spin_unlock_bh(&htt->tx_lock);  	if (res < 0) { -		spin_unlock_bh(&htt->tx_lock);  		goto err_tx_dec;  	}  	msdu_id = res; -	spin_unlock_bh(&htt->tx_lock);  	txdesc = ath10k_htc_alloc_skb(ar, len);  	if (!txdesc) { @@ -371,11 +442,15 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,  				       DMA_TO_DEVICE);  	res = dma_mapping_error(dev, skb_cb->paddr); -	if (res) +	if (res) { +		res = -EIO;  		goto err_free_txdesc; +	}  	skb_put(txdesc, len);  	cmd = (struct htt_cmd *)txdesc->data; +	memset(cmd, 0, len); +  	cmd->hdr.msg_type         = HTT_H2T_MSG_TYPE_MGMT_TX;  	cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);  	cmd->mgmt_tx.len        = __cpu_to_le32(msdu->len); @@ -422,6 +497,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	u16 msdu_id, flags1 = 0;  	dma_addr_t paddr = 0;  	u32 frags_paddr = 0; +	struct htt_msdu_ext_desc *ext_desc = NULL;  	res = ath10k_htt_tx_inc_pending(htt);  	if (res) @@ -429,12 +505,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	spin_lock_bh(&htt->tx_lock);  	res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); +	spin_unlock_bh(&htt->tx_lock);  	if (res < 0) { -		spin_unlock_bh(&htt->tx_lock);  		goto err_tx_dec;  	}  	msdu_id = res; -	spin_unlock_bh(&htt->tx_lock);  	prefetch_len = min(htt->prefetch_len, msdu->len);  	prefetch_len = roundup(prefetch_len, 4); @@ -450,14 +525,20 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	if ((ieee80211_is_action(hdr->frame_control) ||  	     ieee80211_is_deauth(hdr->frame_control) ||  	     ieee80211_is_disassoc(hdr->frame_control)) && -	     ieee80211_has_protected(hdr->frame_control)) +	     ieee80211_has_protected(hdr->frame_control)) {  		skb_put(msdu, IEEE80211_CCMP_MIC_LEN); +	} else if (!skb_cb->htt.nohwcrypt && +		   skb_cb->txmode == ATH10K_HW_TXRX_RAW) { +		skb_put(msdu, IEEE80211_CCMP_MIC_LEN); +	}  	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,  				       DMA_TO_DEVICE);  	res = dma_mapping_error(dev, skb_cb->paddr); -	if (res) +	if (res) { +		res = -EIO;  		goto err_free_txbuf; +	}  	switch (skb_cb->txmode) {  	case ATH10K_HW_TXRX_RAW: @@ -465,16 +546,30 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  		flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;  		/* pass through */  	case ATH10K_HW_TXRX_ETHERNET: -		frags = skb_cb->htt.txbuf->frags; - -		frags[0].paddr = __cpu_to_le32(skb_cb->paddr); -		frags[0].len = __cpu_to_le32(msdu->len); -		frags[1].paddr = 0; -		frags[1].len = 0; - +		if (ar->hw_params.continuous_frag_desc) { +			memset(&htt->frag_desc.vaddr[msdu_id], 0, +			       sizeof(struct htt_msdu_ext_desc)); +			frags = (struct htt_data_tx_desc_frag *) +				&htt->frag_desc.vaddr[msdu_id].frags; +			ext_desc = &htt->frag_desc.vaddr[msdu_id]; +			frags[0].tword_addr.paddr_lo = +				__cpu_to_le32(skb_cb->paddr); +			frags[0].tword_addr.paddr_hi = 0; +			frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); + +			frags_paddr =  htt->frag_desc.paddr + +				(sizeof(struct htt_msdu_ext_desc) * msdu_id); +		} else { +			frags = skb_cb->htt.txbuf->frags; +			frags[0].dword_addr.paddr = +				__cpu_to_le32(skb_cb->paddr); +			frags[0].dword_addr.len = __cpu_to_le32(msdu->len); +			frags[1].dword_addr.paddr = 0; +			frags[1].dword_addr.len = 0; + +			frags_paddr = skb_cb->htt.txbuf_paddr; +		}  		flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - -		frags_paddr = skb_cb->htt.txbuf_paddr;  		break;  	case ATH10K_HW_TXRX_MGMT:  		flags0 |= SM(ATH10K_HW_TXRX_MGMT, @@ -508,14 +603,20 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  			prefetch_len);  	skb_cb->htt.txbuf->htc_hdr.flags = 0; +	if (skb_cb->htt.nohwcrypt) +		flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; +  	if (!skb_cb->is_protected)  		flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;  	flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);  	flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); -	if (msdu->ip_summed == CHECKSUM_PARTIAL) { +	if (msdu->ip_summed == CHECKSUM_PARTIAL && +	    !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {  		flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;  		flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; +		if (ar->hw_params.continuous_frag_desc) +			ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE;  	}  	/* Prevent firmware from sending up tx inspection requests. There's diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 5997f00afe3b..7b84d08a5154 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -34,8 +34,15 @@ const struct ath10k_hw_regs qca988x_regs = {  	.ce7_base_address		= 0x00059000,  	.soc_reset_control_si0_rst_mask	= 0x00000001,  	.soc_reset_control_ce_rst_mask	= 0x00040000, -	.soc_chip_id_address		= 0x00ec, -	.scratch_3_address		= 0x0030, +	.soc_chip_id_address		= 0x000000ec, +	.scratch_3_address		= 0x00000030, +	.fw_indicator_address		= 0x00009030, +	.pcie_local_base_address	= 0x00080000, +	.ce_wrap_intr_sum_host_msi_lsb	= 0x00000008, +	.ce_wrap_intr_sum_host_msi_mask	= 0x0000ff00, +	.pcie_intr_fw_mask		= 0x00000400, +	.pcie_intr_ce_mask_all		= 0x0007f800, +	.pcie_intr_clr_address		= 0x00000014,  };  const struct ath10k_hw_regs qca6174_regs = { @@ -54,8 +61,79 @@ const struct ath10k_hw_regs qca6174_regs = {  	.ce7_base_address			= 0x00036000,  	.soc_reset_control_si0_rst_mask		= 0x00000000,  	.soc_reset_control_ce_rst_mask		= 0x00000001, -	.soc_chip_id_address			= 0x000f0, -	.scratch_3_address			= 0x0028, +	.soc_chip_id_address			= 0x000000f0, +	.scratch_3_address			= 0x00000028, +	.fw_indicator_address			= 0x0003a028, +	.pcie_local_base_address		= 0x00080000, +	.ce_wrap_intr_sum_host_msi_lsb		= 0x00000008, +	.ce_wrap_intr_sum_host_msi_mask		= 0x0000ff00, +	.pcie_intr_fw_mask			= 0x00000400, +	.pcie_intr_ce_mask_all			= 0x0007f800, +	.pcie_intr_clr_address			= 0x00000014, +}; + +const struct ath10k_hw_regs qca99x0_regs = { +	.rtc_state_cold_reset_mask		= 0x00000400, +	.rtc_soc_base_address			= 0x00080000, +	.rtc_wmac_base_address			= 0x00000000, +	.soc_core_base_address			= 0x00082000, +	.ce_wrapper_base_address		= 0x0004d000, +	.ce0_base_address			= 0x0004a000, +	.ce1_base_address			= 0x0004a400, +	.ce2_base_address			= 0x0004a800, +	.ce3_base_address			= 0x0004ac00, +	.ce4_base_address			= 0x0004b000, +	.ce5_base_address			= 0x0004b400, +	.ce6_base_address			= 0x0004b800, +	.ce7_base_address			= 0x0004bc00, +	/* Note: qca99x0 supports upto 12 Copy Engines. Other than address of +	 * CE0 and CE1 no other copy engine is directly referred in the code. +	 * It is not really neccessary to assign address for newly supported +	 * CEs in this address table. +	 *	Copy Engine		Address +	 *	CE8			0x0004c000 +	 *	CE9			0x0004c400 +	 *	CE10			0x0004c800 +	 *	CE11			0x0004cc00 +	 */ +	.soc_reset_control_si0_rst_mask		= 0x00000001, +	.soc_reset_control_ce_rst_mask		= 0x00000100, +	.soc_chip_id_address			= 0x000000ec, +	.scratch_3_address			= 0x00040050, +	.fw_indicator_address			= 0x00040050, +	.pcie_local_base_address		= 0x00000000, +	.ce_wrap_intr_sum_host_msi_lsb		= 0x0000000c, +	.ce_wrap_intr_sum_host_msi_mask		= 0x00fff000, +	.pcie_intr_fw_mask			= 0x00100000, +	.pcie_intr_ce_mask_all			= 0x000fff00, +	.pcie_intr_clr_address			= 0x00000010, +}; + +const struct ath10k_hw_values qca988x_values = { +	.rtc_state_val_on		= 3, +	.ce_count			= 8, +	.msi_assign_ce_max		= 7, +	.num_target_ce_config_wlan	= 7, +	.ce_desc_meta_data_mask		= 0xFFFC, +	.ce_desc_meta_data_lsb		= 2, +}; + +const struct ath10k_hw_values qca6174_values = { +	.rtc_state_val_on		= 3, +	.ce_count			= 8, +	.msi_assign_ce_max		= 7, +	.num_target_ce_config_wlan	= 7, +	.ce_desc_meta_data_mask		= 0xFFFC, +	.ce_desc_meta_data_lsb		= 2, +}; + +const struct ath10k_hw_values qca99x0_values = { +	.rtc_state_val_on		= 5, +	.ce_count			= 12, +	.msi_assign_ce_max		= 12, +	.num_target_ce_config_wlan	= 10, +	.ce_desc_meta_data_mask		= 0xFFF0, +	.ce_desc_meta_data_lsb		= 4,  };  void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, @@ -74,6 +152,6 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,  	cc -= cc_prev - cc_fix;  	rcc -= rcc_prev; -	survey->time = CCNT_TO_MSEC(cc); -	survey->time_busy = CCNT_TO_MSEC(rcc); +	survey->time = CCNT_TO_MSEC(ar, cc); +	survey->time_busy = CCNT_TO_MSEC(ar, rcc);  } diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 85cca29375fe..23afcda2de96 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -72,6 +72,18 @@ enum qca6174_chip_id_rev {  #define QCA6174_HW_3_0_BOARD_DATA_FILE	"board.bin"  #define QCA6174_HW_3_0_PATCH_LOAD_ADDR	0x1234 +/* QCA99X0 1.0 definitions (unsupported) */ +#define QCA99X0_HW_1_0_CHIP_ID_REV     0x0 + +/* QCA99X0 2.0 definitions */ +#define QCA99X0_HW_2_0_DEV_VERSION     0x01000000 +#define QCA99X0_HW_2_0_CHIP_ID_REV     0x1 +#define QCA99X0_HW_2_0_FW_DIR          ATH10K_FW_DIR "/QCA99X0/hw2.0" +#define QCA99X0_HW_2_0_FW_FILE         "firmware.bin" +#define QCA99X0_HW_2_0_OTP_FILE        "otp.bin" +#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" +#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR	0x1234 +  #define ATH10K_FW_API2_FILE		"firmware-2.bin"  #define ATH10K_FW_API3_FILE		"firmware-3.bin" @@ -112,6 +124,9 @@ enum ath10k_fw_ie_type {  	 * FW API 5 and above.  	 */  	ATH10K_FW_IE_HTT_OP_VERSION = 6, + +	/* Code swap image for firmware binary */ +	ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7,  };  enum ath10k_fw_wmi_op_version { @@ -122,6 +137,7 @@ enum ath10k_fw_wmi_op_version {  	ATH10K_FW_WMI_OP_VERSION_10_2 = 3,  	ATH10K_FW_WMI_OP_VERSION_TLV = 4,  	ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, +	ATH10K_FW_WMI_OP_VERSION_10_4 = 6,  	/* keep last */  	ATH10K_FW_WMI_OP_VERSION_MAX, @@ -137,6 +153,8 @@ enum ath10k_fw_htt_op_version {  	ATH10K_FW_HTT_OP_VERSION_TLV = 3, +	ATH10K_FW_HTT_OP_VERSION_10_4 = 4, +  	/* keep last */  	ATH10K_FW_HTT_OP_VERSION_MAX,  }; @@ -144,6 +162,7 @@ enum ath10k_fw_htt_op_version {  enum ath10k_hw_rev {  	ATH10K_HW_QCA988X,  	ATH10K_HW_QCA6174, +	ATH10K_HW_QCA99X0,  };  struct ath10k_hw_regs { @@ -164,26 +183,50 @@ struct ath10k_hw_regs {  	u32 soc_reset_control_ce_rst_mask;  	u32 soc_chip_id_address;  	u32 scratch_3_address; +	u32 fw_indicator_address; +	u32 pcie_local_base_address; +	u32 ce_wrap_intr_sum_host_msi_lsb; +	u32 ce_wrap_intr_sum_host_msi_mask; +	u32 pcie_intr_fw_mask; +	u32 pcie_intr_ce_mask_all; +	u32 pcie_intr_clr_address;  };  extern const struct ath10k_hw_regs qca988x_regs;  extern const struct ath10k_hw_regs qca6174_regs; +extern const struct ath10k_hw_regs qca99x0_regs; + +struct ath10k_hw_values { +	u32 rtc_state_val_on; +	u8 ce_count; +	u8 msi_assign_ce_max; +	u8 num_target_ce_config_wlan; +	u16 ce_desc_meta_data_mask; +	u8 ce_desc_meta_data_lsb; +}; + +extern const struct ath10k_hw_values qca988x_values; +extern const struct ath10k_hw_values qca6174_values; +extern const struct ath10k_hw_values qca99x0_values;  void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,  				u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);  #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)  #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) +#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)  /* Known pecularities: - *  - current FW doesn't support raw rx mode (last tested v599) - *  - current FW dumps upon raw tx mode (last tested v599)   *  - raw appears in nwifi decap, raw and nwifi appear in ethernet decap   *  - raw have FCS, nwifi doesn't   *  - ethernet frames have 802.11 header decapped and parts (base hdr, cipher   *    param, llc/snap) are aligned to 4byte boundaries each */  enum ath10k_hw_txrx_mode {  	ATH10K_HW_TXRX_RAW = 0, + +	/* Native Wifi decap mode is used to align IP frames to 4-byte +	 * boundaries and avoid a very expensive re-alignment in mac80211. +	 */  	ATH10K_HW_TXRX_NATIVE_WIFI = 1,  	ATH10K_HW_TXRX_ETHERNET = 2, @@ -245,10 +288,6 @@ enum ath10k_hw_rate_cck {  #define TARGET_RX_TIMEOUT_LO_PRI		100  #define TARGET_RX_TIMEOUT_HI_PRI		40 -/* Native Wifi decap mode is used to align IP frames to 4-byte boundaries and - * avoid a very expensive re-alignment in mac80211. */ -#define TARGET_RX_DECAP_MODE			ATH10K_HW_TXRX_NATIVE_WIFI -  #define TARGET_SCAN_MAX_PENDING_REQS		4  #define TARGET_BMISS_OFFLOAD_MAX_VDEV		3  #define TARGET_ROAM_OFFLOAD_MAX_VDEV		3 @@ -283,7 +322,6 @@ enum ath10k_hw_rate_cck {  #define TARGET_10X_RX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2))  #define TARGET_10X_RX_TIMEOUT_LO_PRI		100  #define TARGET_10X_RX_TIMEOUT_HI_PRI		40 -#define TARGET_10X_RX_DECAP_MODE		ATH10K_HW_TXRX_NATIVE_WIFI  #define TARGET_10X_SCAN_MAX_PENDING_REQS	4  #define TARGET_10X_BMISS_OFFLOAD_MAX_VDEV	2  #define TARGET_10X_ROAM_OFFLOAD_MAX_VDEV	2 @@ -310,8 +348,70 @@ enum ath10k_hw_rate_cck {  #define TARGET_TLV_NUM_MSDU_DESC		(1024 + 32)  #define TARGET_TLV_NUM_WOW_PATTERNS		22 +/* Diagnostic Window */ +#define CE_DIAG_PIPE	7 + +#define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan + +/* Target specific defines for 10.4 firmware */ +#define TARGET_10_4_NUM_VDEVS			16 +#define TARGET_10_4_NUM_STATIONS		32 +#define TARGET_10_4_NUM_PEERS			((TARGET_10_4_NUM_STATIONS) + \ +						 (TARGET_10_4_NUM_VDEVS)) +#define TARGET_10_4_ACTIVE_PEERS		0 + +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX	512 +#define TARGET_10_4_QCACHE_ACTIVE_PEERS		50 +#define TARGET_10_4_NUM_OFFLOAD_PEERS		0 +#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS	0 +#define TARGET_10_4_NUM_PEER_KEYS		2 +#define TARGET_10_4_TGT_NUM_TIDS		((TARGET_10_4_NUM_PEERS) * 2) +#define TARGET_10_4_AST_SKID_LIMIT		32 +#define TARGET_10_4_TX_CHAIN_MASK		(BIT(0) | BIT(1) | \ +						 BIT(2) | BIT(3)) +#define TARGET_10_4_RX_CHAIN_MASK		(BIT(0) | BIT(1) | \ +						 BIT(2) | BIT(3)) + +/* 100 ms for video, best-effort, and background */ +#define TARGET_10_4_RX_TIMEOUT_LO_PRI		100 + +/* 40 ms for voice */ +#define TARGET_10_4_RX_TIMEOUT_HI_PRI		40 + +#define TARGET_10_4_RX_DECAP_MODE		ATH10K_HW_TXRX_NATIVE_WIFI +#define TARGET_10_4_SCAN_MAX_REQS		4 +#define TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV	3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV	3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES   8 + +/* Note: mcast to ucast is disabled by default */ +#define TARGET_10_4_NUM_MCAST_GROUPS		0 +#define TARGET_10_4_NUM_MCAST_TABLE_ELEMS	0 +#define TARGET_10_4_MCAST2UCAST_MODE		0 + +#define TARGET_10_4_TX_DBG_LOG_SIZE		1024 +#define TARGET_10_4_NUM_WDS_ENTRIES		32 +#define TARGET_10_4_DMA_BURST_SIZE		1 +#define TARGET_10_4_MAC_AGGR_DELIM		0 +#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 +#define TARGET_10_4_VOW_CONFIG			0 +#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV	3 +#define TARGET_10_4_NUM_MSDU_DESC		(1024 + 400) +#define TARGET_10_4_11AC_TX_MAX_FRAGS		2 +#define TARGET_10_4_MAX_PEER_EXT_STATS		16 +#define TARGET_10_4_SMART_ANT_CAP		0 +#define TARGET_10_4_BK_MIN_FREE			0 +#define TARGET_10_4_BE_MIN_FREE			0 +#define TARGET_10_4_VI_MIN_FREE			0 +#define TARGET_10_4_VO_MIN_FREE			0 +#define TARGET_10_4_RX_BATCH_MODE		1 +#define TARGET_10_4_THERMAL_THROTTLING_CONFIG	0 +#define TARGET_10_4_ATF_CONFIG			0 +#define TARGET_10_4_IPHDR_PAD_CONFIG		1 +#define TARGET_10_4_QWRAP_CONFIG		0 +  /* Number of Copy Engines supported */ -#define CE_COUNT 8 +#define CE_COUNT ar->hw_values->ce_count  /*   * Total number of PCIe MSI interrupts requested for all interrupt sources. @@ -335,10 +435,10 @@ enum ath10k_hw_rate_cck {  /* MSIs for Copy Engines */  #define MSI_ASSIGN_CE_INITIAL	1 -#define MSI_ASSIGN_CE_MAX	7 +#define MSI_ASSIGN_CE_MAX	ar->hw_values->msi_assign_ce_max  /* as of IP3.7.1 */ -#define RTC_STATE_V_ON				3 +#define RTC_STATE_V_ON				ar->hw_values->rtc_state_val_on  #define RTC_STATE_COLD_RESET_MASK		ar->regs->rtc_state_cold_reset_mask  #define RTC_STATE_V_LSB				0 @@ -374,7 +474,7 @@ enum ath10k_hw_rate_cck {  #define CE7_BASE_ADDRESS			ar->regs->ce7_base_address  #define DBI_BASE_ADDRESS			0x00060000  #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS	0x0006c000 -#define PCIE_LOCAL_BASE_ADDRESS			0x00080000 +#define PCIE_LOCAL_BASE_ADDRESS		ar->regs->pcie_local_base_address  #define SOC_RESET_CONTROL_ADDRESS		0x00000000  #define SOC_RESET_CONTROL_OFFSET		0x00000000 @@ -448,24 +548,25 @@ enum ath10k_hw_rate_cck {  #define CORE_CTRL_ADDRESS			0x0000  #define PCIE_INTR_ENABLE_ADDRESS		0x0008  #define PCIE_INTR_CAUSE_ADDRESS			0x000c -#define PCIE_INTR_CLR_ADDRESS			0x0014 +#define PCIE_INTR_CLR_ADDRESS			ar->regs->pcie_intr_clr_address  #define SCRATCH_3_ADDRESS			ar->regs->scratch_3_address  #define CPU_INTR_ADDRESS			0x0010 -/* Cycle counters are running at 88MHz */ -#define CCNT_TO_MSEC(x) ((x) / 88000) +#define CCNT_TO_MSEC(ar, x) ((x) / ar->hw_params.channel_counters_freq_hz)  /* Firmware indications to the Host via SCRATCH_3 register. */ -#define FW_INDICATOR_ADDRESS	(SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) +#define FW_INDICATOR_ADDRESS			ar->regs->fw_indicator_address  #define FW_IND_EVENT_PENDING			1  #define FW_IND_INITIALIZED			2  /* HOST_REG interrupt from firmware */ -#define PCIE_INTR_FIRMWARE_MASK			0x00000400 -#define PCIE_INTR_CE_MASK_ALL			0x0007f800 +#define PCIE_INTR_FIRMWARE_MASK			ar->regs->pcie_intr_fw_mask +#define PCIE_INTR_CE_MASK_ALL			ar->regs->pcie_intr_ce_mask_all  #define DRAM_BASE_ADDRESS			0x00400000 +#define PCIE_BAR_REG_ADDRESS			0x40030 +  #define MISSING 0  #define SYSTEM_SLEEP_OFFSET			SOC_SYSTEM_SLEEP_OFFSET diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 218b6af63447..64674c955d44 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -197,6 +197,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif,  		return -EOPNOTSUPP;  	} +	if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { +		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; +	} +  	if (cmd == DISABLE_KEY) {  		arg.key_cipher = WMI_CIPHER_NONE;  		arg.key_data = NULL; @@ -218,6 +222,9 @@ static int ath10k_install_key(struct ath10k_vif *arvif,  	reinit_completion(&ar->install_key_done); +	if (arvif->nohwcrypt) +		return 1; +  	ret = ath10k_send_key(arvif, key, cmd, macaddr, flags);  	if (ret)  		return ret; @@ -240,6 +247,10 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,  	lockdep_assert_held(&ar->conf_mutex); +	if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP && +		    arvif->vif->type != NL80211_IFTYPE_ADHOC)) +		return -EINVAL; +  	spin_lock_bh(&ar->data_lock);  	peer = ath10k_peer_find(ar, arvif->vdev_id, addr);  	spin_unlock_bh(&ar->data_lock); @@ -251,21 +262,34 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,  		if (arvif->wep_keys[i] == NULL)  			continue; -		flags = 0; -		flags |= WMI_KEY_PAIRWISE; +		switch (arvif->vif->type) { +		case NL80211_IFTYPE_AP: +			flags = WMI_KEY_PAIRWISE; -		ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, -					 addr, flags); -		if (ret) -			return ret; +			if (arvif->def_wep_key_idx == i) +				flags |= WMI_KEY_TX_USAGE; -		flags = 0; -		flags |= WMI_KEY_GROUP; +			ret = ath10k_install_key(arvif, arvif->wep_keys[i], +						 SET_KEY, addr, flags); +			if (ret < 0) +				return ret; +			break; +		case NL80211_IFTYPE_ADHOC: +			ret = ath10k_install_key(arvif, arvif->wep_keys[i], +						 SET_KEY, addr, +						 WMI_KEY_PAIRWISE); +			if (ret < 0) +				return ret; -		ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, -					 addr, flags); -		if (ret) -			return ret; +			ret = ath10k_install_key(arvif, arvif->wep_keys[i], +						 SET_KEY, addr, WMI_KEY_GROUP); +			if (ret < 0) +				return ret; +			break; +		default: +			WARN_ON(1); +			return -EINVAL; +		}  		spin_lock_bh(&ar->data_lock);  		peer->keys[i] = arvif->wep_keys[i]; @@ -280,6 +304,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,  	 *  	 * FIXME: Revisit. Perhaps this can be done in a less hacky way.  	 */ +	if (arvif->vif->type != NL80211_IFTYPE_ADHOC) +		return 0; +  	if (arvif->def_wep_key_idx == -1)  		return 0; @@ -322,10 +349,10 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,  		/* key flags are not required to delete the key */  		ret = ath10k_install_key(arvif, peer->keys[i],  					 DISABLE_KEY, addr, flags); -		if (ret && first_errno == 0) +		if (ret < 0 && first_errno == 0)  			first_errno = ret; -		if (ret) +		if (ret < 0)  			ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",  				    i, ret); @@ -398,7 +425,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,  			break;  		/* key flags are not required to delete the key */  		ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags); -		if (ret && first_errno == 0) +		if (ret < 0 && first_errno == 0)  			first_errno = ret;  		if (ret) @@ -591,11 +618,19 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,  static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,  			      enum wmi_peer_type peer_type)  { +	struct ath10k_vif *arvif; +	int num_peers = 0;  	int ret;  	lockdep_assert_held(&ar->conf_mutex); -	if (ar->num_peers >= ar->max_num_peers) +	num_peers = ar->num_peers; + +	/* Each vdev consumes a peer entry as well */ +	list_for_each_entry(arvif, &ar->arvifs, list) +		num_peers++; + +	if (num_peers >= ar->max_num_peers)  		return -ENOBUFS;  	ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type); @@ -671,20 +706,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)  	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);  } -static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value) -{ -	struct ath10k *ar = arvif->ar; -	u32 vdev_param; - -	if (value != 0xFFFFFFFF) -		value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold, -				ATH10K_FRAGMT_THRESHOLD_MIN, -				ATH10K_FRAGMT_THRESHOLD_MAX); - -	vdev_param = ar->wmi.vdev_param->fragmentation_threshold; -	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); -} -  static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)  {  	int ret; @@ -836,7 +857,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)  static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)  {  	struct cfg80211_chan_def *chandef = NULL; -	struct ieee80211_channel *channel = chandef->chan; +	struct ieee80211_channel *channel = NULL;  	struct wmi_vdev_start_request_arg arg = {};  	int ret = 0; @@ -1668,7 +1689,7 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)  	return 0;  } -static int ath10k_mac_ps_vif_count(struct ath10k *ar) +static int ath10k_mac_num_vifs_started(struct ath10k *ar)  {  	struct ath10k_vif *arvif;  	int num = 0; @@ -1676,7 +1697,7 @@ static int ath10k_mac_ps_vif_count(struct ath10k *ar)  	lockdep_assert_held(&ar->conf_mutex);  	list_for_each_entry(arvif, &ar->arvifs, list) -		if (arvif->ps) +		if (arvif->is_started)  			num++;  	return num; @@ -1700,7 +1721,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)  	enable_ps = arvif->ps; -	if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && +	if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 &&  	    !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,  		      ar->fw_features)) {  		ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", @@ -2502,6 +2523,9 @@ static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar,  	u32 param;  	u32 value; +	if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_AFTER_ASSOC) +		return 0; +  	if (!(ar->vht_cap_info &  	      (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |  	       IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | @@ -2995,6 +3019,8 @@ void ath10k_mac_tx_unlock(struct ath10k *ar, int reason)  						   IEEE80211_IFACE_ITER_RESUME_ALL,  						   ath10k_mac_tx_unlock_iter,  						   ar); + +	ieee80211_wake_queue(ar->hw, ar->hw->offchannel_tx_hw_queue);  }  void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason) @@ -3034,38 +3060,16 @@ static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif,  	lockdep_assert_held(&ar->htt.tx_lock); -	switch (pause_id) { -	case WMI_TLV_TX_PAUSE_ID_MCC: -	case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: -	case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: -	case WMI_TLV_TX_PAUSE_ID_AP_PS: -	case WMI_TLV_TX_PAUSE_ID_IBSS_PS: -		switch (action) { -		case WMI_TLV_TX_PAUSE_ACTION_STOP: -			ath10k_mac_vif_tx_lock(arvif, pause_id); -			break; -		case WMI_TLV_TX_PAUSE_ACTION_WAKE: -			ath10k_mac_vif_tx_unlock(arvif, pause_id); -			break; -		default: -			ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", -				    action, arvif->vdev_id); -			break; -		} +	switch (action) { +	case WMI_TLV_TX_PAUSE_ACTION_STOP: +		ath10k_mac_vif_tx_lock(arvif, pause_id); +		break; +	case WMI_TLV_TX_PAUSE_ACTION_WAKE: +		ath10k_mac_vif_tx_unlock(arvif, pause_id);  		break; -	case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: -	case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: -	case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: -	case WMI_TLV_TX_PAUSE_ID_HOST:  	default: -		/* FIXME: Some pause_ids aren't vdev specific. Instead they -		 * target peer_id and tid. Implementing these could improve -		 * traffic scheduling fairness across multiple connected -		 * stations in AP/IBSS modes. -		 */ -		ath10k_dbg(ar, ATH10K_DBG_MAC, -			   "mac ignoring unsupported tx pause vdev %i id %d\n", -			   arvif->vdev_id, pause_id); +		ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", +			    action, arvif->vdev_id);  		break;  	}  } @@ -3082,12 +3086,15 @@ static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac,  	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);  	struct ath10k_mac_tx_pause *arg = data; +	if (arvif->vdev_id != arg->vdev_id) +		return; +  	ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action);  } -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, -				enum wmi_tlv_tx_pause_id pause_id, -				enum wmi_tlv_tx_pause_action action) +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, +				     enum wmi_tlv_tx_pause_id pause_id, +				     enum wmi_tlv_tx_pause_action action)  {  	struct ath10k_mac_tx_pause arg = {  		.vdev_id = vdev_id, @@ -3168,13 +3175,30 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,  	 * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for  	 * NativeWifi txmode - it selects AP key instead of peer key. It seems  	 * to work with Ethernet txmode so use it. +	 * +	 * FIXME: Check if raw mode works with TDLS.  	 */  	if (ieee80211_is_data_present(fc) && sta && sta->tdls)  		return ATH10K_HW_TXRX_ETHERNET; +	if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) +		return ATH10K_HW_TXRX_RAW; +  	return ATH10K_HW_TXRX_NATIVE_WIFI;  } +static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif, +				     struct sk_buff *skb) { +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT | +			 IEEE80211_TX_CTL_INJECTED; +	if ((info->flags & mask) == mask) +		return false; +	if (vif) +		return !ath10k_vif_to_arvif(vif)->nohwcrypt; +	return true; +} +  /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS   * Control in the header.   */ @@ -3341,6 +3365,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)  	int vdev_id;  	int ret;  	unsigned long time_left; +	bool tmp_peer_created = false;  	/* FW requirement: We must create a peer before FW will send out  	 * an offchannel frame. Otherwise the frame will be stuck and @@ -3378,6 +3403,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)  			if (ret)  				ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",  					    peer_addr, vdev_id, ret); +			tmp_peer_created = (ret == 0);  		}  		spin_lock_bh(&ar->data_lock); @@ -3393,7 +3419,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)  			ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",  				    skb); -		if (!peer) { +		if (!peer && tmp_peer_created) {  			ret = ath10k_peer_delete(ar, vdev_id, peer_addr);  			if (ret)  				ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n", @@ -3449,14 +3475,13 @@ void __ath10k_scan_finish(struct ath10k *ar)  	case ATH10K_SCAN_IDLE:  		break;  	case ATH10K_SCAN_RUNNING: -		if (ar->scan.is_roc) -			ieee80211_remain_on_channel_expired(ar->hw); -		/* fall through */  	case ATH10K_SCAN_ABORTING:  		if (!ar->scan.is_roc)  			ieee80211_scan_completed(ar->hw,  						 (ar->scan.state ==  						  ATH10K_SCAN_ABORTING)); +		else if (ar->scan.roc_notify) +			ieee80211_remain_on_channel_expired(ar->hw);  		/* fall through */  	case ATH10K_SCAN_STARTING:  		ar->scan.state = ATH10K_SCAN_IDLE; @@ -3620,6 +3645,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,  	ATH10K_SKB_CB(skb)->htt.is_offchan = false;  	ATH10K_SKB_CB(skb)->htt.freq = 0;  	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); +	ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb);  	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);  	ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);  	ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc); @@ -3635,12 +3661,11 @@ static void ath10k_tx(struct ieee80211_hw *hw,  		ath10k_tx_h_8023(skb);  		break;  	case ATH10K_HW_TXRX_RAW: -		/* FIXME: Packet injection isn't implemented. It should be -		 * doable with firmware 10.2 on qca988x. -		 */ -		WARN_ON_ONCE(1); -		ieee80211_free_txskb(hw, skb); -		return; +		if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { +			WARN_ON_ONCE(1); +			ieee80211_free_txskb(hw, skb); +			return; +		}  	}  	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { @@ -4039,6 +4064,43 @@ static u32 get_nss_from_chainmask(u16 chain_mask)  	return 1;  } +static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif) +{ +	u32 value = 0; +	struct ath10k *ar = arvif->ar; + +	if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC) +		return 0; + +	if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +				IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) +		value |= SM((ar->num_rf_chains - 1), WMI_TXBF_STS_CAP_OFFSET); + +	if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | +				IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) +		value |= SM((ar->num_rf_chains - 1), WMI_BF_SOUND_DIM_OFFSET); + +	if (!value) +		return 0; + +	if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) +		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; + +	if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) +		value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFER | +			  WMI_VDEV_PARAM_TXBF_SU_TX_BFER); + +	if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) +		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; + +	if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) +		value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFEE | +			  WMI_VDEV_PARAM_TXBF_SU_TX_BFEE); + +	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, +					 ar->wmi.vdev_param->txbf, value); +} +  /*   * TODO:   * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, @@ -4080,6 +4142,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));  	} +	if (ar->num_peers >= ar->max_num_peers) { +		ath10k_warn(ar, "refusing vdev creation due to insufficient peer entry resources in firmware\n"); +		ret = -ENOBUFS; +		goto err; +	} +  	if (ar->free_vdev_map == 0) {  		ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");  		ret = -EBUSY; @@ -4159,6 +4227,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  			goto err;  		}  	} +	if (test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)) +		arvif->nohwcrypt = true; + +	if (arvif->nohwcrypt && +	    !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { +		ath10k_warn(ar, "cryptmode module param needed for sw crypto\n"); +		goto err; +	}  	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",  		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, @@ -4257,16 +4333,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  		}  	} -	ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); +	ret = ath10k_mac_set_txbf_conf(arvif);  	if (ret) { -		ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", +		ath10k_warn(ar, "failed to set txbf for vdev %d: %d\n",  			    arvif->vdev_id, ret);  		goto err_peer_delete;  	} -	ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); +	ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);  	if (ret) { -		ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n", +		ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",  			    arvif->vdev_id, ret);  		goto err_peer_delete;  	} @@ -4287,6 +4363,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  		}  	} +	spin_lock_bh(&ar->htt.tx_lock); +	if (!ar->tx_paused) +		ieee80211_wake_queue(ar->hw, arvif->vdev_id); +	spin_unlock_bh(&ar->htt.tx_lock); +  	mutex_unlock(&ar->conf_mutex);  	return 0; @@ -4641,9 +4722,6 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,  	arg.vdev_id = arvif->vdev_id;  	arg.scan_id = ATH10K_SCAN_ID; -	if (!req->no_cck) -		arg.scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; -  	if (req->ie_len) {  		arg.ie_len = req->ie_len;  		memcpy(arg.ie, req->ie, arg.ie_len); @@ -4751,6 +4829,9 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  	if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)  		return 1; +	if (arvif->nohwcrypt) +		return 1; +  	if (key->keyidx > WMI_MAX_KEY_INDEX)  		return -ENOSPC; @@ -4820,6 +4901,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  	ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags);  	if (ret) { +		WARN_ON(ret > 0);  		ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",  			    arvif->vdev_id, peer_addr, ret);  		goto exit; @@ -4835,13 +4917,16 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2);  		if (ret) { +			WARN_ON(ret > 0);  			ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n",  				    arvif->vdev_id, peer_addr, ret);  			ret2 = ath10k_install_key(arvif, key, DISABLE_KEY,  						  peer_addr, flags); -			if (ret2) +			if (ret2) { +				WARN_ON(ret2 > 0);  				ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n",  					    arvif->vdev_id, peer_addr, ret2); +			}  			goto exit;  		}  	} @@ -5462,6 +5547,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,  		ar->scan.is_roc = true;  		ar->scan.vdev_id = arvif->vdev_id;  		ar->scan.roc_freq = chan->center_freq; +		ar->scan.roc_notify = true;  		ret = 0;  		break;  	case ATH10K_SCAN_STARTING: @@ -5525,7 +5611,13 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)  	struct ath10k *ar = hw->priv;  	mutex_lock(&ar->conf_mutex); + +	spin_lock_bh(&ar->data_lock); +	ar->scan.roc_notify = false; +	spin_unlock_bh(&ar->data_lock); +  	ath10k_scan_abort(ar); +  	mutex_unlock(&ar->conf_mutex);  	cancel_delayed_work_sync(&ar->scan.timeout); @@ -5561,12 +5653,27 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)  	return ret;  } +static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ +	/* Even though there's a WMI enum for fragmentation threshold no known +	 * firmware actually implements it. Moreover it is not possible to rely +	 * frame fragmentation to mac80211 because firmware clears the "more +	 * fragments" bit in frame control making it impossible for remote +	 * devices to reassemble frames. +	 * +	 * Hence implement a dummy callback just to say fragmentation isn't +	 * supported. This effectively prevents mac80211 from doing frame +	 * fragmentation in software. +	 */ +	return -EOPNOTSUPP; +} +  static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  			 u32 queues, bool drop)  {  	struct ath10k *ar = hw->priv;  	bool skip; -	int ret; +	long time_left;  	/* mac80211 doesn't care if we really xmit queued frames or not  	 * we'll collect those frames either way if we stop/delete vdevs */ @@ -5578,7 +5685,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	if (ar->state == ATH10K_STATE_WEDGED)  		goto skip; -	ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ +	time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({  			bool empty;  			spin_lock_bh(&ar->htt.tx_lock); @@ -5592,9 +5699,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  			(empty || skip);  		}), ATH10K_FLUSH_TIMEOUT_HZ); -	if (ret <= 0 || skip) -		ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", -			    skip, ar->state, ret); +	if (time_left == 0 || skip) +		ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", +			    skip, ar->state, time_left);  skip:  	mutex_unlock(&ar->conf_mutex); @@ -6219,6 +6326,13 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,  	arvif->is_started = true; +	ret = ath10k_mac_vif_setup_ps(arvif); +	if (ret) { +		ath10k_warn(ar, "failed to update vdev %i ps: %d\n", +			    arvif->vdev_id, ret); +		goto err_stop; +	} +  	if (vif->type == NL80211_IFTYPE_MONITOR) {  		ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr);  		if (ret) { @@ -6236,6 +6350,7 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,  err_stop:  	ath10k_vdev_stop(arvif);  	arvif->is_started = false; +	ath10k_mac_vif_setup_ps(arvif);  err:  	mutex_unlock(&ar->conf_mutex); @@ -6395,6 +6510,7 @@ static const struct ieee80211_ops ath10k_ops = {  	.remain_on_channel		= ath10k_remain_on_channel,  	.cancel_remain_on_channel	= ath10k_cancel_remain_on_channel,  	.set_rts_threshold		= ath10k_set_rts_threshold, +	.set_frag_threshold		= ath10k_mac_op_set_frag_threshold,  	.flush				= ath10k_flush,  	.tx_last_beacon			= ath10k_tx_last_beacon,  	.set_antenna			= ath10k_set_antenna, @@ -6565,8 +6681,11 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {  static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {  	{  		.max = 2, -		.types = BIT(NL80211_IFTYPE_STATION) | -			 BIT(NL80211_IFTYPE_AP) | +		.types = BIT(NL80211_IFTYPE_STATION), +	}, +	{ +		.max = 2, +		.types = BIT(NL80211_IFTYPE_AP) |  			 BIT(NL80211_IFTYPE_P2P_CLIENT) |  			 BIT(NL80211_IFTYPE_P2P_GO),  	}, @@ -6576,6 +6695,26 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {  	},  }; +static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = { +	{ +		.max = 2, +		.types = BIT(NL80211_IFTYPE_STATION), +	}, +	{ +		.max = 2, +		.types = BIT(NL80211_IFTYPE_P2P_CLIENT), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_AP) | +			 BIT(NL80211_IFTYPE_P2P_GO), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_DEVICE), +	}, +}; +  static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {  	{  		.max = 1, @@ -6594,7 +6733,7 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {  	{  		.limits = ath10k_tlv_if_limit,  		.num_different_channels = 1, -		.max_interfaces = 3, +		.max_interfaces = 4,  		.n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),  	},  	{ @@ -6608,11 +6747,17 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {  static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {  	{  		.limits = ath10k_tlv_if_limit, -		.num_different_channels = 2, -		.max_interfaces = 3, +		.num_different_channels = 1, +		.max_interfaces = 4,  		.n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),  	},  	{ +		.limits = ath10k_tlv_qcs_if_limit, +		.num_different_channels = 2, +		.max_interfaces = 4, +		.n_limits = ARRAY_SIZE(ath10k_tlv_qcs_if_limit), +	}, +	{  		.limits = ath10k_tlv_if_limit_ibss,  		.num_different_channels = 1,  		.max_interfaces = 2, @@ -6620,6 +6765,33 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {  	},  }; +static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_STATION), +	}, +	{ +		.max	= 16, +		.types	= BIT(NL80211_IFTYPE_AP) +	}, +}; + +static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { +	{ +		.limits = ath10k_10_4_if_limits, +		.n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), +		.max_interfaces = 16, +		.num_different_channels = 1, +		.beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED +		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | +					BIT(NL80211_CHAN_WIDTH_20) | +					BIT(NL80211_CHAN_WIDTH_40) | +					BIT(NL80211_CHAN_WIDTH_80), +#endif +	}, +}; +  static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)  {  	struct ieee80211_sta_vht_cap vht_cap = {0}; @@ -6844,7 +7016,6 @@ int ath10k_mac_register(struct ath10k *ar)  	ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);  	ieee80211_hw_set(ar->hw, AP_LINK_PS);  	ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); -	ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);  	ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);  	ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);  	ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); @@ -6852,6 +7023,9 @@ int ath10k_mac_register(struct ath10k *ar)  	ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);  	ieee80211_hw_set(ar->hw, QUEUE_CONTROL); +	if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) +		ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); +  	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;  	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; @@ -6902,6 +7076,8 @@ int ath10k_mac_register(struct ath10k *ar)  		goto err_free;  	} +	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); +  	/*  	 * on LL hardware queues are managed entirely by the FW  	 * so we only advertise to mac we can do the queues thing @@ -6941,6 +7117,11 @@ int ath10k_mac_register(struct ath10k *ar)  		ar->hw->wiphy->n_iface_combinations =  			ARRAY_SIZE(ath10k_10x_if_comb);  		break; +	case ATH10K_FW_WMI_OP_VERSION_10_4: +		ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; +		ar->hw->wiphy->n_iface_combinations = +			ARRAY_SIZE(ath10k_10_4_if_comb); +		break;  	case ATH10K_FW_WMI_OP_VERSION_UNSET:  	case ATH10K_FW_WMI_OP_VERSION_MAX:  		WARN_ON(1); @@ -6948,7 +7129,8 @@ int ath10k_mac_register(struct ath10k *ar)  		goto err_free;  	} -	ar->hw->netdev_features = NETIF_F_HW_CSUM; +	if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) +		ar->hw->netdev_features = NETIF_F_HW_CSUM;  	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {  		/* Init ath dfs pattern detector */ diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index b291f063705c..e3cefe4c7cfd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -61,9 +61,9 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif,  void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);  void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id); -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, -				enum wmi_tlv_tx_pause_id pause_id, -				enum wmi_tlv_tx_pause_action action); +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, +				     enum wmi_tlv_tx_pause_id pause_id, +				     enum wmi_tlv_tx_pause_action action);  u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,  			     u8 hw_rate); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ea656e011a96..1046ab65b9ab 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,11 +58,15 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");  #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3  #define QCA988X_2_0_DEVICE_ID	(0x003c) +#define QCA6164_2_1_DEVICE_ID	(0x0041)  #define QCA6174_2_1_DEVICE_ID	(0x003e) +#define QCA99X0_2_0_DEVICE_ID	(0x0040)  static const struct pci_device_id ath10k_pci_id_table[] = {  	{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ +	{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */  	{ PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ +	{ PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */  	{0}  }; @@ -72,16 +76,25 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {  	 * because of that.  	 */  	{ QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, + +	{ QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, +	{ QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, +	{ QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, +	{ QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, +	{ QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, +  	{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV },  	{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV },  	{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV },  	{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV },  	{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + +	{ QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },  };  static void ath10k_pci_buffer_cleanup(struct ath10k *ar);  static int ath10k_pci_cold_reset(struct ath10k *ar); -static int ath10k_pci_warm_reset(struct ath10k *ar); +static int ath10k_pci_safe_chip_reset(struct ath10k *ar);  static int ath10k_pci_wait_for_target_init(struct ath10k *ar);  static int ath10k_pci_init_irq(struct ath10k *ar);  static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -90,6 +103,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar);  static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,  			       struct ath10k_ce_pipe *rx_pipe,  			       struct bmi_xfer *xfer); +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar);  static const struct ce_attr host_ce_config_wlan[] = {  	/* CE0: host->target HTC control and raw streams */ @@ -155,6 +169,38 @@ static const struct ce_attr host_ce_config_wlan[] = {  		.src_sz_max = DIAG_TRANSFER_LIMIT,  		.dest_nentries = 2,  	}, + +	/* CE8: target->host pktlog */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 2048, +		.dest_nentries = 128, +	}, + +	/* CE9 target autonomous qcache memcpy */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 0, +		.dest_nentries = 0, +	}, + +	/* CE10: target autonomous hif memcpy */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 0, +		.dest_nentries = 0, +	}, + +	/* CE11: target autonomous hif memcpy */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 0, +		.dest_nentries = 0, +	},  };  /* Target firmware's Copy Engine configuration. */ @@ -232,6 +278,38 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {  	},  	/* CE7 used only by Host */ +	{ +		.pipenum = __cpu_to_le32(7), +		.pipedir = __cpu_to_le32(PIPEDIR_INOUT), +		.nentries = __cpu_to_le32(0), +		.nbytes_max = __cpu_to_le32(0), +		.flags = __cpu_to_le32(0), +		.reserved = __cpu_to_le32(0), +	}, + +	/* CE8 target->host packtlog */ +	{ +		.pipenum = __cpu_to_le32(8), +		.pipedir = __cpu_to_le32(PIPEDIR_IN), +		.nentries = __cpu_to_le32(64), +		.nbytes_max = __cpu_to_le32(2048), +		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), +		.reserved = __cpu_to_le32(0), +	}, + +	/* CE9 target autonomous qcache memcpy */ +	{ +		.pipenum = __cpu_to_le32(9), +		.pipedir = __cpu_to_le32(PIPEDIR_INOUT), +		.nentries = __cpu_to_le32(32), +		.nbytes_max = __cpu_to_le32(2048), +		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), +		.reserved = __cpu_to_le32(0), +	}, + +	/* It not necessary to send target wlan configuration for CE10 & CE11 +	 * as these CEs are not actively used in target. +	 */  };  /* @@ -479,6 +557,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	int ret; +	if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) { +		ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", +			    offset, offset + sizeof(value), ar_pci->mem_len); +		return; +	} +  	ret = ath10k_pci_wake(ar);  	if (ret) {  		ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", @@ -496,6 +580,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)  	u32 val;  	int ret; +	if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) { +		ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", +			    offset, offset + sizeof(val), ar_pci->mem_len); +		return 0; +	} +  	ret = ath10k_pci_wake(ar);  	if (ret) {  		ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", @@ -678,6 +768,26 @@ static void ath10k_pci_rx_replenish_retry(unsigned long ptr)  	ath10k_pci_rx_post(ar);  } +static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) +{ +	u32 val = 0; + +	switch (ar->hw_rev) { +	case ATH10K_HW_QCA988X: +	case ATH10K_HW_QCA6174: +		val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +					  CORE_CTRL_ADDRESS) & +		       0x7ff) << 21; +		break; +	case ATH10K_HW_QCA99X0: +		val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); +		break; +	} + +	val |= 0x100000 | (addr & 0xfffff); +	return val; +} +  /*   * Diagnostic read/write access is provided for startup/config/debug usage.   * Caller must guarantee proper alignment, when applicable, and single user @@ -740,8 +850,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,  		 * convert it from Target CPU virtual address space  		 * to CE address space  		 */ -		address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, -						     address); +		address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);  		ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,  					    0); @@ -899,7 +1008,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,  	 * to  	 *    CE address space  	 */ -	address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); +	address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);  	remaining_bytes = orig_nbytes;  	ce_data = ce_data_base; @@ -1331,20 +1440,42 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)  {  	u32 val; -	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); -	val &= ~CORE_CTRL_PCIE_REG_31_MASK; - -	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +	switch (ar->hw_rev) { +	case ATH10K_HW_QCA988X: +	case ATH10K_HW_QCA6174: +		val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +					CORE_CTRL_ADDRESS); +		val &= ~CORE_CTRL_PCIE_REG_31_MASK; +		ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + +				   CORE_CTRL_ADDRESS, val); +		break; +	case ATH10K_HW_QCA99X0: +		/* TODO: Find appropriate register configuration for QCA99X0 +		 *  to mask irq/MSI. +		 */ +		 break; +	}  }  static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)  {  	u32 val; -	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); -	val |= CORE_CTRL_PCIE_REG_31_MASK; - -	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +	switch (ar->hw_rev) { +	case ATH10K_HW_QCA988X: +	case ATH10K_HW_QCA6174: +		val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +					CORE_CTRL_ADDRESS); +		val |= CORE_CTRL_PCIE_REG_31_MASK; +		ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + +				   CORE_CTRL_ADDRESS, val); +		break; +	case ATH10K_HW_QCA99X0: +		/* TODO: Find appropriate register configuration for QCA99X0 +		 *  to unmask irq/MSI. +		 */ +		break; +	}  }  static void ath10k_pci_irq_disable(struct ath10k *ar) @@ -1506,7 +1637,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)  	 * masked. To prevent the device from asserting the interrupt reset it  	 * before proceeding with cleanup.  	 */ -	ath10k_pci_warm_reset(ar); +	ath10k_pci_safe_chip_reset(ar);  	ath10k_pci_irq_disable(ar);  	ath10k_pci_irq_sync(ar); @@ -1546,8 +1677,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,  	req_paddr = dma_map_single(ar->dev, treq, req_len, DMA_TO_DEVICE);  	ret = dma_mapping_error(ar->dev, req_paddr); -	if (ret) +	if (ret) { +		ret = -EIO;  		goto err_dma; +	}  	if (resp && resp_len) {  		tresp = kzalloc(*resp_len, GFP_KERNEL); @@ -1559,8 +1692,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,  		resp_paddr = dma_map_single(ar->dev, tresp, *resp_len,  					    DMA_FROM_DEVICE);  		ret = dma_mapping_error(ar->dev, resp_paddr); -		if (ret) +		if (ret) { +			ret = EIO;  			goto err_req; +		}  		xfer.wait_for_resp = true;  		xfer.resp_len = 0; @@ -1687,7 +1822,9 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)  	switch (ar_pci->pdev->device) {  	case QCA988X_2_0_DEVICE_ID: +	case QCA99X0_2_0_DEVICE_ID:  		return 1; +	case QCA6164_2_1_DEVICE_ID:  	case QCA6174_2_1_DEVICE_ID:  		switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {  		case QCA6174_HW_1_0_CHIP_ID_REV: @@ -1757,7 +1894,8 @@ static int ath10k_pci_init_config(struct ath10k *ar)  	ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,  					target_ce_config_wlan, -					sizeof(target_ce_config_wlan)); +					sizeof(struct ce_pipe_config) * +					NUM_TARGET_CE_CONFIG_WLAN);  	if (ret != 0) {  		ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); @@ -1871,7 +2009,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)  		}  		/* Last CE is Diagnostic Window */ -		if (i == CE_COUNT - 1) { +		if (i == CE_DIAG_PIPE) {  			ar_pci->ce_diag = pipe->ce_hdl;  			continue;  		} @@ -2016,6 +2154,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)  	return 0;  } +static int ath10k_pci_safe_chip_reset(struct ath10k *ar) +{ +	if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) { +		return ath10k_pci_warm_reset(ar); +	} else if (QCA_REV_99X0(ar)) { +		ath10k_pci_irq_disable(ar); +		return ath10k_pci_qca99x0_chip_reset(ar); +	} else { +		return -ENOTSUPP; +	} +} +  static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar)  {  	int i, ret; @@ -2122,12 +2272,38 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar)  	return 0;  } +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) +{ +	int ret; + +	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n"); + +	ret = ath10k_pci_cold_reset(ar); +	if (ret) { +		ath10k_warn(ar, "failed to cold reset: %d\n", ret); +		return ret; +	} + +	ret = ath10k_pci_wait_for_target_init(ar); +	if (ret) { +		ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", +			    ret); +		return ret; +	} + +	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n"); + +	return 0; +} +  static int ath10k_pci_chip_reset(struct ath10k *ar)  {  	if (QCA_REV_988X(ar))  		return ath10k_pci_qca988x_chip_reset(ar);  	else if (QCA_REV_6174(ar))  		return ath10k_pci_qca6174_chip_reset(ar); +	else if (QCA_REV_99X0(ar)) +		return ath10k_pci_qca99x0_chip_reset(ar);  	else  		return -ENOTSUPP;  } @@ -2602,7 +2778,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)  static int ath10k_pci_cold_reset(struct ath10k *ar)  { -	int i;  	u32 val;  	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); @@ -2618,23 +2793,18 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)  	val |= 1;  	ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); -	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -		if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & -					  RTC_STATE_COLD_RESET_MASK) -			break; -		msleep(1); -	} +	/* After writing into SOC_GLOBAL_RESET to put device into +	 * reset and pulling out of reset pcie may not be stable +	 * for any immediate pcie register access and cause bus error, +	 * add delay before any pcie access request to fix this issue. +	 */ +	msleep(20);  	/* Pull Target, including PCIe, out of RESET. */  	val &= ~1;  	ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); -	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -		if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & -					    RTC_STATE_COLD_RESET_MASK)) -			break; -		msleep(1); -	} +	msleep(20);  	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); @@ -2679,6 +2849,7 @@ static int ath10k_pci_claim(struct ath10k *ar)  	pci_set_master(pdev);  	/* Arrange for access to Target SoC registers. */ +	ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM);  	ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);  	if (!ar_pci->mem) {  		ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); @@ -2742,9 +2913,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	case QCA988X_2_0_DEVICE_ID:  		hw_rev = ATH10K_HW_QCA988X;  		break; +	case QCA6164_2_1_DEVICE_ID:  	case QCA6174_2_1_DEVICE_ID:  		hw_rev = ATH10K_HW_QCA6174;  		break; +	case QCA99X0_2_0_DEVICE_ID: +		hw_rev = ATH10K_HW_QCA99X0; +		break;  	default:  		WARN_ON(1);  		return -ENOTSUPP; @@ -2763,6 +2938,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	ar_pci->pdev = pdev;  	ar_pci->dev = &pdev->dev;  	ar_pci->ar = ar; +	ar->dev_id = pci_dev->device;  	if (pdev->subsystem_vendor || pdev->subsystem_device)  		scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id), diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d7696ddc03c4..8d364fb8f743 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -162,6 +162,7 @@ struct ath10k_pci {  	struct device *dev;  	struct ath10k *ar;  	void __iomem *mem; +	size_t mem_len;  	/*  	 * Number of MSI interrupts granted, 0 --> using legacy PCI line @@ -236,18 +237,6 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)  #define CDC_WAR_MAGIC_STR   0xceef0000  #define CDC_WAR_DATA_CE     4 -/* - * TODO: Should be a function call specific to each Target-type. - * This convoluted macro converts from Target CPU Virtual Address Space to CE - * Address Space. As part of this process, we conservatively fetch the current - * PCIE_BAR. MOST of the time, this should match the upper bits of PCI space - * for this device; but that's not guaranteed. - */ -#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr)			\ -	(((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS |		\ -	  CORE_CTRL_ADDRESS)) & 0x7ff) << 21) |				\ -	 0x100000 | ((addr) & 0xfffff)) -  /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */  #define DIAG_ACCESS_CE_TIMEOUT_MS 10 diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 492b5a5af434..ca8d16884af1 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -422,6 +422,12 @@ struct rx_mpdu_end {  #define RX_MSDU_START_INFO1_IP_FRAG             (1 << 14)  #define RX_MSDU_START_INFO1_TCP_ONLY_ACK        (1 << 15) +#define RX_MSDU_START_INFO2_DA_IDX_MASK         0x000007ff +#define RX_MSDU_START_INFO2_DA_IDX_LSB          0 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_MASK 0x00ff0000 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_LSB  16 +#define RX_MSDU_START_INFO2_DA_BCAST_MCAST      BIT(11) +  /* The decapped header (rx_hdr_status) contains the following:   *  a) 802.11 header   *  [padding to 4 bytes] @@ -449,12 +455,23 @@ enum rx_msdu_decap_format {  	RX_MSDU_DECAP_8023_SNAP_LLC = 3  }; -struct rx_msdu_start { +struct rx_msdu_start_common {  	__le32 info0; /* %RX_MSDU_START_INFO0_ */  	__le32 flow_id_crc;  	__le32 info1; /* %RX_MSDU_START_INFO1_ */  } __packed; +struct rx_msdu_start_qca99x0 { +	__le32 info2; /* %RX_MSDU_START_INFO2_ */ +} __packed; + +struct rx_msdu_start { +	struct rx_msdu_start_common common; +	union { +		struct rx_msdu_start_qca99x0 qca99x0; +	} __packed; +} __packed; +  /*   * msdu_length   *		MSDU length in bytes after decapsulation.  This field is @@ -540,7 +557,7 @@ struct rx_msdu_start {  #define RX_MSDU_END_INFO0_PRE_DELIM_ERR             (1 << 30)  #define RX_MSDU_END_INFO0_RESERVED_3B               (1 << 31) -struct rx_msdu_end { +struct rx_msdu_end_common {  	__le16 ip_hdr_cksum;  	__le16 tcp_hdr_cksum;  	u8 key_id_octet; @@ -549,6 +566,36 @@ struct rx_msdu_end {  	__le32 info0;  } __packed; +#define RX_MSDU_END_INFO1_TCP_FLAG_MASK     0x000001ff +#define RX_MSDU_END_INFO1_TCP_FLAG_LSB      0 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_MASK   0x00001c00 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_LSB    10 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_MASK  0xffff0000 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_LSB   16 +#define RX_MSDU_END_INFO1_IRO_ELIGIBLE      BIT(9) + +#define RX_MSDU_END_INFO2_DA_OFFSET_MASK    0x0000003f +#define RX_MSDU_END_INFO2_DA_OFFSET_LSB     0 +#define RX_MSDU_END_INFO2_SA_OFFSET_MASK    0x00000fc0 +#define RX_MSDU_END_INFO2_SA_OFFSET_LSB     6 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_MASK  0x0003f000 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_LSB   12 + +struct rx_msdu_end_qca99x0 { +	__le32 ipv6_crc; +	__le32 tcp_seq_no; +	__le32 tcp_ack_no; +	__le32 info1; +	__le32 info2; +} __packed; + +struct rx_msdu_end { +	struct rx_msdu_end_common common; +	union { +		struct rx_msdu_end_qca99x0 qca99x0; +	} __packed; +} __packed; +  /*   *ip_hdr_chksum   *		This can include the IP header checksum or the pseudo header @@ -870,7 +917,11 @@ struct rx_ppdu_start {  #define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24)  #define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25) -#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) +#define RX_PPDU_END_INFO1_PEER_IDX_MASK       0x1ffc +#define RX_PPDU_END_INFO1_PEER_IDX_LSB        2 +#define RX_PPDU_END_INFO1_BB_DATA             BIT(0) +#define RX_PPDU_END_INFO1_PEER_IDX_VALID      BIT(1) +#define RX_PPDU_END_INFO1_PPDU_DONE           BIT(15)  struct rx_ppdu_end_common {  	__le32 evm_p0; @@ -891,13 +942,13 @@ struct rx_ppdu_end_common {  	__le32 evm_p15;  	__le32 tsf_timestamp;  	__le32 wb_timestamp; +} __packed; + +struct rx_ppdu_end_qca988x {  	u8 locationing_timestamp;  	u8 phy_err_code;  	__le16 flags; /* %RX_PPDU_END_FLAGS_ */  	__le32 info0; /* %RX_PPDU_END_INFO0_ */ -} __packed; - -struct rx_ppdu_end_qca988x {  	__le16 bb_length;  	__le16 info1; /* %RX_PPDU_END_INFO1_ */  } __packed; @@ -909,16 +960,126 @@ struct rx_ppdu_end_qca988x {  #define RX_PPDU_END_RTT_NORMAL_MODE            BIT(31)  struct rx_ppdu_end_qca6174 { +	u8 locationing_timestamp; +	u8 phy_err_code; +	__le16 flags; /* %RX_PPDU_END_FLAGS_ */ +	__le32 info0; /* %RX_PPDU_END_INFO0_ */  	__le32 rtt; /* %RX_PPDU_END_RTT_ */  	__le16 bb_length;  	__le16 info1; /* %RX_PPDU_END_INFO1_ */  } __packed; +#define RX_PKT_END_INFO0_RX_SUCCESS              BIT(0) +#define RX_PKT_END_INFO0_ERR_TX_INTERRUPT_RX     BIT(3) +#define RX_PKT_END_INFO0_ERR_OFDM_POWER_DROP     BIT(4) +#define RX_PKT_END_INFO0_ERR_OFDM_RESTART        BIT(5) +#define RX_PKT_END_INFO0_ERR_CCK_POWER_DROP      BIT(6) +#define RX_PKT_END_INFO0_ERR_CCK_RESTART         BIT(7) + +#define RX_LOCATION_INFO_RTT_CORR_VAL_MASK       0x0001ffff +#define RX_LOCATION_INFO_RTT_CORR_VAL_LSB        0 +#define RX_LOCATION_INFO_FAC_STATUS_MASK         0x000c0000 +#define RX_LOCATION_INFO_FAC_STATUS_LSB          18 +#define RX_LOCATION_INFO_PKT_BW_MASK             0x00700000 +#define RX_LOCATION_INFO_PKT_BW_LSB              20 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_MASK 0x01800000 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_LSB  23 +#define RX_LOCATION_INFO_CIR_STATUS              BIT(17) +#define RX_LOCATION_INFO_RTT_MAC_PHY_PHASE       BIT(25) +#define RX_LOCATION_INFO_RTT_TX_DATA_START_X     BIT(26) +#define RX_LOCATION_INFO_HW_IFFT_MODE            BIT(30) +#define RX_LOCATION_INFO_RX_LOCATION_VALID       BIT(31) + +struct rx_pkt_end { +	__le32 info0; /* %RX_PKT_END_INFO0_ */ +	__le32 phy_timestamp_1; +	__le32 phy_timestamp_2; +	__le32 rx_location_info; /* %RX_LOCATION_INFO_ */ +} __packed; + +enum rx_phy_ppdu_end_info0 { +	RX_PHY_PPDU_END_INFO0_ERR_RADAR           = BIT(2), +	RX_PHY_PPDU_END_INFO0_ERR_RX_ABORT        = BIT(3), +	RX_PHY_PPDU_END_INFO0_ERR_RX_NAP          = BIT(4), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_TIMING     = BIT(5), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_PARITY     = BIT(6), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_RATE       = BIT(7), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_LENGTH     = BIT(8), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_RESTART    = BIT(9), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_SERVICE    = BIT(10), +	RX_PHY_PPDU_END_INFO0_ERR_OFDM_POWER_DROP = BIT(11), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_BLOCKER     = BIT(12), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_TIMING      = BIT(13), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_HEADER_CRC  = BIT(14), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_RATE        = BIT(15), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_LENGTH      = BIT(16), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_RESTART     = BIT(17), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_SERVICE     = BIT(18), +	RX_PHY_PPDU_END_INFO0_ERR_CCK_POWER_DROP  = BIT(19), +	RX_PHY_PPDU_END_INFO0_ERR_HT_CRC          = BIT(20), +	RX_PHY_PPDU_END_INFO0_ERR_HT_LENGTH       = BIT(21), +	RX_PHY_PPDU_END_INFO0_ERR_HT_RATE         = BIT(22), +	RX_PHY_PPDU_END_INFO0_ERR_HT_ZLF          = BIT(23), +	RX_PHY_PPDU_END_INFO0_ERR_FALSE_RADAR_EXT = BIT(24), +	RX_PHY_PPDU_END_INFO0_ERR_GREEN_FIELD     = BIT(25), +	RX_PHY_PPDU_END_INFO0_ERR_SPECTRAL_SCAN   = BIT(26), +	RX_PHY_PPDU_END_INFO0_ERR_RX_DYN_BW       = BIT(27), +	RX_PHY_PPDU_END_INFO0_ERR_LEG_HT_MISMATCH = BIT(28), +	RX_PHY_PPDU_END_INFO0_ERR_VHT_CRC         = BIT(29), +	RX_PHY_PPDU_END_INFO0_ERR_VHT_SIGA        = BIT(30), +	RX_PHY_PPDU_END_INFO0_ERR_VHT_LSIG        = BIT(31), +}; + +enum rx_phy_ppdu_end_info1 { +	RX_PHY_PPDU_END_INFO1_ERR_VHT_NDP            = BIT(0), +	RX_PHY_PPDU_END_INFO1_ERR_VHT_NSYM           = BIT(1), +	RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_EXT_SYM     = BIT(2), +	RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID0    = BIT(3), +	RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID1_62 = BIT(4), +	RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID63   = BIT(5), +	RX_PHY_PPDU_END_INFO1_ERR_OFDM_LDPC_DECODER  = BIT(6), +	RX_PHY_PPDU_END_INFO1_ERR_DEFER_NAP          = BIT(7), +	RX_PHY_PPDU_END_INFO1_ERR_FDOMAIN_TIMEOUT    = BIT(8), +	RX_PHY_PPDU_END_INFO1_ERR_LSIG_REL_CHECK     = BIT(9), +	RX_PHY_PPDU_END_INFO1_ERR_BT_COLLISION       = BIT(10), +	RX_PHY_PPDU_END_INFO1_ERR_MU_FEEDBACK        = BIT(11), +	RX_PHY_PPDU_END_INFO1_ERR_TX_INTERRUPT_RX    = BIT(12), +	RX_PHY_PPDU_END_INFO1_ERR_RX_CBF             = BIT(13), +}; + +struct rx_phy_ppdu_end { +	__le32 info0; /* %RX_PHY_PPDU_END_INFO0_ */ +	__le32 info1; /* %RX_PHY_PPDU_END_INFO1_ */ +} __packed; + +#define RX_PPDU_END_RX_TIMING_OFFSET_MASK          0x00000fff +#define RX_PPDU_END_RX_TIMING_OFFSET_LSB           0 + +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_MASK        0x00ffffff +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_LSB         0 +#define RX_PPDU_END_RX_INFO_TX_HT_VHT_ACK          BIT(24) +#define RX_PPDU_END_RX_INFO_RX_PKT_END_VALID       BIT(25) +#define RX_PPDU_END_RX_INFO_RX_PHY_PPDU_END_VALID  BIT(26) +#define RX_PPDU_END_RX_INFO_RX_TIMING_OFFSET_VALID BIT(27) +#define RX_PPDU_END_RX_INFO_BB_CAPTURED_CHANNEL    BIT(28) +#define RX_PPDU_END_RX_INFO_UNSUPPORTED_MU_NC      BIT(29) +#define RX_PPDU_END_RX_INFO_OTP_TXBF_DISABLE       BIT(30) + +struct rx_ppdu_end_qca99x0 { +	struct rx_pkt_end rx_pkt_end; +	struct rx_phy_ppdu_end rx_phy_ppdu_end; +	__le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ +	__le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ +	__le16 bb_length; +	__le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; +  struct rx_ppdu_end {  	struct rx_ppdu_end_common common;  	union {  		struct rx_ppdu_end_qca988x qca988x;  		struct rx_ppdu_end_qca6174 qca6174; +		struct rx_ppdu_end_qca99x0 qca99x0;  	} __packed;  } __packed; diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 8dcd424aa502..4671cfbcd8f7 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -57,7 +57,7 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,  }  int ath10k_spectral_process_fft(struct ath10k *ar, -				const struct wmi_phyerr *phyerr, +				struct wmi_phyerr_ev_arg *phyerr,  				const struct phyerr_fft_report *fftr,  				size_t bin_len, u64 tsf)  { @@ -73,6 +73,15 @@ int ath10k_spectral_process_fft(struct ath10k *ar,  	if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)  		return -EINVAL; +	/* qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in +	 * report mode 2. First 64 bytes carries inband tones (-32 to +31) +	 * and last 4 byte carries band edge detection data (+32) mainly +	 * used in radar detection purpose. Strip last 4 byte to make bin +	 * size is valid one. +	 */ +	if (bin_len == 68) +		bin_len -= 4; +  	reg0 = __le32_to_cpu(fftr->reg0);  	reg1 = __le32_to_cpu(fftr->reg1); @@ -118,15 +127,14 @@ int ath10k_spectral_process_fft(struct ath10k *ar,  	fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);  	fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db); -	freq1 = __le16_to_cpu(phyerr->freq1); -	freq2 = __le16_to_cpu(phyerr->freq2); +	freq1 = phyerr->freq1; +	freq2 = phyerr->freq2;  	fft_sample->freq1 = __cpu_to_be16(freq1);  	fft_sample->freq2 = __cpu_to_be16(freq2);  	chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX); -	fft_sample->noise = __cpu_to_be16( -			__le16_to_cpu(phyerr->nf_chains[chain_idx])); +	fft_sample->noise = __cpu_to_be16(phyerr->nf_chains[chain_idx]);  	bins = (u8 *)fftr;  	bins += sizeof(*fftr); diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h index 042f5b302c75..89b0ad769d4f 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.h +++ b/drivers/net/wireless/ath/ath10k/spectral.h @@ -47,7 +47,7 @@ enum ath10k_spectral_mode {  #ifdef CONFIG_ATH10K_DEBUGFS  int ath10k_spectral_process_fft(struct ath10k *ar, -				const struct wmi_phyerr *phyerr, +				struct wmi_phyerr_ev_arg *phyerr,  				const struct phyerr_fft_report *fftr,  				size_t bin_len, u64 tsf);  int ath10k_spectral_start(struct ath10k *ar); @@ -59,7 +59,7 @@ void ath10k_spectral_destroy(struct ath10k *ar);  static inline int  ath10k_spectral_process_fft(struct ath10k *ar, -			    const struct wmi_phyerr *phyerr, +			    struct wmi_phyerr_ev_arg *phyerr,  			    const struct phyerr_fft_report *fftr,  			    size_t bin_len, u64 tsf)  { diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c new file mode 100644 index 000000000000..3ca3fae408a7 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This file has implementation for code swap logic. With code swap feature, + * target can run the fw binary with even smaller IRAM size by using host + * memory to store some of the code segments. + */ + +#include "core.h" +#include "bmi.h" +#include "debug.h" + +static int ath10k_swap_code_seg_fill(struct ath10k *ar, +				     struct ath10k_swap_code_seg_info *seg_info, +				     const void *data, size_t data_len) +{ +	u8 *virt_addr = seg_info->virt_address[0]; +	u8 swap_magic[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ] = {}; +	const u8 *fw_data = data; +	union ath10k_swap_code_seg_item *swap_item; +	u32 length = 0; +	u32 payload_len; +	u32 total_payload_len = 0; +	u32 size_left = data_len; + +	/* Parse swap bin and copy the content to host allocated memory. +	 * The format is Address, length and value. The last 4-bytes is +	 * target write address. Currently address field is not used. +	 */ +	seg_info->target_addr = -1; +	while (size_left >= sizeof(*swap_item)) { +		swap_item = (union ath10k_swap_code_seg_item *)fw_data; +		payload_len = __le32_to_cpu(swap_item->tlv.length); +		if ((payload_len > size_left) || +		    (payload_len == 0 && +		     size_left != sizeof(struct ath10k_swap_code_seg_tail))) { +			ath10k_err(ar, "refusing to parse invalid tlv length %d\n", +				   payload_len); +			return -EINVAL; +		} + +		if (payload_len == 0) { +			if (memcmp(swap_item->tail.magic_signature, swap_magic, +				   ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ)) { +				ath10k_err(ar, "refusing an invalid swap file\n"); +				return -EINVAL; +			} +			seg_info->target_addr = +				__le32_to_cpu(swap_item->tail.bmi_write_addr); +			break; +		} + +		memcpy(virt_addr, swap_item->tlv.data, payload_len); +		virt_addr += payload_len; +		length = payload_len +  sizeof(struct ath10k_swap_code_seg_tlv); +		size_left -= length; +		fw_data += length; +		total_payload_len += payload_len; +	} + +	if (seg_info->target_addr == -1) { +		ath10k_err(ar, "failed to parse invalid swap file\n"); +		return -EINVAL; +	} +	seg_info->seg_hw_info.swap_size = __cpu_to_le32(total_payload_len); + +	return 0; +} + +static void +ath10k_swap_code_seg_free(struct ath10k *ar, +			  struct ath10k_swap_code_seg_info *seg_info) +{ +	u32 seg_size; + +	if (!seg_info) +		return; + +	if (!seg_info->virt_address[0]) +		return; + +	seg_size = __le32_to_cpu(seg_info->seg_hw_info.size); +	dma_free_coherent(ar->dev, seg_size, seg_info->virt_address[0], +			  seg_info->paddr[0]); +} + +static struct ath10k_swap_code_seg_info * +ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) +{ +	struct ath10k_swap_code_seg_info *seg_info; +	void *virt_addr; +	dma_addr_t paddr; + +	swap_bin_len = roundup(swap_bin_len, 2); +	if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) { +		ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n", +			   swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX); +		return NULL; +	} + +	seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL); +	if (!seg_info) +		return NULL; + +	virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr, +				       GFP_KERNEL); +	if (!virt_addr) { +		ath10k_err(ar, "failed to allocate dma coherent memory\n"); +		return NULL; +	} + +	seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr); +	seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len); +	seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len); +	seg_info->seg_hw_info.num_segs = +			__cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED); +	seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len)); +	seg_info->virt_address[0] = virt_addr; +	seg_info->paddr[0] = paddr; + +	return seg_info; +} + +int ath10k_swap_code_seg_configure(struct ath10k *ar, +				   enum ath10k_swap_code_seg_bin_type type) +{ +	int ret; +	struct ath10k_swap_code_seg_info *seg_info = NULL; + +	switch (type) { +	case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW: +		if (!ar->swap.firmware_swap_code_seg_info) +			return 0; + +		ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n"); +		seg_info = ar->swap.firmware_swap_code_seg_info; +		break; +	default: +	case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP: +	case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF: +		ath10k_warn(ar, "ignoring unknown code swap binary type %d\n", +			    type); +		return 0; +	} + +	ret = ath10k_bmi_write_memory(ar, seg_info->target_addr, +				      &seg_info->seg_hw_info, +				      sizeof(seg_info->seg_hw_info)); +	if (ret) { +		ath10k_err(ar, "failed to write Code swap segment information (%d)\n", +			   ret); +		return ret; +	} + +	return 0; +} + +void ath10k_swap_code_seg_release(struct ath10k *ar) +{ +	ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info); +	ar->swap.firmware_codeswap_data = NULL; +	ar->swap.firmware_codeswap_len = 0; +	ar->swap.firmware_swap_code_seg_info = NULL; +} + +int ath10k_swap_code_seg_init(struct ath10k *ar) +{ +	int ret; +	struct ath10k_swap_code_seg_info *seg_info; + +	if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data) +		return 0; + +	seg_info = ath10k_swap_code_seg_alloc(ar, +					      ar->swap.firmware_codeswap_len); +	if (!seg_info) { +		ath10k_err(ar, "failed to allocate fw code swap segment\n"); +		return -ENOMEM; +	} + +	ret = ath10k_swap_code_seg_fill(ar, seg_info, +					ar->swap.firmware_codeswap_data, +					ar->swap.firmware_codeswap_len); + +	if (ret) { +		ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n", +			    ret); +		ath10k_swap_code_seg_free(ar, seg_info); +		return ret; +	} + +	ar->swap.firmware_swap_code_seg_info = seg_info; + +	return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/swap.h b/drivers/net/wireless/ath/ath10k/swap.h new file mode 100644 index 000000000000..5c89952dd20f --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SWAP_H_ +#define _SWAP_H_ + +#define ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX	(512 * 1024) +#define ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ	12 +#define ATH10K_SWAP_CODE_SEG_NUM_MAX		16 +/* Currently only one swap segment is supported */ +#define ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED	1 + +struct ath10k_swap_code_seg_tlv { +	__le32 address; +	__le32 length; +	u8 data[0]; +} __packed; + +struct ath10k_swap_code_seg_tail { +	u8 magic_signature[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ]; +	__le32 bmi_write_addr; +} __packed; + +union ath10k_swap_code_seg_item { +	struct ath10k_swap_code_seg_tlv tlv; +	struct ath10k_swap_code_seg_tail tail; +} __packed; + +enum ath10k_swap_code_seg_bin_type { +	 ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP, +	 ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW, +	 ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF, +}; + +struct ath10k_swap_code_seg_hw_info { +	/* Swap binary image size */ +	__le32 swap_size; +	__le32 num_segs; + +	/* Swap data size */ +	__le32 size; +	__le32 size_log2; +	__le32 bus_addr[ATH10K_SWAP_CODE_SEG_NUM_MAX]; +	__le64 reserved[ATH10K_SWAP_CODE_SEG_NUM_MAX]; +} __packed; + +struct ath10k_swap_code_seg_info { +	struct ath10k_swap_code_seg_hw_info seg_hw_info; +	void *virt_address[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; +	u32 target_addr; +	dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; +}; + +int ath10k_swap_code_seg_configure(struct ath10k *ar, +				   enum ath10k_swap_code_seg_bin_type type); +void ath10k_swap_code_seg_release(struct ath10k *ar); +int ath10k_swap_code_seg_init(struct ath10k *ar); + +#endif diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index a417aae52623..768bef629099 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -450,4 +450,7 @@ Fw Mode/SubMode Mask  #define QCA6174_BOARD_DATA_SZ     8192  #define QCA6174_BOARD_EXT_DATA_SZ 0 +#define QCA99X0_BOARD_DATA_SZ	  12288 +#define QCA99X0_BOARD_EXT_DATA_SZ 0 +  #endif /* __TARGADDRS_H__ */ diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 826500bb2b1b..e4a9c4c8d0cb 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,  	struct ath10k_skb_cb *skb_cb;  	struct sk_buff *msdu; -	lockdep_assert_held(&htt->tx_lock); -  	ath10k_dbg(ar, ATH10K_DBG_HTT,  		   "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",  		   tx_done->msdu_id, !!tx_done->discard, @@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,  		return;  	} +	spin_lock_bh(&htt->tx_lock);  	msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);  	if (!msdu) {  		ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",  			    tx_done->msdu_id); +		spin_unlock_bh(&htt->tx_lock);  		return;  	} +	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); +	__ath10k_htt_tx_dec_pending(htt); +	if (htt->num_pending_tx == 0) +		wake_up(&htt->empty_tx_wq); +	spin_unlock_bh(&htt->tx_lock);  	skb_cb = ATH10K_SKB_CB(msdu); @@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,  	if (tx_done->discard) {  		ieee80211_free_txskb(htt->ar->hw, msdu); -		goto exit; +		return;  	}  	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -104,12 +109,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,  	ieee80211_tx_status(htt->ar->hw, msdu);  	/* we do not own the msdu anymore */ - -exit: -	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); -	__ath10k_htt_tx_dec_pending(htt); -	if (htt->num_pending_tx == 0) -		wake_up(&htt->empty_tx_wq);  }  struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, @@ -147,9 +146,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)  static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,  				       const u8 *addr, bool expect_mapped)  { -	int ret; +	long time_left; -	ret = wait_event_timeout(ar->peer_mapping_wq, ({ +	time_left = wait_event_timeout(ar->peer_mapping_wq, ({  			bool mapped;  			spin_lock_bh(&ar->data_lock); @@ -160,7 +159,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,  			 test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));  		}), 3*HZ); -	if (ret <= 0) +	if (time_left == 0)  		return -ETIMEDOUT;  	return 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 47fe2e756bec..248ffc3d6620 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -37,8 +37,10 @@ struct wmi_ops {  			      struct wmi_peer_kick_ev_arg *arg);  	int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb,  			 struct wmi_swba_ev_arg *arg); -	int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb, -			   struct wmi_phyerr_ev_arg *arg); +	int (*pull_phyerr_hdr)(struct ath10k *ar, struct sk_buff *skb, +			       struct wmi_phyerr_hdr_arg *arg); +	int (*pull_phyerr)(struct ath10k *ar, const void *phyerr_buf, +			   int left_len, struct wmi_phyerr_ev_arg *arg);  	int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb,  			    struct wmi_svc_rdy_ev_arg *arg);  	int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb, @@ -49,6 +51,7 @@ struct wmi_ops {  			    struct wmi_roam_ev_arg *arg);  	int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb,  			      struct wmi_wow_ev_arg *arg); +	enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar);  	struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);  	struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar); @@ -260,13 +263,23 @@ ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb,  }  static inline int -ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb, -		       struct wmi_phyerr_ev_arg *arg) +ath10k_wmi_pull_phyerr_hdr(struct ath10k *ar, struct sk_buff *skb, +			   struct wmi_phyerr_hdr_arg *arg) +{ +	if (!ar->wmi.ops->pull_phyerr_hdr) +		return -EOPNOTSUPP; + +	return ar->wmi.ops->pull_phyerr_hdr(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_phyerr(struct ath10k *ar, const void *phyerr_buf, +		       int left_len, struct wmi_phyerr_ev_arg *arg)  {  	if (!ar->wmi.ops->pull_phyerr)  		return -EOPNOTSUPP; -	return ar->wmi.ops->pull_phyerr(ar, skb, arg); +	return ar->wmi.ops->pull_phyerr(ar, phyerr_buf, left_len, arg);  }  static inline int @@ -319,6 +332,15 @@ ath10k_wmi_pull_wow_event(struct ath10k *ar, struct sk_buff *skb,  	return ar->wmi.ops->pull_wow_event(ar, skb, arg);  } +static inline enum wmi_txbf_conf +ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar) +{ +	if (!ar->wmi.ops->get_txbf_conf_scheme) +		return WMI_TXBF_CONF_UNSUPPORTED; + +	return ar->wmi.ops->get_txbf_conf_scheme(ar); +} +  static inline int  ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)  { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 8fdba3865c96..b5849b3fd2f0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -377,12 +377,34 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,  		   "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n",  		   pause_id, action, vdev_map, peer_id, tid_map); -	for (vdev_id = 0; vdev_map; vdev_id++) { -		if (!(vdev_map & BIT(vdev_id))) -			continue; - -		vdev_map &= ~BIT(vdev_id); -		ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action); +	switch (pause_id) { +	case WMI_TLV_TX_PAUSE_ID_MCC: +	case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: +	case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: +	case WMI_TLV_TX_PAUSE_ID_AP_PS: +	case WMI_TLV_TX_PAUSE_ID_IBSS_PS: +		for (vdev_id = 0; vdev_map; vdev_id++) { +			if (!(vdev_map & BIT(vdev_id))) +				continue; + +			vdev_map &= ~BIT(vdev_id); +			ath10k_mac_handle_tx_pause_vdev(ar, vdev_id, pause_id, +							action); +		} +		break; +	case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: +	case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: +	case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: +	case WMI_TLV_TX_PAUSE_ID_HOST: +		ath10k_dbg(ar, ATH10K_DBG_MAC, +			   "mac ignoring unsupported tx pause id %d\n", +			   pause_id); +		break; +	default: +		ath10k_dbg(ar, ATH10K_DBG_MAC, +			   "mac ignoring unknown tx pause vdev %d\n", +			   pause_id); +		break;  	}  	kfree(tb); @@ -497,7 +519,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)  		break;  	case WMI_TLV_SERVICE_READY_EVENTID:  		ath10k_wmi_event_service_ready(ar, skb); -		break; +		return;  	case WMI_TLV_READY_EVENTID:  		ath10k_wmi_event_ready(ar, skb);  		break; @@ -709,6 +731,8 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,  					 const void *ptr, void *data)  {  	struct wmi_tlv_swba_parse *swba = data; +	struct wmi_tim_info_arg *tim_info_arg; +	const struct wmi_tim_info *tim_info_ev = ptr;  	if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO)  		return -EPROTO; @@ -716,7 +740,21 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,  	if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info))  		return -ENOBUFS; -	swba->arg->tim_info[swba->n_tim++] = ptr; +	if (__le32_to_cpu(tim_info_ev->tim_len) > +	     sizeof(tim_info_ev->tim_bitmap)) { +		ath10k_warn(ar, "refusing to parse invalid swba structure\n"); +		return -EPROTO; +	} + +	tim_info_arg = &swba->arg->tim_info[swba->n_tim]; +	tim_info_arg->tim_len = tim_info_ev->tim_len; +	tim_info_arg->tim_mcast = tim_info_ev->tim_mcast; +	tim_info_arg->tim_bitmap = tim_info_ev->tim_bitmap; +	tim_info_arg->tim_changed = tim_info_ev->tim_changed; +	tim_info_arg->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending; + +	swba->n_tim++; +  	return 0;  } @@ -800,9 +838,9 @@ static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar,  	return 0;  } -static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, -					    struct sk_buff *skb, -					    struct wmi_phyerr_ev_arg *arg) +static int ath10k_wmi_tlv_op_pull_phyerr_ev_hdr(struct ath10k *ar, +						struct sk_buff *skb, +						struct wmi_phyerr_hdr_arg *arg)  {  	const void **tb;  	const struct wmi_tlv_phyerr_ev *ev; @@ -824,10 +862,10 @@ static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar,  		return -EPROTO;  	} -	arg->num_phyerrs  = ev->num_phyerrs; -	arg->tsf_l32 = ev->tsf_l32; -	arg->tsf_u32 = ev->tsf_u32; -	arg->buf_len = ev->buf_len; +	arg->num_phyerrs  = __le32_to_cpu(ev->num_phyerrs); +	arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); +	arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); +	arg->buf_len = __le32_to_cpu(ev->buf_len);  	arg->phyerrs = phyerrs;  	kfree(tb); @@ -1241,6 +1279,11 @@ ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar,  	return skb;  } +static enum wmi_txbf_conf ath10k_wmi_tlv_txbf_conf_scheme(struct ath10k *ar) +{ +	return WMI_TXBF_CONF_AFTER_ASSOC; +} +  static struct sk_buff *  ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id,  				     u32 param_value) @@ -1335,7 +1378,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)  	cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64);  	cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64);  	cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); -	cfg->rx_decap_mode = __cpu_to_le32(1); +	cfg->rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode);  	cfg->scan_max_pending_reqs = __cpu_to_le32(4);  	cfg->bmiss_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);  	cfg->roam_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); @@ -3151,6 +3194,38 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {  	.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,  	.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,  	.adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID, +	.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.oem_req_cmdid = WMI_CMD_UNSUPPORTED, +	.nan_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, +	.qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, +	.tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, +	.fwtest_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,  };  static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { @@ -3204,6 +3279,48 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {  	.burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR,  	.burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE,  	.cal_period = WMI_PDEV_PARAM_UNSUPPORTED, +	.aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.en_stats = WMI_PDEV_PARAM_UNSUPPORTED, +	.mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, +	.ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, +	.mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, +	.sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, +	.pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, +	.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,  };  static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { @@ -3262,6 +3379,22 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {  	.tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,  	.ap_detect_out_of_sync_sleeping_sta_time_secs =  					WMI_TLV_VDEV_PARAM_UNSUPPORTED, +	.rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, +	.cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, +	.mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, +	.proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, +	.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, +	.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, +	.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,  };  static const struct wmi_ops wmi_tlv_ops = { @@ -3274,12 +3407,14 @@ static const struct wmi_ops wmi_tlv_ops = {  	.pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,  	.pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,  	.pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, -	.pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev, +	.pull_phyerr_hdr = ath10k_wmi_tlv_op_pull_phyerr_ev_hdr, +	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,  	.pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,  	.pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,  	.pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,  	.pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev,  	.pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, +	.get_txbf_conf_scheme = ath10k_wmi_tlv_txbf_conf_scheme,  	.gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,  	.gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c046c244705..ce01107ef37a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -148,6 +148,48 @@ static struct wmi_cmd_map wmi_cmd_map = {  	.gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID,  	.gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID,  	.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, +	.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.oem_req_cmdid = WMI_CMD_UNSUPPORTED, +	.nan_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, +	.qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, +	.tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, +	.fwtest_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, +	.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, +	.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,  };  /* 10.X WMI cmd track */ @@ -271,6 +313,48 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {  	.gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID,  	.gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID,  	.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, +	.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.oem_req_cmdid = WMI_CMD_UNSUPPORTED, +	.nan_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, +	.qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, +	.tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, +	.fwtest_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, +	.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, +	.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,  };  /* 10.2.4 WMI cmd track */ @@ -393,6 +477,231 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {  	.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,  	.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,  	.pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, +	.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.oem_req_cmdid = WMI_CMD_UNSUPPORTED, +	.nan_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, +	.qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, +	.tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, +	.fwtest_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, +	.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, +	.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, +}; + +/* 10.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_4_cmd_map = { +	.init_cmdid = WMI_10_4_INIT_CMDID, +	.start_scan_cmdid = WMI_10_4_START_SCAN_CMDID, +	.stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, +	.scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, +	.scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, +	.pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, +	.pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, +	.pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, +	.pdev_pktlog_enable_cmdid = WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, +	.pdev_pktlog_disable_cmdid = WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, +	.pdev_set_wmm_params_cmdid = WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, +	.pdev_set_ht_cap_ie_cmdid = WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, +	.pdev_set_vht_cap_ie_cmdid = WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, +	.pdev_set_dscp_tid_map_cmdid = WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, +	.pdev_set_quiet_mode_cmdid = WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, +	.pdev_green_ap_ps_enable_cmdid = WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, +	.pdev_get_tpc_config_cmdid = WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, +	.pdev_set_base_macaddr_cmdid = WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, +	.vdev_create_cmdid = WMI_10_4_VDEV_CREATE_CMDID, +	.vdev_delete_cmdid = WMI_10_4_VDEV_DELETE_CMDID, +	.vdev_start_request_cmdid = WMI_10_4_VDEV_START_REQUEST_CMDID, +	.vdev_restart_request_cmdid = WMI_10_4_VDEV_RESTART_REQUEST_CMDID, +	.vdev_up_cmdid = WMI_10_4_VDEV_UP_CMDID, +	.vdev_stop_cmdid = WMI_10_4_VDEV_STOP_CMDID, +	.vdev_down_cmdid = WMI_10_4_VDEV_DOWN_CMDID, +	.vdev_set_param_cmdid = WMI_10_4_VDEV_SET_PARAM_CMDID, +	.vdev_install_key_cmdid = WMI_10_4_VDEV_INSTALL_KEY_CMDID, +	.peer_create_cmdid = WMI_10_4_PEER_CREATE_CMDID, +	.peer_delete_cmdid = WMI_10_4_PEER_DELETE_CMDID, +	.peer_flush_tids_cmdid = WMI_10_4_PEER_FLUSH_TIDS_CMDID, +	.peer_set_param_cmdid = WMI_10_4_PEER_SET_PARAM_CMDID, +	.peer_assoc_cmdid = WMI_10_4_PEER_ASSOC_CMDID, +	.peer_add_wds_entry_cmdid = WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, +	.peer_remove_wds_entry_cmdid = WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, +	.peer_mcast_group_cmdid = WMI_10_4_PEER_MCAST_GROUP_CMDID, +	.bcn_tx_cmdid = WMI_10_4_BCN_TX_CMDID, +	.pdev_send_bcn_cmdid = WMI_10_4_PDEV_SEND_BCN_CMDID, +	.bcn_tmpl_cmdid = WMI_10_4_BCN_PRB_TMPL_CMDID, +	.bcn_filter_rx_cmdid = WMI_10_4_BCN_FILTER_RX_CMDID, +	.prb_req_filter_rx_cmdid = WMI_10_4_PRB_REQ_FILTER_RX_CMDID, +	.mgmt_tx_cmdid = WMI_10_4_MGMT_TX_CMDID, +	.prb_tmpl_cmdid = WMI_10_4_PRB_TMPL_CMDID, +	.addba_clear_resp_cmdid = WMI_10_4_ADDBA_CLEAR_RESP_CMDID, +	.addba_send_cmdid = WMI_10_4_ADDBA_SEND_CMDID, +	.addba_status_cmdid = WMI_10_4_ADDBA_STATUS_CMDID, +	.delba_send_cmdid = WMI_10_4_DELBA_SEND_CMDID, +	.addba_set_resp_cmdid = WMI_10_4_ADDBA_SET_RESP_CMDID, +	.send_singleamsdu_cmdid = WMI_10_4_SEND_SINGLEAMSDU_CMDID, +	.sta_powersave_mode_cmdid = WMI_10_4_STA_POWERSAVE_MODE_CMDID, +	.sta_powersave_param_cmdid = WMI_10_4_STA_POWERSAVE_PARAM_CMDID, +	.sta_mimo_ps_mode_cmdid = WMI_10_4_STA_MIMO_PS_MODE_CMDID, +	.pdev_dfs_enable_cmdid = WMI_10_4_PDEV_DFS_ENABLE_CMDID, +	.pdev_dfs_disable_cmdid = WMI_10_4_PDEV_DFS_DISABLE_CMDID, +	.roam_scan_mode = WMI_10_4_ROAM_SCAN_MODE, +	.roam_scan_rssi_threshold = WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, +	.roam_scan_period = WMI_10_4_ROAM_SCAN_PERIOD, +	.roam_scan_rssi_change_threshold = +				WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +	.roam_ap_profile = WMI_10_4_ROAM_AP_PROFILE, +	.ofl_scan_add_ap_profile = WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, +	.ofl_scan_remove_ap_profile = WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, +	.ofl_scan_period = WMI_10_4_OFL_SCAN_PERIOD, +	.p2p_dev_set_device_info = WMI_10_4_P2P_DEV_SET_DEVICE_INFO, +	.p2p_dev_set_discoverability = WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, +	.p2p_go_set_beacon_ie = WMI_10_4_P2P_GO_SET_BEACON_IE, +	.p2p_go_set_probe_resp_ie = WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, +	.p2p_set_vendor_ie_data_cmdid = WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, +	.ap_ps_peer_param_cmdid = WMI_10_4_AP_PS_PEER_PARAM_CMDID, +	.ap_ps_peer_uapsd_coex_cmdid = WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, +	.peer_rate_retry_sched_cmdid = WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, +	.wlan_profile_trigger_cmdid = WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, +	.wlan_profile_set_hist_intvl_cmdid = +				WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +	.wlan_profile_get_profile_data_cmdid = +				WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +	.wlan_profile_enable_profile_id_cmdid = +				WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +	.wlan_profile_list_profile_id_cmdid = +				WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +	.pdev_suspend_cmdid = WMI_10_4_PDEV_SUSPEND_CMDID, +	.pdev_resume_cmdid = WMI_10_4_PDEV_RESUME_CMDID, +	.add_bcn_filter_cmdid = WMI_10_4_ADD_BCN_FILTER_CMDID, +	.rmv_bcn_filter_cmdid = WMI_10_4_RMV_BCN_FILTER_CMDID, +	.wow_add_wake_pattern_cmdid = WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, +	.wow_del_wake_pattern_cmdid = WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, +	.wow_enable_disable_wake_event_cmdid = +				WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +	.wow_enable_cmdid = WMI_10_4_WOW_ENABLE_CMDID, +	.wow_hostwakeup_from_sleep_cmdid = +				WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +	.rtt_measreq_cmdid = WMI_10_4_RTT_MEASREQ_CMDID, +	.rtt_tsf_cmdid = WMI_10_4_RTT_TSF_CMDID, +	.vdev_spectral_scan_configure_cmdid = +				WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +	.vdev_spectral_scan_enable_cmdid = +				WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +	.request_stats_cmdid = WMI_10_4_REQUEST_STATS_CMDID, +	.set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, +	.network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, +	.gtk_offload_cmdid = WMI_10_4_GTK_OFFLOAD_CMDID, +	.csa_offload_enable_cmdid = WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, +	.csa_offload_chanswitch_cmdid = WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, +	.chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, +	.echo_cmdid = WMI_10_4_ECHO_CMDID, +	.pdev_utf_cmdid = WMI_10_4_PDEV_UTF_CMDID, +	.dbglog_cfg_cmdid = WMI_10_4_DBGLOG_CFG_CMDID, +	.pdev_qvit_cmdid = WMI_10_4_PDEV_QVIT_CMDID, +	.pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_set_keepalive_cmdid = WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, +	.vdev_get_keepalive_cmdid = WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, +	.force_fw_hang_cmdid = WMI_10_4_FORCE_FW_HANG_CMDID, +	.gpio_config_cmdid = WMI_10_4_GPIO_CONFIG_CMDID, +	.gpio_output_cmdid = WMI_10_4_GPIO_OUTPUT_CMDID, +	.pdev_get_temperature_cmdid = WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, +	.vdev_set_wmm_params_cmdid = WMI_CMD_UNSUPPORTED, +	.tdls_set_state_cmdid = WMI_CMD_UNSUPPORTED, +	.tdls_peer_update_cmdid = WMI_CMD_UNSUPPORTED, +	.adaptive_qcs_cmdid = WMI_CMD_UNSUPPORTED, +	.scan_update_request_cmdid = WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, +	.vdev_standby_response_cmdid = WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, +	.vdev_resume_response_cmdid = WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, +	.wlan_peer_caching_add_peer_cmdid = +			WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, +	.wlan_peer_caching_evict_peer_cmdid = +			WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, +	.wlan_peer_caching_restore_peer_cmdid = +			WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, +	.wlan_peer_caching_print_all_peers_info_cmdid = +			WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, +	.peer_update_wds_entry_cmdid = WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, +	.peer_add_proxy_sta_entry_cmdid = +			WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, +	.rtt_keepalive_cmdid = WMI_10_4_RTT_KEEPALIVE_CMDID, +	.oem_req_cmdid = WMI_10_4_OEM_REQ_CMDID, +	.nan_cmdid = WMI_10_4_NAN_CMDID, +	.vdev_ratemask_cmdid = WMI_10_4_VDEV_RATEMASK_CMDID, +	.qboost_cfg_cmdid = WMI_10_4_QBOOST_CFG_CMDID, +	.pdev_smart_ant_enable_cmdid = WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, +	.pdev_smart_ant_set_rx_antenna_cmdid = +			WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, +	.peer_smart_ant_set_tx_antenna_cmdid = +			WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, +	.peer_smart_ant_set_train_info_cmdid = +			WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, +	.peer_smart_ant_set_node_config_ops_cmdid = +			WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, +	.pdev_set_antenna_switch_table_cmdid = +			WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, +	.pdev_set_ctl_table_cmdid = WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, +	.pdev_set_mimogain_table_cmdid = WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, +	.pdev_ratepwr_table_cmdid = WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, +	.pdev_ratepwr_chainmsk_table_cmdid = +			WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, +	.pdev_fips_cmdid = WMI_10_4_PDEV_FIPS_CMDID, +	.tt_set_conf_cmdid = WMI_10_4_TT_SET_CONF_CMDID, +	.fwtest_cmdid = WMI_10_4_FWTEST_CMDID, +	.vdev_atf_request_cmdid = WMI_10_4_VDEV_ATF_REQUEST_CMDID, +	.peer_atf_request_cmdid = WMI_10_4_PEER_ATF_REQUEST_CMDID, +	.pdev_get_ani_cck_config_cmdid = WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, +	.pdev_get_ani_ofdm_config_cmdid = +			WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, +	.pdev_reserve_ast_entry_cmdid = WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, +	.pdev_get_nfcal_power_cmdid = WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, +	.pdev_get_tpc_cmdid = WMI_10_4_PDEV_GET_TPC_CMDID, +	.pdev_get_ast_info_cmdid = WMI_10_4_PDEV_GET_AST_INFO_CMDID, +	.vdev_set_dscp_tid_map_cmdid = WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, +	.pdev_get_info_cmdid = WMI_10_4_PDEV_GET_INFO_CMDID, +	.vdev_get_info_cmdid = WMI_10_4_VDEV_GET_INFO_CMDID, +	.vdev_filter_neighbor_rx_packets_cmdid = +			WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, +	.mu_cal_start_cmdid = WMI_10_4_MU_CAL_START_CMDID, +	.set_cca_params_cmdid = WMI_10_4_SET_CCA_PARAMS_CMDID, +	.pdev_bss_chan_info_request_cmdid = +			WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,  };  /* MAIN WMI VDEV param map */ @@ -452,6 +761,22 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = {  	.tx_encap_type = WMI_VDEV_PARAM_TX_ENCAP_TYPE,  	.ap_detect_out_of_sync_sleeping_sta_time_secs =  					WMI_VDEV_PARAM_UNSUPPORTED, +	.rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, +	.cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, +	.mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, +	.proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, +	.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, +	.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, +	.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,  };  /* 10.X WMI VDEV param map */ @@ -511,6 +836,22 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = {  	.tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED,  	.ap_detect_out_of_sync_sleeping_sta_time_secs =  		WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +	.rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, +	.cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, +	.mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, +	.proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, +	.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, +	.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, +	.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,  };  static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { @@ -569,6 +910,97 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {  	.tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED,  	.ap_detect_out_of_sync_sleeping_sta_time_secs =  		WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +	.rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, +	.cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, +	.mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, +	.vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, +	.early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, +	.proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, +	.meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, +	.rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, +	.bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { +	.rts_threshold = WMI_10_4_VDEV_PARAM_RTS_THRESHOLD, +	.fragmentation_threshold = WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +	.beacon_interval = WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, +	.listen_interval = WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, +	.multicast_rate = WMI_10_4_VDEV_PARAM_MULTICAST_RATE, +	.mgmt_tx_rate = WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, +	.slot_time = WMI_10_4_VDEV_PARAM_SLOT_TIME, +	.preamble = WMI_10_4_VDEV_PARAM_PREAMBLE, +	.swba_time = WMI_10_4_VDEV_PARAM_SWBA_TIME, +	.wmi_vdev_stats_update_period = WMI_10_4_VDEV_STATS_UPDATE_PERIOD, +	.wmi_vdev_pwrsave_ageout_time = WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, +	.wmi_vdev_host_swba_interval = WMI_10_4_VDEV_HOST_SWBA_INTERVAL, +	.dtim_period = WMI_10_4_VDEV_PARAM_DTIM_PERIOD, +	.wmi_vdev_oc_scheduler_air_time_limit = +	       WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +	.wds = WMI_10_4_VDEV_PARAM_WDS, +	.atim_window = WMI_10_4_VDEV_PARAM_ATIM_WINDOW, +	.bmiss_count_max = WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, +	.bmiss_first_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, +	.bmiss_final_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, +	.feature_wmm = WMI_10_4_VDEV_PARAM_FEATURE_WMM, +	.chwidth = WMI_10_4_VDEV_PARAM_CHWIDTH, +	.chextoffset = WMI_10_4_VDEV_PARAM_CHEXTOFFSET, +	.disable_htprotection = WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, +	.sta_quickkickout = WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, +	.mgmt_rate = WMI_10_4_VDEV_PARAM_MGMT_RATE, +	.protection_mode = WMI_10_4_VDEV_PARAM_PROTECTION_MODE, +	.fixed_rate = WMI_10_4_VDEV_PARAM_FIXED_RATE, +	.sgi = WMI_10_4_VDEV_PARAM_SGI, +	.ldpc = WMI_10_4_VDEV_PARAM_LDPC, +	.tx_stbc = WMI_10_4_VDEV_PARAM_TX_STBC, +	.rx_stbc = WMI_10_4_VDEV_PARAM_RX_STBC, +	.intra_bss_fwd = WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, +	.def_keyid = WMI_10_4_VDEV_PARAM_DEF_KEYID, +	.nss = WMI_10_4_VDEV_PARAM_NSS, +	.bcast_data_rate = WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, +	.mcast_data_rate = WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, +	.mcast_indicate = WMI_10_4_VDEV_PARAM_MCAST_INDICATE, +	.dhcp_indicate = WMI_10_4_VDEV_PARAM_DHCP_INDICATE, +	.unknown_dest_indicate = WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +	.ap_keepalive_min_idle_inactive_time_secs = +	       WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_idle_inactive_time_secs = +	       WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_unresponsive_time_secs = +	       WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +	.ap_enable_nawds = WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, +	.mcast2ucast_set = WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, +	.enable_rtscts = WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, +	.txbf = WMI_10_4_VDEV_PARAM_TXBF, +	.packet_powersave = WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, +	.drop_unencry = WMI_10_4_VDEV_PARAM_DROP_UNENCRY, +	.tx_encap_type = WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, +	.ap_detect_out_of_sync_sleeping_sta_time_secs = +	       WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +	.rc_num_retries = WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, +	.cabq_maxdur = WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, +	.mfptest_set = WMI_10_4_VDEV_PARAM_MFPTEST_SET, +	.rts_fixed_rate = WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, +	.vht_sgimask = WMI_10_4_VDEV_PARAM_VHT_SGIMASK, +	.vht80_ratemask = WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, +	.early_rx_adjust_enable = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, +	.early_rx_tgt_bmiss_num = WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, +	.early_rx_bmiss_sample_cycle = +	       WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, +	.early_rx_slop_step = WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, +	.early_rx_init_slop = WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, +	.early_rx_adjust_pause = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, +	.proxy_sta = WMI_10_4_VDEV_PARAM_PROXY_STA, +	.meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, +	.rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, +	.bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK,  };  static struct wmi_pdev_param_map wmi_pdev_param_map = { @@ -621,6 +1053,48 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {  	.burst_dur = WMI_PDEV_PARAM_UNSUPPORTED,  	.burst_enable = WMI_PDEV_PARAM_UNSUPPORTED,  	.cal_period = WMI_PDEV_PARAM_UNSUPPORTED, +	.aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.en_stats = WMI_PDEV_PARAM_UNSUPPORTED, +	.mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, +	.ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, +	.mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, +	.sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, +	.pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, +	.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,  };  static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -674,6 +1148,48 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {  	.burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,  	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,  	.cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +	.aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.en_stats = WMI_PDEV_PARAM_UNSUPPORTED, +	.mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, +	.ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, +	.mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, +	.sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, +	.pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, +	.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,  };  static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { @@ -727,6 +1243,48 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {  	.burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,  	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,  	.cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +	.aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, +	.rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, +	.proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, +	.peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, +	.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, +	.en_stats = WMI_PDEV_PARAM_UNSUPPORTED, +	.mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, +	.noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, +	.set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, +	.atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, +	.ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, +	.mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, +	.sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, +	.signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, +	.cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, +	.rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, +	.pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, +	.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, +	.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,  };  /* firmware 10.2 specific mappings */ @@ -849,6 +1407,139 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {  	.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,  	.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,  	.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, +	.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, +	.wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, +	.rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.oem_req_cmdid = WMI_CMD_UNSUPPORTED, +	.nan_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, +	.qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, +	.tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, +	.fwtest_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, +}; + +static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { +	.tx_chain_mask = WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK, +	.rx_chain_mask = WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, +	.txpower_limit2g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, +	.txpower_limit5g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, +	.txpower_scale = WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, +	.beacon_gen_mode = WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, +	.beacon_tx_mode = WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, +	.resmgr_offchan_mode = WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +	.protection_mode = WMI_10_4_PDEV_PARAM_PROTECTION_MODE, +	.dynamic_bw = WMI_10_4_PDEV_PARAM_DYNAMIC_BW, +	.non_agg_sw_retry_th = WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +	.agg_sw_retry_th = WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, +	.sta_kickout_th = WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, +	.ac_aggrsize_scaling = WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, +	.ltr_enable = WMI_10_4_PDEV_PARAM_LTR_ENABLE, +	.ltr_ac_latency_be = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, +	.ltr_ac_latency_bk = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, +	.ltr_ac_latency_vi = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, +	.ltr_ac_latency_vo = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, +	.ltr_ac_latency_timeout = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +	.ltr_sleep_override = WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +	.ltr_rx_override = WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, +	.ltr_tx_activity_timeout = WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +	.l1ss_enable = WMI_10_4_PDEV_PARAM_L1SS_ENABLE, +	.dsleep_enable = WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, +	.pcielp_txbuf_flush = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, +	.pcielp_txbuf_watermark = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, +	.pcielp_txbuf_tmo_en = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +	.pcielp_txbuf_tmo_value = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, +	.pdev_stats_update_period = +			WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +	.vdev_stats_update_period = +			WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +	.peer_stats_update_period = +			WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +	.bcnflt_stats_update_period = +			WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +	.pmf_qos = WMI_10_4_PDEV_PARAM_PMF_QOS, +	.arp_ac_override = WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, +	.dcs = WMI_10_4_PDEV_PARAM_DCS, +	.ani_enable = WMI_10_4_PDEV_PARAM_ANI_ENABLE, +	.ani_poll_period = WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, +	.ani_listen_period = WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, +	.ani_ofdm_level = WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, +	.ani_cck_level = WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, +	.dyntxchain = WMI_10_4_PDEV_PARAM_DYNTXCHAIN, +	.proxy_sta = WMI_10_4_PDEV_PARAM_PROXY_STA, +	.idle_ps_config = WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, +	.power_gating_sleep = WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, +	.fast_channel_reset = WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, +	.burst_dur = WMI_10_4_PDEV_PARAM_BURST_DUR, +	.burst_enable = WMI_10_4_PDEV_PARAM_BURST_ENABLE, +	.cal_period = WMI_10_4_PDEV_PARAM_CAL_PERIOD, +	.aggr_burst = WMI_10_4_PDEV_PARAM_AGGR_BURST, +	.rx_decap_mode = WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, +	.smart_antenna_default_antenna = +			WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, +	.igmpmld_override = WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, +	.igmpmld_tid = WMI_10_4_PDEV_PARAM_IGMPMLD_TID, +	.antenna_gain = WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, +	.rx_filter = WMI_10_4_PDEV_PARAM_RX_FILTER, +	.set_mcast_to_ucast_tid = WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, +	.proxy_sta_mode = WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, +	.set_mcast2ucast_mode = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, +	.set_mcast2ucast_buffer = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, +	.remove_mcast2ucast_buffer = +			WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, +	.peer_sta_ps_statechg_enable = +			WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, +	.igmpmld_ac_override = WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, +	.block_interbss = WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, +	.set_disable_reset_cmdid = WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, +	.set_msdu_ttl_cmdid = WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, +	.set_ppdu_duration_cmdid = WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, +	.txbf_sound_period_cmdid = WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, +	.set_promisc_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, +	.set_burst_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, +	.en_stats = WMI_10_4_PDEV_PARAM_EN_STATS, +	.mu_group_policy = WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, +	.noise_detection = WMI_10_4_PDEV_PARAM_NOISE_DETECTION, +	.noise_threshold = WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, +	.dpd_enable = WMI_10_4_PDEV_PARAM_DPD_ENABLE, +	.set_mcast_bcast_echo = WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, +	.atf_strict_sch = WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, +	.atf_sched_duration = WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, +	.ant_plzn = WMI_10_4_PDEV_PARAM_ANT_PLZN, +	.mgmt_retry_limit = WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, +	.sensitivity_level = WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, +	.signed_txpower_2g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, +	.signed_txpower_5g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, +	.enable_per_tid_amsdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, +	.enable_per_tid_ampdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, +	.cca_threshold = WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, +	.rts_fixed_rate = WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, +	.pdev_reset = WMI_10_4_PDEV_PARAM_PDEV_RESET, +	.wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, +	.arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR, +	.arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR,  };  void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, @@ -1232,6 +1923,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,  			return "completed [preempted]";  		case WMI_SCAN_REASON_TIMEDOUT:  			return "completed [timedout]"; +		case WMI_SCAN_REASON_INTERNAL_FAILURE: +			return "completed [internal err]";  		case WMI_SCAN_REASON_MAX:  			break;  		} @@ -1246,6 +1939,10 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,  		return "preempted";  	case WMI_SCAN_EVENT_START_FAILED:  		return "start failed"; +	case WMI_SCAN_EVENT_RESTARTED: +		return "restarted"; +	case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: +		return "foreign channel exit";  	default:  		return "unknown";  	} @@ -1321,6 +2018,8 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)  		break;  	case WMI_SCAN_EVENT_DEQUEUED:  	case WMI_SCAN_EVENT_PREEMPTED: +	case WMI_SCAN_EVENT_RESTARTED: +	case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT:  	default:  		break;  	} @@ -1433,6 +2132,40 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,  	return 0;  } +static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, +					      struct sk_buff *skb, +					      struct wmi_mgmt_rx_ev_arg *arg) +{ +	struct wmi_10_4_mgmt_rx_event *ev; +	struct wmi_10_4_mgmt_rx_hdr *ev_hdr; +	size_t pull_len; +	u32 msdu_len; + +	ev = (struct wmi_10_4_mgmt_rx_event *)skb->data; +	ev_hdr = &ev->hdr; +	pull_len = sizeof(*ev); + +	if (skb->len < pull_len) +		return -EPROTO; + +	skb_pull(skb, pull_len); +	arg->channel = ev_hdr->channel; +	arg->buf_len = ev_hdr->buf_len; +	arg->status = ev_hdr->status; +	arg->snr = ev_hdr->snr; +	arg->phy_mode = ev_hdr->phy_mode; +	arg->rate = ev_hdr->rate; + +	msdu_len = __le32_to_cpu(arg->buf_len); +	if (skb->len < msdu_len) +		return -EPROTO; + +	/* Make sure bytes added for padding are removed. */ +	skb_trim(skb, msdu_len); + +	return 0; +} +  int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)  {  	struct wmi_mgmt_rx_ev_arg arg = {}; @@ -1593,6 +2326,29 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb,  	return 0;  } +static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar, +					      struct sk_buff *skb, +					      struct wmi_ch_info_ev_arg *arg) +{ +	struct wmi_10_4_chan_info_event *ev = (void *)skb->data; + +	if (skb->len < sizeof(*ev)) +		return -EPROTO; + +	skb_pull(skb, sizeof(*ev)); +	arg->err_code = ev->err_code; +	arg->freq = ev->freq; +	arg->cmd_flags = ev->cmd_flags; +	arg->noise_floor = ev->noise_floor; +	arg->rx_clear_count = ev->rx_clear_count; +	arg->cycle_count = ev->cycle_count; +	arg->chan_tx_pwr_range = ev->chan_tx_pwr_range; +	arg->chan_tx_pwr_tp = ev->chan_tx_pwr_tp; +	arg->rx_frame_count = ev->rx_frame_count; + +	return 0; +} +  void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)  {  	struct wmi_ch_info_ev_arg arg = {}; @@ -1656,8 +2412,10 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)  		ar->ch_info_can_report_survey = true;  	} -	ar->survey_last_rx_clear_count = rx_clear_count; -	ar->survey_last_cycle_count = cycle_count; +	if (!(cmd_flags & WMI_CHAN_INFO_FLAG_PRE_COMPLETE)) { +		ar->survey_last_rx_clear_count = rx_clear_count; +		ar->survey_last_cycle_count = cycle_count; +	}  exit:  	spin_unlock_bh(&ar->data_lock); @@ -2149,33 +2907,42 @@ exit:  static void ath10k_wmi_update_tim(struct ath10k *ar,  				  struct ath10k_vif *arvif,  				  struct sk_buff *bcn, -				  const struct wmi_tim_info *tim_info) +				  const struct wmi_tim_info_arg *tim_info)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;  	struct ieee80211_tim_ie *tim;  	u8 *ies, *ie;  	u8 ie_len, pvm_len;  	__le32 t; -	u32 v; +	u32 v, tim_len; + +	/* When FW reports 0 in tim_len, ensure atleast first byte +	 * in tim_bitmap is considered for pvm calculation. +	 */ +	tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1;  	/* if next SWBA has no tim_changed the tim_bitmap is garbage.  	 * we must copy the bitmap upon change and reuse it later */  	if (__le32_to_cpu(tim_info->tim_changed)) {  		int i; -		BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != -			     sizeof(tim_info->tim_bitmap)); +		if (sizeof(arvif->u.ap.tim_bitmap) < tim_len) { +			ath10k_warn(ar, "SWBA TIM field is too big (%u), truncated it to %zu", +				    tim_len, sizeof(arvif->u.ap.tim_bitmap)); +			tim_len = sizeof(arvif->u.ap.tim_bitmap); +		} -		for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { +		for (i = 0; i < tim_len; i++) {  			t = tim_info->tim_bitmap[i / 4];  			v = __le32_to_cpu(t);  			arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;  		} -		/* FW reports either length 0 or 16 -		 * so we calculate this on our own */ +		/* FW reports either length 0 or length based on max supported +		 * station. so we calculate this on our own +		 */  		arvif->u.ap.tim_len = 0; -		for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) +		for (i = 0; i < tim_len; i++)  			if (arvif->u.ap.tim_bitmap[i])  				arvif->u.ap.tim_len = i; @@ -2199,7 +2966,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,  	pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */  	if (pvm_len < arvif->u.ap.tim_len) { -		int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; +		int expand_size = tim_len - pvm_len;  		int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len);  		void *next_ie = ie + 2 + ie_len; @@ -2214,7 +2981,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,  		}  	} -	if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { +	if (pvm_len > tim_len) {  		ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);  		return;  	} @@ -2278,7 +3045,21 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,  		if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))  			break; -		arg->tim_info[i] = &ev->bcn_info[i].tim_info; +		if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > +		     sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { +			ath10k_warn(ar, "refusing to parse invalid swba structure\n"); +			return -EPROTO; +		} + +		arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len; +		arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; +		arg->tim_info[i].tim_bitmap = +				ev->bcn_info[i].tim_info.tim_bitmap; +		arg->tim_info[i].tim_changed = +				ev->bcn_info[i].tim_info.tim_changed; +		arg->tim_info[i].tim_num_ps_pending = +				ev->bcn_info[i].tim_info.tim_num_ps_pending; +  		arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info;  		i++;  	} @@ -2286,12 +3067,74 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,  	return 0;  } +static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, +					   struct sk_buff *skb, +					   struct wmi_swba_ev_arg *arg) +{ +	struct wmi_10_4_host_swba_event *ev = (void *)skb->data; +	u32 map, tim_len; +	size_t i; + +	if (skb->len < sizeof(*ev)) +		return -EPROTO; + +	skb_pull(skb, sizeof(*ev)); +	arg->vdev_map = ev->vdev_map; + +	for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { +		if (!(map & BIT(0))) +			continue; + +		/* If this happens there were some changes in firmware and +		 * ath10k should update the max size of tim_info array. +		 */ +		if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) +			break; + +		if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > +		      sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { +			ath10k_warn(ar, "refusing to parse invalid swba structure\n"); +			return -EPROTO; +		} + +		tim_len = __le32_to_cpu(ev->bcn_info[i].tim_info.tim_len); +		if (tim_len) { +			/* Exclude 4 byte guard length */ +			tim_len -= 4; +			arg->tim_info[i].tim_len = __cpu_to_le32(tim_len); +		} else { +			arg->tim_info[i].tim_len = 0; +		} + +		arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; +		arg->tim_info[i].tim_bitmap = +				ev->bcn_info[i].tim_info.tim_bitmap; +		arg->tim_info[i].tim_changed = +				ev->bcn_info[i].tim_info.tim_changed; +		arg->tim_info[i].tim_num_ps_pending = +				ev->bcn_info[i].tim_info.tim_num_ps_pending; + +		/* 10.4 firmware doesn't have p2p support. notice of absence +		 * info can be ignored for now. +		 */ + +		i++; +	} + +	return 0; +} + +static enum wmi_txbf_conf ath10k_wmi_10_4_txbf_conf_scheme(struct ath10k *ar) +{ +	return WMI_TXBF_CONF_BEFORE_ASSOC; +} +  void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  {  	struct wmi_swba_ev_arg arg = {};  	u32 map;  	int i = -1; -	const struct wmi_tim_info *tim_info; +	const struct wmi_tim_info_arg *tim_info;  	const struct wmi_p2p_noa_info *noa_info;  	struct ath10k_vif *arvif;  	struct sk_buff *bcn; @@ -2320,7 +3163,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  			break;  		} -		tim_info = arg.tim_info[i]; +		tim_info = &arg.tim_info[i];  		noa_info = arg.noa_info[i];  		ath10k_dbg(ar, ATH10K_DBG_MGMT, @@ -2335,6 +3178,10 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  			   __le32_to_cpu(tim_info->tim_bitmap[1]),  			   __le32_to_cpu(tim_info->tim_bitmap[0])); +		/* TODO: Only first 4 word from tim_bitmap is dumped. +		 * Extend debug code to dump full tim_bitmap. +		 */ +  		arvif = ath10k_get_arvif(ar, vdev_id);  		if (arvif == NULL) {  			ath10k_warn(ar, "no vif for vdev_id %d found\n", @@ -2391,6 +3238,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  				ath10k_warn(ar, "failed to map beacon: %d\n",  					    ret);  				dev_kfree_skb_any(bcn); +				ret = -EIO;  				goto skip;  			} @@ -2424,7 +3272,7 @@ void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)  }  static void ath10k_dfs_radar_report(struct ath10k *ar, -				    const struct wmi_phyerr *phyerr, +				    struct wmi_phyerr_ev_arg *phyerr,  				    const struct phyerr_radar_report *rr,  				    u64 tsf)  { @@ -2468,7 +3316,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,  	}  	/* report event to DFS pattern detector */ -	tsf32l = __le32_to_cpu(phyerr->tsf_timestamp); +	tsf32l = phyerr->tsf_timestamp;  	tsf64 = tsf & (~0xFFFFFFFFULL);  	tsf64 |= tsf32l; @@ -2513,7 +3361,7 @@ radar_detected:  }  static int ath10k_dfs_fft_report(struct ath10k *ar, -				 const struct wmi_phyerr *phyerr, +				 struct wmi_phyerr_ev_arg *phyerr,  				 const struct phyerr_fft_report *fftr,  				 u64 tsf)  { @@ -2551,7 +3399,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,  }  void ath10k_wmi_event_dfs(struct ath10k *ar, -			  const struct wmi_phyerr *phyerr, +			  struct wmi_phyerr_ev_arg *phyerr,  			  u64 tsf)  {  	int buf_len, tlv_len, res, i = 0; @@ -2560,11 +3408,11 @@ void ath10k_wmi_event_dfs(struct ath10k *ar,  	const struct phyerr_fft_report *fftr;  	const u8 *tlv_buf; -	buf_len = __le32_to_cpu(phyerr->buf_len); +	buf_len = phyerr->buf_len;  	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,  		   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",  		   phyerr->phy_err_code, phyerr->rssi_combined, -		   __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len); +		   phyerr->tsf_timestamp, tsf, buf_len);  	/* Skip event if DFS disabled */  	if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) @@ -2616,7 +3464,7 @@ void ath10k_wmi_event_dfs(struct ath10k *ar,  }  void ath10k_wmi_event_spectral_scan(struct ath10k *ar, -				    const struct wmi_phyerr *phyerr, +				    struct wmi_phyerr_ev_arg *phyerr,  				    u64 tsf)  {  	int buf_len, tlv_len, res, i = 0; @@ -2625,7 +3473,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar,  	const struct phyerr_fft_report *fftr;  	size_t fftr_len; -	buf_len = __le32_to_cpu(phyerr->buf_len); +	buf_len = phyerr->buf_len;  	while (i < buf_len) {  		if (i + sizeof(*tlv) > buf_len) { @@ -2658,7 +3506,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar,  							  fftr, fftr_len,  							  tsf);  			if (res < 0) { -				ath10k_warn(ar, "failed to process fft report: %d\n", +				ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n",  					    res);  				return;  			} @@ -2669,65 +3517,169 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar,  	}  } -static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, -					struct wmi_phyerr_ev_arg *arg) +static int ath10k_wmi_op_pull_phyerr_ev_hdr(struct ath10k *ar, +					    struct sk_buff *skb, +					    struct wmi_phyerr_hdr_arg *arg)  {  	struct wmi_phyerr_event *ev = (void *)skb->data;  	if (skb->len < sizeof(*ev))  		return -EPROTO; -	arg->num_phyerrs = ev->num_phyerrs; -	arg->tsf_l32 = ev->tsf_l32; -	arg->tsf_u32 = ev->tsf_u32; -	arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev)); +	arg->num_phyerrs = __le32_to_cpu(ev->num_phyerrs); +	arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); +	arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); +	arg->buf_len = skb->len - sizeof(*ev);  	arg->phyerrs = ev->phyerrs;  	return 0;  } +static int ath10k_wmi_10_4_op_pull_phyerr_ev_hdr(struct ath10k *ar, +						 struct sk_buff *skb, +						 struct wmi_phyerr_hdr_arg *arg) +{ +	struct wmi_10_4_phyerr_event *ev = (void *)skb->data; + +	if (skb->len < sizeof(*ev)) +		return -EPROTO; + +	/* 10.4 firmware always reports only one phyerr */ +	arg->num_phyerrs = 1; + +	arg->tsf_l32 = __le32_to_cpu(ev->tsf_l32); +	arg->tsf_u32 = __le32_to_cpu(ev->tsf_u32); +	arg->buf_len = skb->len; +	arg->phyerrs = skb->data; + +	return 0; +} + +int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, +				 const void *phyerr_buf, +				 int left_len, +				 struct wmi_phyerr_ev_arg *arg) +{ +	const struct wmi_phyerr *phyerr = phyerr_buf; +	int i; + +	if (left_len < sizeof(*phyerr)) { +		ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", +			    left_len, sizeof(*phyerr)); +		return -EINVAL; +	} + +	arg->tsf_timestamp = __le32_to_cpu(phyerr->tsf_timestamp); +	arg->freq1 = __le16_to_cpu(phyerr->freq1); +	arg->freq2 = __le16_to_cpu(phyerr->freq2); +	arg->rssi_combined = phyerr->rssi_combined; +	arg->chan_width_mhz = phyerr->chan_width_mhz; +	arg->buf_len = __le32_to_cpu(phyerr->buf_len); +	arg->buf = phyerr->buf; +	arg->hdr_len = sizeof(*phyerr); + +	for (i = 0; i < 4; i++) +		arg->nf_chains[i] = __le16_to_cpu(phyerr->nf_chains[i]); + +	switch (phyerr->phy_err_code) { +	case PHY_ERROR_GEN_SPECTRAL_SCAN: +		arg->phy_err_code = PHY_ERROR_SPECTRAL_SCAN; +		break; +	case PHY_ERROR_GEN_FALSE_RADAR_EXT: +		arg->phy_err_code = PHY_ERROR_FALSE_RADAR_EXT; +		break; +	case PHY_ERROR_GEN_RADAR: +		arg->phy_err_code = PHY_ERROR_RADAR; +		break; +	default: +		arg->phy_err_code = PHY_ERROR_UNKNOWN; +		break; +	} + +	return 0; +} + +static int ath10k_wmi_10_4_op_pull_phyerr_ev(struct ath10k *ar, +					     const void *phyerr_buf, +					     int left_len, +					     struct wmi_phyerr_ev_arg *arg) +{ +	const struct wmi_10_4_phyerr_event *phyerr = phyerr_buf; +	u32 phy_err_mask; +	int i; + +	if (left_len < sizeof(*phyerr)) { +		ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", +			    left_len, sizeof(*phyerr)); +		return -EINVAL; +	} + +	arg->tsf_timestamp = __le32_to_cpu(phyerr->tsf_timestamp); +	arg->freq1 = __le16_to_cpu(phyerr->freq1); +	arg->freq2 = __le16_to_cpu(phyerr->freq2); +	arg->rssi_combined = phyerr->rssi_combined; +	arg->chan_width_mhz = phyerr->chan_width_mhz; +	arg->buf_len = __le32_to_cpu(phyerr->buf_len); +	arg->buf = phyerr->buf; +	arg->hdr_len = sizeof(*phyerr); + +	for (i = 0; i < 4; i++) +		arg->nf_chains[i] = __le16_to_cpu(phyerr->nf_chains[i]); + +	phy_err_mask = __le32_to_cpu(phyerr->phy_err_mask[0]); + +	if (phy_err_mask & PHY_ERROR_10_4_SPECTRAL_SCAN_MASK) +		arg->phy_err_code = PHY_ERROR_SPECTRAL_SCAN; +	else if (phy_err_mask & PHY_ERROR_10_4_RADAR_MASK) +		arg->phy_err_code = PHY_ERROR_RADAR; +	else +		arg->phy_err_code = PHY_ERROR_UNKNOWN; + +	return 0; +} +  void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)  { -	struct wmi_phyerr_ev_arg arg = {}; -	const struct wmi_phyerr *phyerr; +	struct wmi_phyerr_hdr_arg hdr_arg = {}; +	struct wmi_phyerr_ev_arg phyerr_arg = {}; +	const void *phyerr;  	u32 count, i, buf_len, phy_err_code;  	u64 tsf;  	int left_len, ret;  	ATH10K_DFS_STAT_INC(ar, phy_errors); -	ret = ath10k_wmi_pull_phyerr(ar, skb, &arg); +	ret = ath10k_wmi_pull_phyerr_hdr(ar, skb, &hdr_arg);  	if (ret) { -		ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); +		ath10k_warn(ar, "failed to parse phyerr event hdr: %d\n", ret);  		return;  	} -	left_len = __le32_to_cpu(arg.buf_len); -  	/* Check number of included events */ -	count = __le32_to_cpu(arg.num_phyerrs); +	count = hdr_arg.num_phyerrs; + +	left_len = hdr_arg.buf_len; -	tsf = __le32_to_cpu(arg.tsf_u32); +	tsf = hdr_arg.tsf_u32;  	tsf <<= 32; -	tsf |= __le32_to_cpu(arg.tsf_l32); +	tsf |= hdr_arg.tsf_l32;  	ath10k_dbg(ar, ATH10K_DBG_WMI,  		   "wmi event phyerr count %d tsf64 0x%llX\n",  		   count, tsf); -	phyerr = arg.phyerrs; +	phyerr = hdr_arg.phyerrs;  	for (i = 0; i < count; i++) { -		/* Check if we can read event header */ -		if (left_len < sizeof(*phyerr)) { -			ath10k_warn(ar, "single event (%d) wrong head len\n", +		ret = ath10k_wmi_pull_phyerr(ar, phyerr, left_len, &phyerr_arg); +		if (ret) { +			ath10k_warn(ar, "failed to parse phyerr event (%d)\n",  				    i);  			return;  		} -		left_len -= sizeof(*phyerr); - -		buf_len = __le32_to_cpu(phyerr->buf_len); -		phy_err_code = phyerr->phy_err_code; +		left_len -= phyerr_arg.hdr_len; +		buf_len = phyerr_arg.buf_len; +		phy_err_code = phyerr_arg.phy_err_code;  		if (left_len < buf_len) {  			ath10k_warn(ar, "single event (%d) wrong buf len\n", i); @@ -2738,20 +3690,20 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)  		switch (phy_err_code) {  		case PHY_ERROR_RADAR: -			ath10k_wmi_event_dfs(ar, phyerr, tsf); +			ath10k_wmi_event_dfs(ar, &phyerr_arg, tsf);  			break;  		case PHY_ERROR_SPECTRAL_SCAN: -			ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); +			ath10k_wmi_event_spectral_scan(ar, &phyerr_arg, tsf);  			break;  		case PHY_ERROR_FALSE_RADAR_EXT: -			ath10k_wmi_event_dfs(ar, phyerr, tsf); -			ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); +			ath10k_wmi_event_dfs(ar, &phyerr_arg, tsf); +			ath10k_wmi_event_spectral_scan(ar, &phyerr_arg, tsf);  			break;  		default:  			break;  		} -		phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len; +		phyerr = phyerr + phyerr_arg.hdr_len + buf_len;  	}  } @@ -2949,7 +3901,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,  	ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,  							   pool_size,  							   &paddr, -							   GFP_ATOMIC); +							   GFP_KERNEL);  	if (!ar->wmi.mem_chunks[idx].vaddr) {  		ath10k_warn(ar, "failed to allocate memory chunk\n");  		return -ENOMEM; @@ -3038,12 +3990,19 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,  	return 0;  } -void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_event_service_ready_work(struct work_struct *work)  { +	struct ath10k *ar = container_of(work, struct ath10k, svc_rdy_work); +	struct sk_buff *skb = ar->svc_rdy_skb;  	struct wmi_svc_rdy_ev_arg arg = {};  	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;  	int ret; +	if (!skb) { +		ath10k_warn(ar, "invalid service ready event skb\n"); +		return; +	} +  	ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg);  	if (ret) {  		ath10k_warn(ar, "failed to parse service ready: %d\n", ret); @@ -3075,10 +4034,10 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)  	if (ar->fw_api == 1 && ar->fw_version_build > 636)  		set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); -	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { +	if (ar->num_rf_chains > ar->max_spatial_stream) {  		ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", -			    ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); -		ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; +			    ar->num_rf_chains, ar->max_spatial_stream); +		ar->num_rf_chains = ar->max_spatial_stream;  	}  	ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; @@ -3101,20 +4060,39 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)  		return;  	} +	if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { +		ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX + +				    TARGET_10_4_NUM_VDEVS; +		ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS + +				       TARGET_10_4_NUM_VDEVS; +		ar->num_tids = ar->num_active_peers * 2; +		ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX; +	} + +	/* TODO: Adjust max peer count for cases like WMI_SERVICE_RATECTRL_CACHE +	 * and WMI_SERVICE_IRAM_TIDS, etc. +	 */ +  	for (i = 0; i < num_mem_reqs; ++i) {  		req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);  		num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);  		unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size);  		num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); -		if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) +		if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) { +			if (ar->num_active_peers) +				num_units = ar->num_active_peers + 1; +			else +				num_units = ar->max_num_peers + 1; +		} else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) {  			/* number of units to allocate is number of  			 * peers, 1 extra for self peer on target */  			/* this needs to be tied, host and target  			 * can get out of sync */ -			num_units = TARGET_10X_NUM_PEERS + 1; -		else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) -			num_units = TARGET_10X_NUM_VDEVS + 1; +			num_units = ar->max_num_peers + 1; +		} else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) { +			num_units = ar->max_num_vdevs + 1; +		}  		ath10k_dbg(ar, ATH10K_DBG_WMI,  			   "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", @@ -3144,9 +4122,17 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)  		   __le32_to_cpu(arg.eeprom_rd),  		   __le32_to_cpu(arg.num_mem_reqs)); +	dev_kfree_skb(skb); +	ar->svc_rdy_skb = NULL;  	complete(&ar->wmi.service_ready);  } +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +{ +	ar->svc_rdy_skb = skb; +	queue_work(ar->workqueue_aux, &ar->svc_rdy_work); +} +  static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,  				     struct wmi_rdy_ev_arg *arg)  { @@ -3318,7 +4304,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)  		break;  	case WMI_SERVICE_READY_EVENTID:  		ath10k_wmi_event_service_ready(ar, skb); -		break; +		return;  	case WMI_READY_EVENTID:  		ath10k_wmi_event_ready(ar, skb);  		break; @@ -3439,7 +4425,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)  		break;  	case WMI_10X_SERVICE_READY_EVENTID:  		ath10k_wmi_event_service_ready(ar, skb); -		break; +		return;  	case WMI_10X_READY_EVENTID:  		ath10k_wmi_event_ready(ar, skb);  		break; @@ -3550,7 +4536,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)  		break;  	case WMI_10_2_SERVICE_READY_EVENTID:  		ath10k_wmi_event_service_ready(ar, skb); -		break; +		return;  	case WMI_10_2_READY_EVENTID:  		ath10k_wmi_event_ready(ar, skb);  		break; @@ -3576,6 +4562,76 @@ out:  	dev_kfree_skb(skb);  } +static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ +	struct wmi_cmd_hdr *cmd_hdr; +	enum wmi_10_4_event_id id; + +	cmd_hdr = (struct wmi_cmd_hdr *)skb->data; +	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + +	if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr))) +		goto out; + +	trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + +	switch (id) { +	case WMI_10_4_MGMT_RX_EVENTID: +		ath10k_wmi_event_mgmt_rx(ar, skb); +		/* mgmt_rx() owns the skb now! */ +		return; +	case WMI_10_4_ECHO_EVENTID: +		ath10k_wmi_event_echo(ar, skb); +		break; +	case WMI_10_4_DEBUG_MESG_EVENTID: +		ath10k_wmi_event_debug_mesg(ar, skb); +		break; +	case WMI_10_4_SERVICE_READY_EVENTID: +		ath10k_wmi_event_service_ready(ar, skb); +		return; +	case WMI_10_4_SCAN_EVENTID: +		ath10k_wmi_event_scan(ar, skb); +		break; +	case WMI_10_4_CHAN_INFO_EVENTID: +		ath10k_wmi_event_chan_info(ar, skb); +		break; +	case WMI_10_4_PHYERR_EVENTID: +		ath10k_wmi_event_phyerr(ar, skb); +		break; +	case WMI_10_4_READY_EVENTID: +		ath10k_wmi_event_ready(ar, skb); +		break; +	case WMI_10_4_PEER_STA_KICKOUT_EVENTID: +		ath10k_wmi_event_peer_sta_kickout(ar, skb); +		break; +	case WMI_10_4_HOST_SWBA_EVENTID: +		ath10k_wmi_event_host_swba(ar, skb); +		break; +	case WMI_10_4_TBTTOFFSET_UPDATE_EVENTID: +		ath10k_wmi_event_tbttoffset_update(ar, skb); +		break; +	case WMI_10_4_DEBUG_PRINT_EVENTID: +		ath10k_wmi_event_debug_print(ar, skb); +		break; +	case WMI_10_4_VDEV_START_RESP_EVENTID: +		ath10k_wmi_event_vdev_start_resp(ar, skb); +		break; +	case WMI_10_4_VDEV_STOPPED_EVENTID: +		ath10k_wmi_event_vdev_stopped(ar, skb); +		break; +	case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: +		ath10k_dbg(ar, ATH10K_DBG_WMI, +			   "received event id %d not implemented\n", id); +		break; +	default: +		ath10k_warn(ar, "Unknown eventid: %d\n", id); +		break; +	} + +out: +	dev_kfree_skb(skb); +} +  static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)  {  	int ret; @@ -3762,8 +4818,7 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar)  	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_RX_TIMEOUT_HI_PRI); -	config.rx_decap_mode = __cpu_to_le32(TARGET_RX_DECAP_MODE); - +	config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode);  	config.scan_max_pending_reqs =  		__cpu_to_le32(TARGET_SCAN_MAX_PENDING_REQS); @@ -3831,8 +4886,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)  	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); -	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); - +	config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode);  	config.scan_max_pending_reqs =  		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); @@ -3897,7 +4951,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)  	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);  	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); -	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); +	config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode);  	config.scan_max_pending_reqs =  		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); @@ -3950,6 +5004,88 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)  	return buf;  } +static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) +{ +	struct wmi_init_cmd_10_4 *cmd; +	struct sk_buff *buf; +	struct wmi_resource_config_10_4 config = {}; +	u32 len; + +	config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); +	config.num_peers = __cpu_to_le32(ar->max_num_peers); +	config.num_active_peers = __cpu_to_le32(ar->num_active_peers); +	config.num_tids = __cpu_to_le32(ar->num_tids); + +	config.num_offload_peers = __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_PEERS); +	config.num_offload_reorder_buffs = +			__cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS); +	config.num_peer_keys  = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS); +	config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT); +	config.tx_chain_mask  = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK); +	config.rx_chain_mask  = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK); + +	config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); + +	config.rx_decap_mode	    = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE); +	config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); +	config.bmiss_offload_max_vdev = +			__cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); +	config.roam_offload_max_vdev  = +			__cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV); +	config.roam_offload_max_ap_profiles = +			__cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES); +	config.num_mcast_groups = __cpu_to_le32(TARGET_10_4_NUM_MCAST_GROUPS); +	config.num_mcast_table_elems = +			__cpu_to_le32(TARGET_10_4_NUM_MCAST_TABLE_ELEMS); + +	config.mcast2ucast_mode = __cpu_to_le32(TARGET_10_4_MCAST2UCAST_MODE); +	config.tx_dbg_log_size  = __cpu_to_le32(TARGET_10_4_TX_DBG_LOG_SIZE); +	config.num_wds_entries  = __cpu_to_le32(TARGET_10_4_NUM_WDS_ENTRIES); +	config.dma_burst_size   = __cpu_to_le32(TARGET_10_4_DMA_BURST_SIZE); +	config.mac_aggr_delim   = __cpu_to_le32(TARGET_10_4_MAC_AGGR_DELIM); + +	config.rx_skip_defrag_timeout_dup_detection_check = +	  __cpu_to_le32(TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK); + +	config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG); +	config.gtk_offload_max_vdev = +			__cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV); +	config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC); +	config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS); +	config.max_peer_ext_stats = +			__cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS); +	config.smart_ant_cap = __cpu_to_le32(TARGET_10_4_SMART_ANT_CAP); + +	config.bk_minfree = __cpu_to_le32(TARGET_10_4_BK_MIN_FREE); +	config.be_minfree = __cpu_to_le32(TARGET_10_4_BE_MIN_FREE); +	config.vi_minfree = __cpu_to_le32(TARGET_10_4_VI_MIN_FREE); +	config.vo_minfree = __cpu_to_le32(TARGET_10_4_VO_MIN_FREE); + +	config.rx_batchmode = __cpu_to_le32(TARGET_10_4_RX_BATCH_MODE); +	config.tt_support = +			__cpu_to_le32(TARGET_10_4_THERMAL_THROTTLING_CONFIG); +	config.atf_config = __cpu_to_le32(TARGET_10_4_ATF_CONFIG); +	config.iphdr_pad_config = __cpu_to_le32(TARGET_10_4_IPHDR_PAD_CONFIG); +	config.qwrap_config = __cpu_to_le32(TARGET_10_4_QWRAP_CONFIG); + +	len = sizeof(*cmd) + +	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + +	buf = ath10k_wmi_alloc_skb(ar, len); +	if (!buf) +		return ERR_PTR(-ENOMEM); + +	cmd = (struct wmi_init_cmd_10_4 *)buf->data; +	memcpy(&cmd->resource_config, &config, sizeof(config)); +	ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); + +	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.4\n"); +	return buf; +} +  int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)  {  	if (arg->ie_len && !arg->ie) @@ -4172,7 +5308,6 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,  		| WMI_SCAN_EVENT_BSS_CHANNEL  		| WMI_SCAN_EVENT_FOREIGN_CHANNEL  		| WMI_SCAN_EVENT_DEQUEUED; -	arg->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES;  	arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;  	arg->n_bssids = 1;  	arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; @@ -5170,6 +6305,7 @@ static const struct wmi_ops wmi_ops = {  	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,  	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,  	.pull_swba = ath10k_wmi_op_pull_swba_ev, +	.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,  	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,  	.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,  	.pull_rdy = ath10k_wmi_op_pull_rdy_ev, @@ -5241,6 +6377,7 @@ static const struct wmi_ops wmi_10_1_ops = {  	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,  	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,  	.pull_swba = ath10k_wmi_op_pull_swba_ev, +	.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,  	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,  	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,  	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev, @@ -5306,6 +6443,7 @@ static const struct wmi_ops wmi_10_2_ops = {  	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,  	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,  	.pull_swba = ath10k_wmi_op_pull_swba_ev, +	.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,  	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,  	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,  	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev, @@ -5367,6 +6505,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {  	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,  	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,  	.pull_swba = ath10k_wmi_op_pull_swba_ev, +	.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,  	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,  	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,  	.pull_roam_ev = ath10k_wmi_op_pull_roam_ev, @@ -5412,9 +6551,73 @@ static const struct wmi_ops wmi_10_2_4_ops = {  	/* .gen_adaptive_qcs not implemented */  }; +static const struct wmi_ops wmi_10_4_ops = { +	.rx = ath10k_wmi_10_4_op_rx, +	.map_svc = wmi_10_4_svc_map, + +	.pull_scan = ath10k_wmi_op_pull_scan_ev, +	.pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, +	.pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev, +	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, +	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, +	.pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, +	.pull_phyerr_hdr = ath10k_wmi_10_4_op_pull_phyerr_ev_hdr, +	.pull_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev, +	.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, +	.pull_rdy = ath10k_wmi_op_pull_rdy_ev, +	.get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme, + +	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, +	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, +	.gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, +	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, +	.gen_init = ath10k_wmi_10_4_op_gen_init, +	.gen_start_scan = ath10k_wmi_op_gen_start_scan, +	.gen_stop_scan = ath10k_wmi_op_gen_stop_scan, +	.gen_vdev_create = ath10k_wmi_op_gen_vdev_create, +	.gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, +	.gen_vdev_start = ath10k_wmi_op_gen_vdev_start, +	.gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, +	.gen_vdev_up = ath10k_wmi_op_gen_vdev_up, +	.gen_vdev_down = ath10k_wmi_op_gen_vdev_down, +	.gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, +	.gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, +	.gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, +	.gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, +	.gen_peer_create = ath10k_wmi_op_gen_peer_create, +	.gen_peer_delete = ath10k_wmi_op_gen_peer_delete, +	.gen_peer_flush = ath10k_wmi_op_gen_peer_flush, +	.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, +	.gen_set_psmode = ath10k_wmi_op_gen_set_psmode, +	.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, +	.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, +	.gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, +	.gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, +	.gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, +	.gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, +	.gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, +	.gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, +	.gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, +	.gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, +	.gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, +	.gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, +	.gen_addba_send = ath10k_wmi_op_gen_addba_send, +	.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, +	.gen_delba_send = ath10k_wmi_op_gen_delba_send, + +	/* shared with 10.2 */ +	.gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, +}; +  int ath10k_wmi_attach(struct ath10k *ar)  {  	switch (ar->wmi.op_version) { +	case ATH10K_FW_WMI_OP_VERSION_10_4: +		ar->wmi.ops = &wmi_10_4_ops; +		ar->wmi.cmd = &wmi_10_4_cmd_map; +		ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; +		ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; +		break;  	case ATH10K_FW_WMI_OP_VERSION_10_2_4:  		ar->wmi.cmd = &wmi_10_2_4_cmd_map;  		ar->wmi.ops = &wmi_10_2_4_ops; @@ -5452,6 +6655,8 @@ int ath10k_wmi_attach(struct ath10k *ar)  	init_completion(&ar->wmi.service_ready);  	init_completion(&ar->wmi.unified_ready); +	INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work); +  	return 0;  } @@ -5459,6 +6664,11 @@ void ath10k_wmi_detach(struct ath10k *ar)  {  	int i; +	cancel_work_sync(&ar->svc_rdy_work); + +	if (ar->svc_rdy_skb) +		dev_kfree_skb(ar->svc_rdy_skb); +  	/* free the host memory chunks requested by firmware */  	for (i = 0; i < ar->wmi.num_mem_chunks; i++) {  		dma_free_coherent(ar->dev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cf44a3d080a3..52d35032d53e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -150,6 +150,12 @@ enum wmi_service {  	WMI_SERVICE_SAP_AUTH_OFFLOAD,  	WMI_SERVICE_ATF,  	WMI_SERVICE_COEX_GPIO, +	WMI_SERVICE_ENHANCED_PROXY_STA, +	WMI_SERVICE_TT, +	WMI_SERVICE_PEER_CACHING, +	WMI_SERVICE_AUX_SPECTRAL_INTF, +	WMI_SERVICE_AUX_CHAN_LOAD_INTF, +	WMI_SERVICE_BSS_CHANNEL_INFO_64,  	/* keep last */  	WMI_SERVICE_MAX, @@ -218,6 +224,51 @@ enum wmi_main_service {  	WMI_MAIN_SERVICE_TX_ENCAP,  }; +enum wmi_10_4_service { +	WMI_10_4_SERVICE_BEACON_OFFLOAD = 0, +	WMI_10_4_SERVICE_SCAN_OFFLOAD, +	WMI_10_4_SERVICE_ROAM_OFFLOAD, +	WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, +	WMI_10_4_SERVICE_STA_PWRSAVE, +	WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, +	WMI_10_4_SERVICE_AP_UAPSD, +	WMI_10_4_SERVICE_AP_DFS, +	WMI_10_4_SERVICE_11AC, +	WMI_10_4_SERVICE_BLOCKACK, +	WMI_10_4_SERVICE_PHYERR, +	WMI_10_4_SERVICE_BCN_FILTER, +	WMI_10_4_SERVICE_RTT, +	WMI_10_4_SERVICE_RATECTRL, +	WMI_10_4_SERVICE_WOW, +	WMI_10_4_SERVICE_RATECTRL_CACHE, +	WMI_10_4_SERVICE_IRAM_TIDS, +	WMI_10_4_SERVICE_BURST, +	WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, +	WMI_10_4_SERVICE_GTK_OFFLOAD, +	WMI_10_4_SERVICE_SCAN_SCH, +	WMI_10_4_SERVICE_CSA_OFFLOAD, +	WMI_10_4_SERVICE_CHATTER, +	WMI_10_4_SERVICE_COEX_FREQAVOID, +	WMI_10_4_SERVICE_PACKET_POWER_SAVE, +	WMI_10_4_SERVICE_FORCE_FW_HANG, +	WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, +	WMI_10_4_SERVICE_GPIO, +	WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +	WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +	WMI_10_4_SERVICE_STA_KEEP_ALIVE, +	WMI_10_4_SERVICE_TX_ENCAP, +	WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, +	WMI_10_4_SERVICE_EARLY_RX, +	WMI_10_4_SERVICE_ENHANCED_PROXY_STA, +	WMI_10_4_SERVICE_TT, +	WMI_10_4_SERVICE_ATF, +	WMI_10_4_SERVICE_PEER_CACHING, +	WMI_10_4_SERVICE_COEX_GPIO, +	WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, +	WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, +	WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, +}; +  static inline char *wmi_service_name(int service_id)  {  #define SVCSTR(x) case x: return #x @@ -299,6 +350,12 @@ static inline char *wmi_service_name(int service_id)  	SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD);  	SVCSTR(WMI_SERVICE_ATF);  	SVCSTR(WMI_SERVICE_COEX_GPIO); +	SVCSTR(WMI_SERVICE_ENHANCED_PROXY_STA); +	SVCSTR(WMI_SERVICE_TT); +	SVCSTR(WMI_SERVICE_PEER_CACHING); +	SVCSTR(WMI_SERVICE_AUX_SPECTRAL_INTF); +	SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); +	SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);  	default:  		return NULL;  	} @@ -437,6 +494,95 @@ static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,  	       WMI_SERVICE_TX_ENCAP, len);  } +static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, +				    size_t len) +{ +	SVCMAP(WMI_10_4_SERVICE_BEACON_OFFLOAD, +	       WMI_SERVICE_BEACON_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_SCAN_OFFLOAD, +	       WMI_SERVICE_SCAN_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_ROAM_OFFLOAD, +	       WMI_SERVICE_ROAM_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, +	       WMI_SERVICE_BCN_MISS_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_STA_PWRSAVE, +	       WMI_SERVICE_STA_PWRSAVE, len); +	SVCMAP(WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, +	       WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); +	SVCMAP(WMI_10_4_SERVICE_AP_UAPSD, +	       WMI_SERVICE_AP_UAPSD, len); +	SVCMAP(WMI_10_4_SERVICE_AP_DFS, +	       WMI_SERVICE_AP_DFS, len); +	SVCMAP(WMI_10_4_SERVICE_11AC, +	       WMI_SERVICE_11AC, len); +	SVCMAP(WMI_10_4_SERVICE_BLOCKACK, +	       WMI_SERVICE_BLOCKACK, len); +	SVCMAP(WMI_10_4_SERVICE_PHYERR, +	       WMI_SERVICE_PHYERR, len); +	SVCMAP(WMI_10_4_SERVICE_BCN_FILTER, +	       WMI_SERVICE_BCN_FILTER, len); +	SVCMAP(WMI_10_4_SERVICE_RTT, +	       WMI_SERVICE_RTT, len); +	SVCMAP(WMI_10_4_SERVICE_RATECTRL, +	       WMI_SERVICE_RATECTRL, len); +	SVCMAP(WMI_10_4_SERVICE_WOW, +	       WMI_SERVICE_WOW, len); +	SVCMAP(WMI_10_4_SERVICE_RATECTRL_CACHE, +	       WMI_SERVICE_RATECTRL_CACHE, len); +	SVCMAP(WMI_10_4_SERVICE_IRAM_TIDS, +	       WMI_SERVICE_IRAM_TIDS, len); +	SVCMAP(WMI_10_4_SERVICE_BURST, +	       WMI_SERVICE_BURST, len); +	SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, +	       WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); +	SVCMAP(WMI_10_4_SERVICE_GTK_OFFLOAD, +	       WMI_SERVICE_GTK_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_SCAN_SCH, +	       WMI_SERVICE_SCAN_SCH, len); +	SVCMAP(WMI_10_4_SERVICE_CSA_OFFLOAD, +	       WMI_SERVICE_CSA_OFFLOAD, len); +	SVCMAP(WMI_10_4_SERVICE_CHATTER, +	       WMI_SERVICE_CHATTER, len); +	SVCMAP(WMI_10_4_SERVICE_COEX_FREQAVOID, +	       WMI_SERVICE_COEX_FREQAVOID, len); +	SVCMAP(WMI_10_4_SERVICE_PACKET_POWER_SAVE, +	       WMI_SERVICE_PACKET_POWER_SAVE, len); +	SVCMAP(WMI_10_4_SERVICE_FORCE_FW_HANG, +	       WMI_SERVICE_FORCE_FW_HANG, len); +	SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, +	       WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); +	SVCMAP(WMI_10_4_SERVICE_GPIO, +	       WMI_SERVICE_GPIO, len); +	SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, +	       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); +	SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, +	       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); +	SVCMAP(WMI_10_4_SERVICE_STA_KEEP_ALIVE, +	       WMI_SERVICE_STA_KEEP_ALIVE, len); +	SVCMAP(WMI_10_4_SERVICE_TX_ENCAP, +	       WMI_SERVICE_TX_ENCAP, len); +	SVCMAP(WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, +	       WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); +	SVCMAP(WMI_10_4_SERVICE_EARLY_RX, +	       WMI_SERVICE_EARLY_RX, len); +	SVCMAP(WMI_10_4_SERVICE_ENHANCED_PROXY_STA, +	       WMI_SERVICE_ENHANCED_PROXY_STA, len); +	SVCMAP(WMI_10_4_SERVICE_TT, +	       WMI_SERVICE_TT, len); +	SVCMAP(WMI_10_4_SERVICE_ATF, +	       WMI_SERVICE_ATF, len); +	SVCMAP(WMI_10_4_SERVICE_PEER_CACHING, +	       WMI_SERVICE_PEER_CACHING, len); +	SVCMAP(WMI_10_4_SERVICE_COEX_GPIO, +	       WMI_SERVICE_COEX_GPIO, len); +	SVCMAP(WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, +	       WMI_SERVICE_AUX_SPECTRAL_INTF, len); +	SVCMAP(WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, +	       WMI_SERVICE_AUX_CHAN_LOAD_INTF, len); +	SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, +	       WMI_SERVICE_BSS_CHANNEL_INFO_64, len); +} +  #undef SVCMAP  /* 2 word representation of MAC addr */ @@ -565,6 +711,48 @@ struct wmi_cmd_map {  	u32 tdls_set_state_cmdid;  	u32 tdls_peer_update_cmdid;  	u32 adaptive_qcs_cmdid; +	u32 scan_update_request_cmdid; +	u32 vdev_standby_response_cmdid; +	u32 vdev_resume_response_cmdid; +	u32 wlan_peer_caching_add_peer_cmdid; +	u32 wlan_peer_caching_evict_peer_cmdid; +	u32 wlan_peer_caching_restore_peer_cmdid; +	u32 wlan_peer_caching_print_all_peers_info_cmdid; +	u32 peer_update_wds_entry_cmdid; +	u32 peer_add_proxy_sta_entry_cmdid; +	u32 rtt_keepalive_cmdid; +	u32 oem_req_cmdid; +	u32 nan_cmdid; +	u32 vdev_ratemask_cmdid; +	u32 qboost_cfg_cmdid; +	u32 pdev_smart_ant_enable_cmdid; +	u32 pdev_smart_ant_set_rx_antenna_cmdid; +	u32 peer_smart_ant_set_tx_antenna_cmdid; +	u32 peer_smart_ant_set_train_info_cmdid; +	u32 peer_smart_ant_set_node_config_ops_cmdid; +	u32 pdev_set_antenna_switch_table_cmdid; +	u32 pdev_set_ctl_table_cmdid; +	u32 pdev_set_mimogain_table_cmdid; +	u32 pdev_ratepwr_table_cmdid; +	u32 pdev_ratepwr_chainmsk_table_cmdid; +	u32 pdev_fips_cmdid; +	u32 tt_set_conf_cmdid; +	u32 fwtest_cmdid; +	u32 vdev_atf_request_cmdid; +	u32 peer_atf_request_cmdid; +	u32 pdev_get_ani_cck_config_cmdid; +	u32 pdev_get_ani_ofdm_config_cmdid; +	u32 pdev_reserve_ast_entry_cmdid; +	u32 pdev_get_nfcal_power_cmdid; +	u32 pdev_get_tpc_cmdid; +	u32 pdev_get_ast_info_cmdid; +	u32 vdev_set_dscp_tid_map_cmdid; +	u32 pdev_get_info_cmdid; +	u32 vdev_get_info_cmdid; +	u32 vdev_filter_neighbor_rx_packets_cmdid; +	u32 mu_cal_start_cmdid; +	u32 set_cca_params_cmdid; +	u32 pdev_bss_chan_info_request_cmdid;  };  /* @@ -1220,6 +1408,216 @@ enum wmi_10_2_event_id {  	WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,  }; +enum wmi_10_4_cmd_id { +	WMI_10_4_START_CMDID = 0x9000, +	WMI_10_4_END_CMDID = 0x9FFF, +	WMI_10_4_INIT_CMDID, +	WMI_10_4_START_SCAN_CMDID = WMI_10_4_START_CMDID, +	WMI_10_4_STOP_SCAN_CMDID, +	WMI_10_4_SCAN_CHAN_LIST_CMDID, +	WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, +	WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, +	WMI_10_4_ECHO_CMDID, +	WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, +	WMI_10_4_PDEV_SET_CHANNEL_CMDID, +	WMI_10_4_PDEV_SET_PARAM_CMDID, +	WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, +	WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, +	WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, +	WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, +	WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, +	WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, +	WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, +	WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, +	WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, +	WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, +	WMI_10_4_VDEV_CREATE_CMDID, +	WMI_10_4_VDEV_DELETE_CMDID, +	WMI_10_4_VDEV_START_REQUEST_CMDID, +	WMI_10_4_VDEV_RESTART_REQUEST_CMDID, +	WMI_10_4_VDEV_UP_CMDID, +	WMI_10_4_VDEV_STOP_CMDID, +	WMI_10_4_VDEV_DOWN_CMDID, +	WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, +	WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, +	WMI_10_4_VDEV_SET_PARAM_CMDID, +	WMI_10_4_VDEV_INSTALL_KEY_CMDID, +	WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, +	WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, +	WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, +	WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, +	WMI_10_4_PEER_CREATE_CMDID, +	WMI_10_4_PEER_DELETE_CMDID, +	WMI_10_4_PEER_FLUSH_TIDS_CMDID, +	WMI_10_4_PEER_SET_PARAM_CMDID, +	WMI_10_4_PEER_ASSOC_CMDID, +	WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, +	WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, +	WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, +	WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, +	WMI_10_4_PEER_MCAST_GROUP_CMDID, +	WMI_10_4_BCN_TX_CMDID, +	WMI_10_4_PDEV_SEND_BCN_CMDID, +	WMI_10_4_BCN_PRB_TMPL_CMDID, +	WMI_10_4_BCN_FILTER_RX_CMDID, +	WMI_10_4_PRB_REQ_FILTER_RX_CMDID, +	WMI_10_4_MGMT_TX_CMDID, +	WMI_10_4_PRB_TMPL_CMDID, +	WMI_10_4_ADDBA_CLEAR_RESP_CMDID, +	WMI_10_4_ADDBA_SEND_CMDID, +	WMI_10_4_ADDBA_STATUS_CMDID, +	WMI_10_4_DELBA_SEND_CMDID, +	WMI_10_4_ADDBA_SET_RESP_CMDID, +	WMI_10_4_SEND_SINGLEAMSDU_CMDID, +	WMI_10_4_STA_POWERSAVE_MODE_CMDID, +	WMI_10_4_STA_POWERSAVE_PARAM_CMDID, +	WMI_10_4_STA_MIMO_PS_MODE_CMDID, +	WMI_10_4_DBGLOG_CFG_CMDID, +	WMI_10_4_PDEV_DFS_ENABLE_CMDID, +	WMI_10_4_PDEV_DFS_DISABLE_CMDID, +	WMI_10_4_PDEV_QVIT_CMDID, +	WMI_10_4_ROAM_SCAN_MODE, +	WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, +	WMI_10_4_ROAM_SCAN_PERIOD, +	WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +	WMI_10_4_ROAM_AP_PROFILE, +	WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, +	WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, +	WMI_10_4_OFL_SCAN_PERIOD, +	WMI_10_4_P2P_DEV_SET_DEVICE_INFO, +	WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, +	WMI_10_4_P2P_GO_SET_BEACON_IE, +	WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, +	WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, +	WMI_10_4_AP_PS_PEER_PARAM_CMDID, +	WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, +	WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, +	WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, +	WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +	WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +	WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +	WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +	WMI_10_4_PDEV_SUSPEND_CMDID, +	WMI_10_4_PDEV_RESUME_CMDID, +	WMI_10_4_ADD_BCN_FILTER_CMDID, +	WMI_10_4_RMV_BCN_FILTER_CMDID, +	WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, +	WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, +	WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +	WMI_10_4_WOW_ENABLE_CMDID, +	WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +	WMI_10_4_RTT_MEASREQ_CMDID, +	WMI_10_4_RTT_TSF_CMDID, +	WMI_10_4_RTT_KEEPALIVE_CMDID, +	WMI_10_4_OEM_REQ_CMDID, +	WMI_10_4_NAN_CMDID, +	WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +	WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +	WMI_10_4_REQUEST_STATS_CMDID, +	WMI_10_4_GPIO_CONFIG_CMDID, +	WMI_10_4_GPIO_OUTPUT_CMDID, +	WMI_10_4_VDEV_RATEMASK_CMDID, +	WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, +	WMI_10_4_GTK_OFFLOAD_CMDID, +	WMI_10_4_QBOOST_CFG_CMDID, +	WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, +	WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, +	WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, +	WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, +	WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, +	WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, +	WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, +	WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, +	WMI_10_4_FORCE_FW_HANG_CMDID, +	WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, +	WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, +	WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, +	WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, +	WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, +	WMI_10_4_PDEV_FIPS_CMDID, +	WMI_10_4_TT_SET_CONF_CMDID, +	WMI_10_4_FWTEST_CMDID, +	WMI_10_4_VDEV_ATF_REQUEST_CMDID, +	WMI_10_4_PEER_ATF_REQUEST_CMDID, +	WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, +	WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, +	WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, +	WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, +	WMI_10_4_PDEV_GET_TPC_CMDID, +	WMI_10_4_PDEV_GET_AST_INFO_CMDID, +	WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, +	WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, +	WMI_10_4_PDEV_GET_INFO_CMDID, +	WMI_10_4_VDEV_GET_INFO_CMDID, +	WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, +	WMI_10_4_MU_CAL_START_CMDID, +	WMI_10_4_SET_CCA_PARAMS_CMDID, +	WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, +	WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, +}; + +enum wmi_10_4_event_id { +	WMI_10_4_SERVICE_READY_EVENTID = 0x8000, +	WMI_10_4_READY_EVENTID, +	WMI_10_4_DEBUG_MESG_EVENTID, +	WMI_10_4_START_EVENTID = 0x9000, +	WMI_10_4_END_EVENTID = 0x9FFF, +	WMI_10_4_SCAN_EVENTID = WMI_10_4_START_EVENTID, +	WMI_10_4_ECHO_EVENTID, +	WMI_10_4_UPDATE_STATS_EVENTID, +	WMI_10_4_INST_RSSI_STATS_EVENTID, +	WMI_10_4_VDEV_START_RESP_EVENTID, +	WMI_10_4_VDEV_STANDBY_REQ_EVENTID, +	WMI_10_4_VDEV_RESUME_REQ_EVENTID, +	WMI_10_4_VDEV_STOPPED_EVENTID, +	WMI_10_4_PEER_STA_KICKOUT_EVENTID, +	WMI_10_4_HOST_SWBA_EVENTID, +	WMI_10_4_TBTTOFFSET_UPDATE_EVENTID, +	WMI_10_4_MGMT_RX_EVENTID, +	WMI_10_4_CHAN_INFO_EVENTID, +	WMI_10_4_PHYERR_EVENTID, +	WMI_10_4_ROAM_EVENTID, +	WMI_10_4_PROFILE_MATCH, +	WMI_10_4_DEBUG_PRINT_EVENTID, +	WMI_10_4_PDEV_QVIT_EVENTID, +	WMI_10_4_WLAN_PROFILE_DATA_EVENTID, +	WMI_10_4_RTT_MEASUREMENT_REPORT_EVENTID, +	WMI_10_4_TSF_MEASUREMENT_REPORT_EVENTID, +	WMI_10_4_RTT_ERROR_REPORT_EVENTID, +	WMI_10_4_RTT_KEEPALIVE_EVENTID, +	WMI_10_4_OEM_CAPABILITY_EVENTID, +	WMI_10_4_OEM_MEASUREMENT_REPORT_EVENTID, +	WMI_10_4_OEM_ERROR_REPORT_EVENTID, +	WMI_10_4_NAN_EVENTID, +	WMI_10_4_WOW_WAKEUP_HOST_EVENTID, +	WMI_10_4_GTK_OFFLOAD_STATUS_EVENTID, +	WMI_10_4_GTK_REKEY_FAIL_EVENTID, +	WMI_10_4_DCS_INTERFERENCE_EVENTID, +	WMI_10_4_PDEV_TPC_CONFIG_EVENTID, +	WMI_10_4_CSA_HANDLING_EVENTID, +	WMI_10_4_GPIO_INPUT_EVENTID, +	WMI_10_4_PEER_RATECODE_LIST_EVENTID, +	WMI_10_4_GENERIC_BUFFER_EVENTID, +	WMI_10_4_MCAST_BUF_RELEASE_EVENTID, +	WMI_10_4_MCAST_LIST_AGEOUT_EVENTID, +	WMI_10_4_VDEV_GET_KEEPALIVE_EVENTID, +	WMI_10_4_WDS_PEER_EVENTID, +	WMI_10_4_PEER_STA_PS_STATECHG_EVENTID, +	WMI_10_4_PDEV_FIPS_EVENTID, +	WMI_10_4_TT_STATS_EVENTID, +	WMI_10_4_PDEV_CHANNEL_HOPPING_EVENTID, +	WMI_10_4_PDEV_ANI_CCK_LEVEL_EVENTID, +	WMI_10_4_PDEV_ANI_OFDM_LEVEL_EVENTID, +	WMI_10_4_PDEV_RESERVE_AST_ENTRY_EVENTID, +	WMI_10_4_PDEV_NFCAL_POWER_EVENTID, +	WMI_10_4_PDEV_TPC_EVENTID, +	WMI_10_4_PDEV_GET_AST_INFO_EVENTID, +	WMI_10_4_PDEV_TEMPERATURE_EVENTID, +	WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, +	WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID, +	WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, +}; +  enum wmi_phy_mode {  	MODE_11A        = 0,   /* 11a Mode */  	MODE_11G        = 1,   /* 11b/g Mode */ @@ -1349,7 +1747,8 @@ enum wmi_channel_change_cause {  /* Indicate reason for channel switch */  #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13) -#define WMI_MAX_SPATIAL_STREAM   3 +#define WMI_MAX_SPATIAL_STREAM        3 /* default max ss */ +#define WMI_10_4_MAX_SPATIAL_STREAM   4  /* HT Capabilities*/  #define WMI_HT_CAP_ENABLED                0x0001   /* HT Enabled/ disabled */ @@ -1979,8 +2378,224 @@ struct wmi_resource_config_10_2 {  	__le32 feature_mask;  } __packed; -#define NUM_UNITS_IS_NUM_VDEVS   0x1 -#define NUM_UNITS_IS_NUM_PEERS   0x2 +#define NUM_UNITS_IS_NUM_VDEVS         BIT(0) +#define NUM_UNITS_IS_NUM_PEERS         BIT(1) +#define NUM_UNITS_IS_NUM_ACTIVE_PEERS  BIT(2) + +struct wmi_resource_config_10_4 { +	/* Number of virtual devices (VAPs) to support */ +	__le32 num_vdevs; + +	/* Number of peer nodes to support */ +	__le32 num_peers; + +	/* Number of active peer nodes to support */ +	__le32 num_active_peers; + +	/* In offload mode, target supports features like WOW, chatter and other +	 * protocol offloads. In order to support them some functionalities like +	 * reorder buffering, PN checking need to be done in target. +	 * This determines maximum number of peers supported by target in +	 * offload mode. +	 */ +	__le32 num_offload_peers; + +	/* Number of reorder buffers available for doing target based reorder +	 * Rx reorder buffering +	 */ +	__le32 num_offload_reorder_buffs; + +	/* Number of keys per peer */ +	__le32 num_peer_keys; + +	/* Total number of TX/RX data TIDs */ +	__le32 num_tids; + +	/* Max skid for resolving hash collisions. +	 * The address search table is sparse, so that if two MAC addresses +	 * result in the same hash value, the second of these conflicting +	 * entries can slide to the next index in the address search table, +	 * and use it, if it is unoccupied.  This ast_skid_limit parameter +	 * specifies the upper bound on how many subsequent indices to search +	 * over to find an unoccupied space. +	 */ +	__le32 ast_skid_limit; + +	/* The nominal chain mask for transmit. +	 * The chain mask may be modified dynamically, e.g. to operate AP tx +	 * with a reduced number of chains if no clients are associated. +	 * This configuration parameter specifies the nominal chain-mask that +	 * should be used when not operating with a reduced set of tx chains. +	 */ +	__le32 tx_chain_mask; + +	/* The nominal chain mask for receive. +	 * The chain mask may be modified dynamically, e.g. for a client to use +	 * a reduced number of chains for receive if the traffic to the client +	 * is low enough that it doesn't require downlink MIMO or antenna +	 * diversity. This configuration parameter specifies the nominal +	 * chain-mask that should be used when not operating with a reduced +	 * set of rx chains. +	 */ +	__le32 rx_chain_mask; + +	/* What rx reorder timeout (ms) to use for the AC. +	 * Each WMM access class (voice, video, best-effort, background) will +	 * have its own timeout value to dictate how long to wait for missing +	 * rx MPDUs to arrive before flushing subsequent MPDUs that have already +	 * been received. This parameter specifies the timeout in milliseconds +	 * for each class. +	 */ +	__le32 rx_timeout_pri[4]; + +	/* What mode the rx should decap packets to. +	 * MAC can decap to RAW (no decap), native wifi or Ethernet types. +	 * This setting also determines the default TX behavior, however TX +	 * behavior can be modified on a per VAP basis during VAP init +	 */ +	__le32 rx_decap_mode; + +	__le32 scan_max_pending_req; + +	__le32 bmiss_offload_max_vdev; + +	__le32 roam_offload_max_vdev; + +	__le32 roam_offload_max_ap_profiles; + +	/* How many groups to use for mcast->ucast conversion. +	 * The target's WAL maintains a table to hold information regarding +	 * which peers belong to a given multicast group, so that if +	 * multicast->unicast conversion is enabled, the target can convert +	 * multicast tx frames to a series of unicast tx frames, to each peer +	 * within the multicast group. This num_mcast_groups configuration +	 * parameter tells the target how many multicast groups to provide +	 * storage for within its multicast group membership table. +	 */ +	__le32 num_mcast_groups; + +	/* Size to alloc for the mcast membership table. +	 * This num_mcast_table_elems configuration parameter tells the target +	 * how many peer elements it needs to provide storage for in its +	 * multicast group membership table. These multicast group membership +	 * table elements are shared by the multicast groups stored within +	 * the table. +	 */ +	__le32 num_mcast_table_elems; + +	/* Whether/how to do multicast->unicast conversion. +	 * This configuration parameter specifies whether the target should +	 * perform multicast --> unicast conversion on transmit, and if so, +	 * what to do if it finds no entries in its multicast group membership +	 * table for the multicast IP address in the tx frame. +	 * Configuration value: +	 * 0 -> Do not perform multicast to unicast conversion. +	 * 1 -> Convert multicast frames to unicast, if the IP multicast address +	 *      from the tx frame is found in the multicast group membership +	 *      table.  If the IP multicast address is not found, drop the frame +	 * 2 -> Convert multicast frames to unicast, if the IP multicast address +	 *      from the tx frame is found in the multicast group membership +	 *      table.  If the IP multicast address is not found, transmit the +	 *      frame as multicast. +	 */ +	__le32 mcast2ucast_mode; + +	/* How much memory to allocate for a tx PPDU dbg log. +	 * This parameter controls how much memory the target will allocate to +	 * store a log of tx PPDU meta-information (how large the PPDU was, +	 * when it was sent, whether it was successful, etc.) +	 */ +	__le32 tx_dbg_log_size; + +	/* How many AST entries to be allocated for WDS */ +	__le32 num_wds_entries; + +	/* MAC DMA burst size. 0 -default, 1 -256B */ +	__le32 dma_burst_size; + +	/* Fixed delimiters to be inserted after every MPDU to account for +	 * interface latency to avoid underrun. +	 */ +	__le32 mac_aggr_delim; + +	/* Determine whether target is responsible for detecting duplicate +	 * non-aggregate MPDU and timing out stale fragments. A-MPDU reordering +	 * is always performed on the target. +	 * +	 * 0: target responsible for frag timeout and dup checking +	 * 1: host responsible for frag timeout and dup checking +	 */ +	__le32 rx_skip_defrag_timeout_dup_detection_check; + +	/* Configuration for VoW : No of Video nodes to be supported and max +	 * no of descriptors for each video link (node). +	 */ +	__le32 vow_config; + +	/* Maximum vdev that could use gtk offload */ +	__le32 gtk_offload_max_vdev; + +	/* Number of msdu descriptors target should use */ +	__le32 num_msdu_desc; + +	/* Max number of tx fragments per MSDU. +	 * This parameter controls the max number of tx fragments per MSDU. +	 * This will passed by target as part of the WMI_SERVICE_READY event +	 * and is overridden by the OS shim as required. +	 */ +	__le32 max_frag_entries; + +	/* Max number of extended peer stats. +	 * This parameter controls the max number of peers for which extended +	 * statistics are supported by target +	 */ +	__le32 max_peer_ext_stats; + +	/* Smart antenna capabilities information. +	 * 1 - Smart antenna is enabled +	 * 0 - Smart antenna is disabled +	 * In future this can contain smart antenna specific capabilities. +	 */ +	__le32 smart_ant_cap; + +	/* User can configure the buffers allocated for each AC (BE, BK, VI, VO) +	 * during init. +	 */ +	__le32 bk_minfree; +	__le32 be_minfree; +	__le32 vi_minfree; +	__le32 vo_minfree; + +	/* Rx batch mode capability. +	 * 1 - Rx batch mode enabled +	 * 0 - Rx batch mode disabled +	 */ +	__le32 rx_batchmode; + +	/* Thermal throttling capability. +	 * 1 - Capable of thermal throttling +	 * 0 - Not capable of thermal throttling +	 */ +	__le32 tt_support; + +	/* ATF configuration. +	 * 1  - Enable ATF +	 * 0  - Disable ATF +	 */ +	__le32 atf_config; + +	/* Configure padding to manage IP header un-alignment +	 * 1  - Enable padding +	 * 0  - Disable padding +	 */ +	__le32 iphdr_pad_config; + +	/* qwrap configuration +	 * 1  - This is qwrap configuration +	 * 0  - This is not qwrap +	 */ +	__le32 qwrap_config; +} __packed;  /* strucutre describing host memory chunk. */  struct host_memory_chunk { @@ -2014,6 +2629,11 @@ struct wmi_init_cmd_10_2 {  	struct wmi_host_mem_chunks mem_chunks;  } __packed; +struct wmi_init_cmd_10_4 { +	struct wmi_resource_config_10_4 resource_config; +	struct wmi_host_mem_chunks mem_chunks; +} __packed; +  struct wmi_chan_list_entry {  	__le16 freq;  	u8 phy_mode; /* valid for 10.2 only */ @@ -2260,15 +2880,17 @@ enum wmi_bss_filter {  };  enum wmi_scan_event_type { -	WMI_SCAN_EVENT_STARTED         = 0x1, -	WMI_SCAN_EVENT_COMPLETED       = 0x2, -	WMI_SCAN_EVENT_BSS_CHANNEL     = 0x4, -	WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, -	WMI_SCAN_EVENT_DEQUEUED        = 0x10, -	WMI_SCAN_EVENT_PREEMPTED       = 0x20, /* possibly by high-prio scan */ -	WMI_SCAN_EVENT_START_FAILED    = 0x40, -	WMI_SCAN_EVENT_RESTARTED       = 0x80, -	WMI_SCAN_EVENT_MAX             = 0x8000 +	WMI_SCAN_EVENT_STARTED              = BIT(0), +	WMI_SCAN_EVENT_COMPLETED            = BIT(1), +	WMI_SCAN_EVENT_BSS_CHANNEL          = BIT(2), +	WMI_SCAN_EVENT_FOREIGN_CHANNEL      = BIT(3), +	WMI_SCAN_EVENT_DEQUEUED             = BIT(4), +	/* possibly by high-prio scan */ +	WMI_SCAN_EVENT_PREEMPTED            = BIT(5), +	WMI_SCAN_EVENT_START_FAILED         = BIT(6), +	WMI_SCAN_EVENT_RESTARTED            = BIT(7), +	WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = BIT(8), +	WMI_SCAN_EVENT_MAX                  = BIT(15),  };  enum wmi_scan_completion_reason { @@ -2276,6 +2898,7 @@ enum wmi_scan_completion_reason {  	WMI_SCAN_REASON_CANCELLED,  	WMI_SCAN_REASON_PREEMPTED,  	WMI_SCAN_REASON_TIMEDOUT, +	WMI_SCAN_REASON_INTERNAL_FAILURE,  	WMI_SCAN_REASON_MAX,  }; @@ -2329,15 +2952,40 @@ struct wmi_mgmt_rx_event_v2 {  	u8 buf[0];  } __packed; +struct wmi_10_4_mgmt_rx_hdr { +	__le32 channel; +	__le32 snr; +	    u8 rssi_ctl[4]; +	__le32 rate; +	__le32 phy_mode; +	__le32 buf_len; +	__le32 status; +} __packed; + +struct wmi_10_4_mgmt_rx_event { +	struct wmi_10_4_mgmt_rx_hdr hdr; +	u8 buf[0]; +} __packed; +  #define WMI_RX_STATUS_OK			0x00  #define WMI_RX_STATUS_ERR_CRC			0x01  #define WMI_RX_STATUS_ERR_DECRYPT		0x08  #define WMI_RX_STATUS_ERR_MIC			0x10  #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS	0x20 -#define PHY_ERROR_SPECTRAL_SCAN		0x26 -#define PHY_ERROR_FALSE_RADAR_EXT		0x24 -#define PHY_ERROR_RADAR				0x05 +#define PHY_ERROR_GEN_SPECTRAL_SCAN		0x26 +#define PHY_ERROR_GEN_FALSE_RADAR_EXT		0x24 +#define PHY_ERROR_GEN_RADAR			0x05 + +#define PHY_ERROR_10_4_RADAR_MASK               0x4 +#define PHY_ERROR_10_4_SPECTRAL_SCAN_MASK       0x4000000 + +enum phy_err_type { +	PHY_ERROR_UNKNOWN, +	PHY_ERROR_SPECTRAL_SCAN, +	PHY_ERROR_FALSE_RADAR_EXT, +	PHY_ERROR_RADAR +};  struct wmi_phyerr {  	__le32 tsf_timestamp; @@ -2360,6 +3008,23 @@ struct wmi_phyerr_event {  	struct wmi_phyerr phyerrs[0];  } __packed; +struct wmi_10_4_phyerr_event { +	__le32 tsf_l32; +	__le32 tsf_u32; +	__le16 freq1; +	__le16 freq2; +	u8 rssi_combined; +	u8 chan_width_mhz; +	u8 phy_err_code; +	u8 rsvd0; +	__le32 rssi_chains[4]; +	__le16 nf_chains[4]; +	__le32 phy_err_mask[2]; +	__le32 tsf_timestamp; +	__le32 buf_len; +	u8 buf[0]; +} __packed; +  #define PHYERR_TLV_SIG				0xBB  #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT	0xFB  #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY	0xF8 @@ -2613,6 +3278,48 @@ struct wmi_pdev_param_map {  	u32 burst_dur;  	u32 burst_enable;  	u32 cal_period; +	u32 aggr_burst; +	u32 rx_decap_mode; +	u32 smart_antenna_default_antenna; +	u32 igmpmld_override; +	u32 igmpmld_tid; +	u32 antenna_gain; +	u32 rx_filter; +	u32 set_mcast_to_ucast_tid; +	u32 proxy_sta_mode; +	u32 set_mcast2ucast_mode; +	u32 set_mcast2ucast_buffer; +	u32 remove_mcast2ucast_buffer; +	u32 peer_sta_ps_statechg_enable; +	u32 igmpmld_ac_override; +	u32 block_interbss; +	u32 set_disable_reset_cmdid; +	u32 set_msdu_ttl_cmdid; +	u32 set_ppdu_duration_cmdid; +	u32 txbf_sound_period_cmdid; +	u32 set_promisc_mode_cmdid; +	u32 set_burst_mode_cmdid; +	u32 en_stats; +	u32 mu_group_policy; +	u32 noise_detection; +	u32 noise_threshold; +	u32 dpd_enable; +	u32 set_mcast_bcast_echo; +	u32 atf_strict_sch; +	u32 atf_sched_duration; +	u32 ant_plzn; +	u32 mgmt_retry_limit; +	u32 sensitivity_level; +	u32 signed_txpower_2g; +	u32 signed_txpower_5g; +	u32 enable_per_tid_amsdu; +	u32 enable_per_tid_ampdu; +	u32 cca_threshold; +	u32 rts_fixed_rate; +	u32 pdev_reset; +	u32 wapi_mbssid_offset; +	u32 arp_srcaddr; +	u32 arp_dstaddr;  };  #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -2828,6 +3535,100 @@ enum wmi_10x_pdev_param {  	WMI_10X_PDEV_PARAM_CAL_PERIOD  }; +enum wmi_10_4_pdev_param { +	WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK = 0x1, +	WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, +	WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, +	WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, +	WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, +	WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, +	WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, +	WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +	WMI_10_4_PDEV_PARAM_PROTECTION_MODE, +	WMI_10_4_PDEV_PARAM_DYNAMIC_BW, +	WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +	WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, +	WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, +	WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, +	WMI_10_4_PDEV_PARAM_LTR_ENABLE, +	WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, +	WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, +	WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, +	WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, +	WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +	WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +	WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, +	WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +	WMI_10_4_PDEV_PARAM_L1SS_ENABLE, +	WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, +	WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, +	WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, +	WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +	WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, +	WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +	WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +	WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +	WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +	WMI_10_4_PDEV_PARAM_PMF_QOS, +	WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, +	WMI_10_4_PDEV_PARAM_DCS, +	WMI_10_4_PDEV_PARAM_ANI_ENABLE, +	WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, +	WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, +	WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, +	WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, +	WMI_10_4_PDEV_PARAM_DYNTXCHAIN, +	WMI_10_4_PDEV_PARAM_PROXY_STA, +	WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, +	WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, +	WMI_10_4_PDEV_PARAM_AGGR_BURST, +	WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, +	WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, +	WMI_10_4_PDEV_PARAM_BURST_DUR, +	WMI_10_4_PDEV_PARAM_BURST_ENABLE, +	WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, +	WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, +	WMI_10_4_PDEV_PARAM_IGMPMLD_TID, +	WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, +	WMI_10_4_PDEV_PARAM_RX_FILTER, +	WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, +	WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, +	WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, +	WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, +	WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, +	WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, +	WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, +	WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, +	WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, +	WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, +	WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, +	WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, +	WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, +	WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, +	WMI_10_4_PDEV_PARAM_EN_STATS, +	WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, +	WMI_10_4_PDEV_PARAM_NOISE_DETECTION, +	WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, +	WMI_10_4_PDEV_PARAM_DPD_ENABLE, +	WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, +	WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, +	WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, +	WMI_10_4_PDEV_PARAM_ANT_PLZN, +	WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, +	WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, +	WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, +	WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, +	WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, +	WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, +	WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, +	WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, +	WMI_10_4_PDEV_PARAM_CAL_PERIOD, +	WMI_10_4_PDEV_PARAM_PDEV_RESET, +	WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, +	WMI_10_4_PDEV_PARAM_ARP_SRCADDR, +	WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; +  struct wmi_pdev_set_param_cmd {  	__le32 param_id;  	__le32 param_value; @@ -3506,6 +4307,22 @@ struct wmi_vdev_param_map {  	u32 drop_unencry;  	u32 tx_encap_type;  	u32 ap_detect_out_of_sync_sleeping_sta_time_secs; +	u32 rc_num_retries; +	u32 cabq_maxdur; +	u32 mfptest_set; +	u32 rts_fixed_rate; +	u32 vht_sgimask; +	u32 vht80_ratemask; +	u32 early_rx_adjust_enable; +	u32 early_rx_tgt_bmiss_num; +	u32 early_rx_bmiss_sample_cycle; +	u32 early_rx_slop_step; +	u32 early_rx_init_slop; +	u32 early_rx_adjust_pause; +	u32 proxy_sta; +	u32 meru_vc; +	u32 rx_decap_type; +	u32 bw_nss_ratemask;  };  #define WMI_VDEV_PARAM_UNSUPPORTED 0 @@ -3764,11 +4581,85 @@ enum wmi_10x_vdev_param {  	WMI_10X_VDEV_PARAM_VHT80_RATEMASK,  }; +enum wmi_10_4_vdev_param { +	WMI_10_4_VDEV_PARAM_RTS_THRESHOLD = 0x1, +	WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +	WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, +	WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, +	WMI_10_4_VDEV_PARAM_MULTICAST_RATE, +	WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, +	WMI_10_4_VDEV_PARAM_SLOT_TIME, +	WMI_10_4_VDEV_PARAM_PREAMBLE, +	WMI_10_4_VDEV_PARAM_SWBA_TIME, +	WMI_10_4_VDEV_STATS_UPDATE_PERIOD, +	WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, +	WMI_10_4_VDEV_HOST_SWBA_INTERVAL, +	WMI_10_4_VDEV_PARAM_DTIM_PERIOD, +	WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +	WMI_10_4_VDEV_PARAM_WDS, +	WMI_10_4_VDEV_PARAM_ATIM_WINDOW, +	WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, +	WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, +	WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, +	WMI_10_4_VDEV_PARAM_FEATURE_WMM, +	WMI_10_4_VDEV_PARAM_CHWIDTH, +	WMI_10_4_VDEV_PARAM_CHEXTOFFSET, +	WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, +	WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, +	WMI_10_4_VDEV_PARAM_MGMT_RATE, +	WMI_10_4_VDEV_PARAM_PROTECTION_MODE, +	WMI_10_4_VDEV_PARAM_FIXED_RATE, +	WMI_10_4_VDEV_PARAM_SGI, +	WMI_10_4_VDEV_PARAM_LDPC, +	WMI_10_4_VDEV_PARAM_TX_STBC, +	WMI_10_4_VDEV_PARAM_RX_STBC, +	WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, +	WMI_10_4_VDEV_PARAM_DEF_KEYID, +	WMI_10_4_VDEV_PARAM_NSS, +	WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, +	WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, +	WMI_10_4_VDEV_PARAM_MCAST_INDICATE, +	WMI_10_4_VDEV_PARAM_DHCP_INDICATE, +	WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +	WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +	WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +	WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +	WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, +	WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, +	WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, +	WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, +	WMI_10_4_VDEV_PARAM_TXBF, +	WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, +	WMI_10_4_VDEV_PARAM_DROP_UNENCRY, +	WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, +	WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +	WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, +	WMI_10_4_VDEV_PARAM_MFPTEST_SET, +	WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, +	WMI_10_4_VDEV_PARAM_VHT_SGIMASK, +	WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, +	WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, +	WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, +	WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, +	WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, +	WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, +	WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, +	WMI_10_4_VDEV_PARAM_PROXY_STA, +	WMI_10_4_VDEV_PARAM_MERU_VC, +	WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, +	WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, +}; +  #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)  #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)  #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)  #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) +#define WMI_TXBF_STS_CAP_OFFSET_LSB	4 +#define WMI_TXBF_STS_CAP_OFFSET_MASK	0xf0 +#define WMI_BF_SOUND_DIM_OFFSET_LSB	8 +#define WMI_BF_SOUND_DIM_OFFSET_MASK	0xf00 +  /* slot time long */  #define WMI_VDEV_SLOT_TIME_LONG		0x1  /* slot time short */ @@ -4305,6 +5196,14 @@ struct wmi_tim_info {  	__le32 tim_num_ps_pending;  } __packed; +struct wmi_tim_info_arg { +	__le32 tim_len; +	__le32 tim_mcast; +	const __le32 *tim_bitmap; +	__le32 tim_changed; +	__le32 tim_num_ps_pending; +} __packed; +  /* Maximum number of NOA Descriptors supported */  #define WMI_P2P_MAX_NOA_DESCRIPTORS 4  #define WMI_P2P_OPPPS_ENABLE_BIT	BIT(0) @@ -4336,6 +5235,47 @@ struct wmi_host_swba_event {  	struct wmi_bcn_info bcn_info[0];  } __packed; +/* 16 words = 512 client + 1 word = for guard */ +#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17 + +struct wmi_10_4_tim_info { +	__le32 tim_len; +	__le32 tim_mcast; +	__le32 tim_bitmap[WMI_10_4_TIM_BITMAP_ARRAY_SIZE]; +	__le32 tim_changed; +	__le32 tim_num_ps_pending; +} __packed; + +#define WMI_10_4_P2P_MAX_NOA_DESCRIPTORS 1 + +struct wmi_10_4_p2p_noa_info { +	/* Bit 0 - Flag to indicate an update in NOA schedule +	 * Bits 7-1 - Reserved +	 */ +	u8 changed; +	/* NOA index */ +	u8 index; +	/* Bit 0 - Opp PS state of the AP +	 * Bits 1-7 - Ctwindow in TUs +	 */ +	u8 ctwindow_oppps; +	/* Number of NOA descriptors */ +	u8 num_descriptors; + +	struct wmi_p2p_noa_descriptor +		noa_descriptors[WMI_10_4_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + +struct wmi_10_4_bcn_info { +	struct wmi_10_4_tim_info tim_info; +	struct wmi_10_4_p2p_noa_info p2p_noa_info; +} __packed; + +struct wmi_10_4_host_swba_event { +	__le32 vdev_map; +	struct wmi_10_4_bcn_info bcn_info[0]; +} __packed; +  #define WMI_MAX_AP_VDEV 16  struct wmi_tbtt_offset_event { @@ -4660,11 +5600,24 @@ struct wmi_chan_info_event {  	__le32 cycle_count;  } __packed; +struct wmi_10_4_chan_info_event { +	__le32 err_code; +	__le32 freq; +	__le32 cmd_flags; +	__le32 noise_floor; +	__le32 rx_clear_count; +	__le32 cycle_count; +	__le32 chan_tx_pwr_range; +	__le32 chan_tx_pwr_tp; +	__le32 rx_frame_count; +} __packed; +  struct wmi_peer_sta_kickout_event {  	struct wmi_mac_addr peer_macaddr;  } __packed;  #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) +#define WMI_CHAN_INFO_FLAG_PRE_COMPLETE BIT(1)  /* Beacon filter wmi command info */  #define BCN_FLT_MAX_SUPPORTED_IES	256 @@ -4840,6 +5793,9 @@ struct wmi_ch_info_ev_arg {  	__le32 noise_floor;  	__le32 rx_clear_count;  	__le32 cycle_count; +	__le32 chan_tx_pwr_range; +	__le32 chan_tx_pwr_tp; +	__le32 rx_frame_count;  };  struct wmi_vdev_start_ev_arg { @@ -4855,16 +5811,29 @@ struct wmi_peer_kick_ev_arg {  struct wmi_swba_ev_arg {  	__le32 vdev_map; -	const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; +	struct wmi_tim_info_arg tim_info[WMI_MAX_AP_VDEV];  	const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV];  };  struct wmi_phyerr_ev_arg { -	__le32 num_phyerrs; -	__le32 tsf_l32; -	__le32 tsf_u32; -	__le32 buf_len; -	const struct wmi_phyerr *phyerrs; +	u32 tsf_timestamp; +	u16 freq1; +	u16 freq2; +	u8 rssi_combined; +	u8 chan_width_mhz; +	u8 phy_err_code; +	u16 nf_chains[4]; +	u32 buf_len; +	const u8 *buf; +	u8 hdr_len; +}; + +struct wmi_phyerr_hdr_arg { +	u32 num_phyerrs; +	u32 tsf_l32; +	u32 tsf_u32; +	u32 buf_len; +	const void *phyerrs;  };  struct wmi_svc_rdy_ev_arg { @@ -5085,6 +6054,12 @@ struct wmi_tdls_peer_capab_arg {  	u32 pref_offchan_bw;  }; +enum wmi_txbf_conf { +	WMI_TXBF_CONF_UNSUPPORTED, +	WMI_TXBF_CONF_BEFORE_ASSOC, +	WMI_TXBF_CONF_AFTER_ASSOC, +}; +  struct ath10k;  struct ath10k_vif;  struct ath10k_fw_stats_pdev; @@ -5136,9 +6111,9 @@ void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_dfs(struct ath10k *ar, -			  const struct wmi_phyerr *phyerr, u64 tsf); +			  struct wmi_phyerr_ev_arg *phyerr, u64 tsf);  void ath10k_wmi_event_spectral_scan(struct ath10k *ar, -				    const struct wmi_phyerr *phyerr, +				    struct wmi_phyerr_ev_arg *phyerr,  				    u64 tsf);  void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb); @@ -5167,5 +6142,6 @@ void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);  void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);  int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); - +int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, +				 int left_len, struct wmi_phyerr_ev_arg *arg);  #endif /* _WMI_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index a68d8fd853a3..8e02b381990f 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -301,8 +301,26 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)  		ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);  exit: +	if (ret) { +		switch (ar->state) { +		case ATH10K_STATE_ON: +			ar->state = ATH10K_STATE_RESTARTING; +			ret = 1; +			break; +		case ATH10K_STATE_OFF: +		case ATH10K_STATE_RESTARTING: +		case ATH10K_STATE_RESTARTED: +		case ATH10K_STATE_UTF: +		case ATH10K_STATE_WEDGED: +			ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n", +				    ar->state); +			ret = -EIO; +			break; +		} +	} +  	mutex_unlock(&ar->conf_mutex); -	return ret ? 1 : 0; +	return ret;  }  int ath10k_wow_init(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 2399a3921762..b1278f9f24ba 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -5,7 +5,6 @@ config ATH5K  	select MAC80211_LEDS  	select LEDS_CLASS  	select NEW_LEDS -	select AVERAGE  	select ATH5K_AHB if ATH25  	select ATH5K_PCI if !ATH25  	---help--- diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 5c008757662b..38be2702c0e2 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -223,7 +223,7 @@ static void  ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,  			 bool ofdm_trigger)  { -	int rssi = ewma_read(&ah->ah_beacon_rssi_avg); +	int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg);  	ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "raise immunity (%s)",  		ofdm_trigger ? "ODFM" : "CCK"); @@ -309,7 +309,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,  static void  ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)  { -	int rssi = ewma_read(&ah->ah_beacon_rssi_avg); +	int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg);  	ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "lower immunity"); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index e22b0e778927..fa6e89e5c421 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1252,6 +1252,8 @@ struct ath5k_statistics {  #define ATH5K_TXQ_LEN_MAX	(ATH_TXBUF / 4)		/* bufs per queue */  #define ATH5K_TXQ_LEN_LOW	(ATH5K_TXQ_LEN_MAX / 2)	/* low mark */ +DECLARE_EWMA(beacon_rssi, 1024, 8) +  /* Driver state associated with an instance of a device */  struct ath5k_hw {  	struct ath_common       common; @@ -1432,7 +1434,7 @@ struct ath5k_hw {  	struct ath5k_nfcal_hist ah_nfcal_hist;  	/* average beacon RSSI in our BSS (used by ANI) */ -	struct ewma		ah_beacon_rssi_avg; +	struct ewma_beacon_rssi	ah_beacon_rssi_avg;  	/* noise floor from last periodic calibration */  	s32			ah_noise_floor; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 23552f43d125..342563a3706f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1430,7 +1430,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,  	trace_ath5k_rx(ah, skb);  	if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { -		ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); +		ewma_beacon_rssi_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi);  		/* check beacons in IBSS mode */  		if (ah->opmode == NL80211_IFTYPE_ADHOC) @@ -2936,7 +2936,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,  	ah->ah_cal_next_short = jiffies +  		msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); -	ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); +	ewma_beacon_rssi_init(&ah->ah_beacon_rssi_avg);  	/* clear survey data and cycle counters */  	memset(&ah->survey, 0, sizeof(ah->survey)); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index c70782e8f07b..654a1e33f827 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -722,7 +722,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,  			st->mib_intr);  	len += snprintf(buf + len, sizeof(buf) - len,  			"beacon RSSI average:\t%d\n", -			(int)ewma_read(&ah->ah_beacon_rssi_avg)); +			(int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));  #define CC_PRINT(_struct, _field) \  	_struct._field, \ diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 14cab1403dd6..112d8a9b8d43 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -427,7 +427,7 @@ struct htc_endpoint_credit_dist {  };  /* - * credit distibution code that is passed into the distrbution function, + * credit distribution code that is passed into the distribution function,   * there are mandatory and optional codes that must be handled   */  enum htc_credit_dist_reason { diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b921005ad7ee..a5e1de75a4a3 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -154,7 +154,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)  }  /*  Performs DIX to 802.3 encapsulation for transmit packets. - *  Assumes the entire DIX header is contigous and that there is + *  Assumes the entire DIX header is contiguous and that there is   *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.   */  int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) @@ -449,7 +449,7 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)  /*   * Performs 802.3 to DIX encapsulation for received packets. - * Assumes the entire 802.3 header is contigous. + * Assumes the entire 802.3 header is contiguous.   */  int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)  { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fc595b92ac56..c5f8bc4b5595 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -455,7 +455,7 @@  #define AR_PHY_MODE              (AR_SM_BASE + 0x8)  #define AR_PHY_ACTIVE            (AR_SM_BASE + 0xc)  #define AR_PHY_SPUR_MASK_A       (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) -#define AR_PHY_SPUR_MASK_B       (AR_SM_BASE + 0x24) +#define AR_PHY_SPUR_MASK_B       (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x1c : 0x24))  #define AR_PHY_SPECTRAL_SCAN     (AR_SM_BASE + 0x28)  #define AR_PHY_RADAR_BW_FILTER   (AR_SM_BASE + 0x2c)  #define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) @@ -495,7 +495,7 @@  #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A                       0x3FF  #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S                     0 -#define AR_PHY_TEST              (AR_SM_BASE + 0x160) +#define AR_PHY_TEST              (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x15c : 0x160))  #define AR_PHY_TEST_BBB_OBS_SEL       0x780000  #define AR_PHY_TEST_BBB_OBS_SEL_S     19 @@ -521,24 +521,29 @@  #define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S	  29 -#define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168) +#define AR_PHY_TSTDAC            (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x164 : 0x168)) -#define AR_PHY_CHAN_STATUS       (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_STATUS       (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x168 : 0x16c))  #define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170))  #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ	0x00000008  #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S	3 -#define AR_PHY_CHNINFO_NOISEPWR  (AR_SM_BASE + 0x174) -#define AR_PHY_CHNINFO_GAINDIFF  (AR_SM_BASE + 0x178) -#define AR_PHY_CHNINFO_FINETIM   (AR_SM_BASE + 0x17c) -#define AR_PHY_CHAN_INFO_GAIN_0  (AR_SM_BASE + 0x180) -#define AR_PHY_SCRAMBLER_SEED    (AR_SM_BASE + 0x190) -#define AR_PHY_CCK_TX_CTRL       (AR_SM_BASE + 0x194) +#define AR_PHY_CHNINFO_NOISEPWR  (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x170 : 0x174)) +#define AR_PHY_CHNINFO_GAINDIFF  (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x174 : 0x178)) +#define AR_PHY_CHNINFO_FINETIM   (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x178 : 0x17c)) +#define AR_PHY_CHAN_INFO_GAIN_0  (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x17c : 0x180)) +#define AR_PHY_SCRAMBLER_SEED    (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x184 : 0x190)) +#define AR_PHY_CCK_TX_CTRL       (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x188 : 0x194))  #define AR_PHY_HEAVYCLIP_CTL     (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4))  #define AR_PHY_HEAVYCLIP_20      (AR_SM_BASE + 0x1a8)  #define AR_PHY_HEAVYCLIP_40      (AR_SM_BASE + 0x1ac) +#define AR_PHY_HEAVYCLIP_1	 (AR_SM_BASE + 0x19c) +#define AR_PHY_HEAVYCLIP_2	 (AR_SM_BASE + 0x1a0) +#define AR_PHY_HEAVYCLIP_3	 (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_4	 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_5	 (AR_SM_BASE + 0x1ac)  #define AR_PHY_ILLEGAL_TXRATE    (AR_SM_BASE + 0x1b0)  #define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a7a81b3969ce..c85c47978e1e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -172,14 +172,6 @@ struct ath_txq {  	struct sk_buff_head complete_q;  }; -struct ath_atx_ac { -	struct ath_txq *txq; -	struct list_head list; -	struct list_head tid_q; -	bool clear_ps_filter; -	bool sched; -}; -  struct ath_frame_info {  	struct ath_buf *bf;  	u16 framelen; @@ -242,7 +234,7 @@ struct ath_atx_tid {  	struct sk_buff_head buf_q;  	struct sk_buff_head retry_q;  	struct ath_node *an; -	struct ath_atx_ac *ac; +	struct ath_txq *txq;  	unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];  	u16 seq_start;  	u16 seq_next; @@ -252,8 +244,8 @@ struct ath_atx_tid {  	int baw_tail;   /* next unused tx buffer slot */  	s8 bar_index; -	bool sched;  	bool active; +	bool clear_ps_filter;  };  struct ath_node { @@ -261,7 +253,6 @@ struct ath_node {  	struct ieee80211_sta *sta; /* station struct we're part of */  	struct ieee80211_vif *vif; /* interface with which we're associated */  	struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; -	struct ath_atx_ac ac[IEEE80211_NUM_ACS];  	u16 maxampdu;  	u8 mpdudensity; @@ -410,6 +401,12 @@ enum ath_offchannel_state {  	ATH_OFFCHANNEL_ROC_DONE,  }; +enum ath_roc_complete_reason { +	ATH_ROC_COMPLETE_EXPIRE, +	ATH_ROC_COMPLETE_ABORT, +	ATH_ROC_COMPLETE_CANCEL, +}; +  struct ath_offchannel {  	struct ath_chanctx chan;  	struct timer_list timer; @@ -471,7 +468,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,  void ath_chanctx_set_next(struct ath_softc *sc, bool force);  void ath_offchannel_next(struct ath_softc *sc);  void ath_scan_complete(struct ath_softc *sc, bool abort); -void ath_roc_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, +		      enum ath_roc_complete_reason reason);  struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc);  #else diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 206665059d66..90f5773a1a61 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -915,18 +915,27 @@ void ath_offchannel_next(struct ath_softc *sc)  	}  } -void ath_roc_complete(struct ath_softc *sc, bool abort) +void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	if (abort) +	sc->offchannel.roc_vif = NULL; +	sc->offchannel.roc_chan = NULL; + +	switch (reason) { +	case ATH_ROC_COMPLETE_ABORT:  		ath_dbg(common, CHAN_CTX, "RoC aborted\n"); -	else +		ieee80211_remain_on_channel_expired(sc->hw); +		break; +	case ATH_ROC_COMPLETE_EXPIRE:  		ath_dbg(common, CHAN_CTX, "RoC expired\n"); +		ieee80211_remain_on_channel_expired(sc->hw); +		break; +	case ATH_ROC_COMPLETE_CANCEL: +		ath_dbg(common, CHAN_CTX, "RoC canceled\n"); +		break; +	} -	sc->offchannel.roc_vif = NULL; -	sc->offchannel.roc_chan = NULL; -	ieee80211_remain_on_channel_expired(sc->hw);  	ath_offchannel_next(sc);  	ath9k_ps_restore(sc);  } @@ -1058,7 +1067,7 @@ static void ath_offchannel_timer(unsigned long data)  	case ATH_OFFCHANNEL_ROC_START:  	case ATH_OFFCHANNEL_ROC_WAIT:  		sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; -		ath_roc_complete(sc, false); +		ath_roc_complete(sc, ATH_ROC_COMPLETE_EXPIRE);  		break;  	default:  		break; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dbf8f4959642..da32c8faad94 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -765,6 +765,8 @@ static int read_file_reset(struct seq_file *file, void *data)  		[RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",  		[RESET_TYPE_MCI] = "MCI Reset",  		[RESET_TYPE_CALIBRATION] = "Calibration error", +		[RESET_TX_DMA_ERROR] = "Tx DMA stop error", +		[RESET_RX_DMA_ERROR] = "Rx DMA stop error",  	};  	int i; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a8e9319958e6..cd68c5f0e751 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -50,6 +50,8 @@ enum ath_reset_type {  	RESET_TYPE_BEACON_STUCK,  	RESET_TYPE_MCI,  	RESET_TYPE_CALIBRATION, +	RESET_TX_DMA_ERROR, +	RESET_RX_DMA_ERROR,  	__RESET_TYPE_MAX  }; diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index ffca918ff16a..c2ca57a2ed09 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -26,12 +26,11 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,  	struct ath_node *an = file->private_data;  	struct ath_softc *sc = an->sc;  	struct ath_atx_tid *tid; -	struct ath_atx_ac *ac;  	struct ath_txq *txq;  	u32 len = 0, size = 4096;  	char *buf;  	size_t retval; -	int tidno, acno; +	int tidno;  	buf = kzalloc(size, GFP_KERNEL);  	if (buf == NULL) @@ -49,26 +48,13 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,  			 an->mpdudensity);  	len += scnprintf(buf + len, size - len, -			 "%2s%7s\n", "AC", "SCHED"); - -	for (acno = 0, ac = &an->ac[acno]; -	     acno < IEEE80211_NUM_ACS; acno++, ac++) { -		txq = ac->txq; -		ath_txq_lock(sc, txq); -		len += scnprintf(buf + len, size - len, -				 "%2d%7d\n", -				 acno, ac->sched); -		ath_txq_unlock(sc, txq); -	} - -	len += scnprintf(buf + len, size - len,  			 "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",  			 "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",  			 "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");  	for (tidno = 0, tid = &an->tid[tidno];  	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		txq = tid->ac->txq; +		txq = tid->txq;  		ath_txq_lock(sc, txq);  		if (tid->active) {  			len += scnprintf(buf + len, size - len, @@ -80,7 +66,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,  					 tid->baw_head,  					 tid->baw_tail,  					 tid->bar_index, -					 tid->sched); +					 !list_empty(&tid->list));  		}  		ath_txq_unlock(sc, txq);  	} diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index e98a9eaba7ff..1ece42c2443d 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -30,6 +30,157 @@ struct ath_radar_data {  	u8 pulse_length_pri;  }; +/**** begin: CHIRP ************************************************************/ + +/* min and max gradients for defined FCC chirping pulses, given by + * - 20MHz chirp width over a pulse width of  50us + * -  5MHz chirp width over a pulse width of 100us + */ +static const int BIN_DELTA_MIN		= 1; +static const int BIN_DELTA_MAX		= 10; + +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ +#define NUM_DIFFS 3 +static const int FFT_NUM_SAMPLES	= (NUM_DIFFS + 1); + +/* Threshold for difference of delta peaks */ +static const int MAX_DIFF		= 2; + +/* width range to be checked for chirping */ +static const int MIN_CHIRP_PULSE_WIDTH	= 20; +static const int MAX_CHIRP_PULSE_WIDTH	= 110; + +struct ath9k_dfs_fft_20 { +	u8 bin[28]; +	u8 lower_bins[3]; +} __packed; +struct ath9k_dfs_fft_40 { +	u8 bin[64]; +	u8 lower_bins[3]; +	u8 upper_bins[3]; +} __packed; + +static inline int fft_max_index(u8 *bins) +{ +	return (bins[2] & 0xfc) >> 2; +} +static inline int fft_max_magnitude(u8 *bins) +{ +	return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; +} +static inline u8 fft_bitmap_weight(u8 *bins) +{ +	return bins[0] & 0x3f; +} + +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, +				    bool is_ctl, bool is_ext) +{ +	const int DFS_UPPER_BIN_OFFSET = 64; +	/* if detected radar on both channels, select the significant one */ +	if (is_ctl && is_ext) { +		/* first check wether channels have 'strong' bins */ +		is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; +		is_ext = fft_bitmap_weight(fft->upper_bins) != 0; + +		/* if still unclear, take higher magnitude */ +		if (is_ctl && is_ext) { +			int mag_lower = fft_max_magnitude(fft->lower_bins); +			int mag_upper = fft_max_magnitude(fft->upper_bins); +			if (mag_upper > mag_lower) +				is_ctl = false; +			else +				is_ext = false; +		} +	} +	if (is_ctl) +		return fft_max_index(fft->lower_bins); +	return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; +} +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, +				 int datalen, bool is_ctl, bool is_ext) +{ +	int i; +	int max_bin[FFT_NUM_SAMPLES]; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	int prev_delta; + +	if (IS_CHAN_HT40(ah->curchan)) { +		struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; +		int num_fft_packets = datalen / sizeof(*fft); +		if (num_fft_packets == 0) +			return false; + +		ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", +			datalen, num_fft_packets); +		if (num_fft_packets < (FFT_NUM_SAMPLES)) { +			ath_dbg(common, DFS, "not enough packets for chirp\n"); +			return false; +		} +		/* HW sometimes adds 2 garbage bytes in front of FFT samples */ +		if ((datalen % sizeof(*fft)) == 2) { +			fft = (struct ath9k_dfs_fft_40 *) (data + 2); +			ath_dbg(common, DFS, "fixing datalen by 2\n"); +		} +		if (IS_CHAN_HT40MINUS(ah->curchan)) { +			int temp = is_ctl; +			is_ctl = is_ext; +			is_ext = temp; +		} +		for (i = 0; i < FFT_NUM_SAMPLES; i++) +			max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, +							      is_ext); +	} else { +		struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; +		int num_fft_packets = datalen / sizeof(*fft); +		if (num_fft_packets == 0) +			return false; +		ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", +			datalen, num_fft_packets); +		if (num_fft_packets < (FFT_NUM_SAMPLES)) { +			ath_dbg(common, DFS, "not enough packets for chirp\n"); +			return false; +		} +		/* in ht20, this is a 6-bit signed number => shift it to 0 */ +		for (i = 0; i < FFT_NUM_SAMPLES; i++) +			max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; +	} +	ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", +		max_bin[0], max_bin[1], max_bin[2], max_bin[3]); + +	/* Check for chirp attributes within specs +	 * a) delta of adjacent max_bins is within range +	 * b) delta of adjacent deltas are within tolerance +	 */ +	prev_delta = 0; +	for (i = 0; i < NUM_DIFFS; i++) { +		int ddelta = -1; +		int delta = max_bin[i + 1] - max_bin[i]; + +		/* ensure gradient is within valid range */ +		if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { +			ath_dbg(common, DFS, "CHIRP: invalid delta %d " +				"in sample %d\n", delta, i); +			return false; +		} +		if (i == 0) +			goto done; +		ddelta = delta - prev_delta; +		if (abs(ddelta) > MAX_DIFF) { +			ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", +				ddelta); +			return false; +		} +done: +		ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", +			i, delta, ddelta); +		prev_delta = delta; +	} +	return true; +} +/**** end: CHIRP **************************************************************/ +  /* convert pulse duration to usecs, considering clock mode */  static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)  { @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc,  		return false;  	} -	/* -	 * TODO: check chirping pulses -	 *	 checks for chirping are dependent on the DFS regulatory domain -	 *	 used, which is yet TBD -	 */ -  	/* convert duration to usecs */  	pe->width = dur_to_usecs(sc->sc_ah, dur);  	pe->rssi = rssi; @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,  	if (!ath9k_postprocess_radar_event(sc, &ard, &pe))  		return; +	if (pe.width > MIN_CHIRP_PULSE_WIDTH && +	    pe.width < MAX_CHIRP_PULSE_WIDTH) { +		bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); +		bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); +		int clen = datalen - 3; +		pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); +	} else { +		pe.chirp = false; +	} +  	ath_dbg(common, DFS,  		"ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "  		"width=%d, rssi=%d, delta_ts=%llu\n", @@ -198,7 +353,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,  	sc->dfs_prev_pulse_ts = pe.ts;  	if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND)  		ath9k_dfs_process_radar_pulse(sc, &pe); -	if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { +	if (IS_CHAN_HT40(ah->curchan) && +	    ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {  		pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20;  		ath9k_dfs_process_radar_pulse(sc, &pe);  	} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 39eaf9b6e9b4..1e84882f8c5b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -74,7 +74,7 @@ static struct ath_ps_ops ath9k_htc_ps_ops = {  static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)  { -	int time_left; +	unsigned long time_left;  	if (atomic_read(&priv->htc->tgt_ready) > 0) {  		atomic_dec(&priv->htc->tgt_ready); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index dab1323dfec7..172a9ff4aaab 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -794,8 +794,11 @@ void ath9k_htc_ani_work(struct work_struct *work)  		common->ani.longcal_timer = timestamp;  	} -	/* Short calibration applies only while caldone is false */ -	if (!common->ani.caldone) { +	/* +	 * Short calibration applies only while caldone +	 * is false or -ETIMEDOUT +	 */ +	if (common->ani.caldone <= 0) {  		if ((timestamp - common->ani.shortcal_timer) >=  		    short_cal_interval) {  			shortcal = true; @@ -844,7 +847,11 @@ set_timer:  	*/  	cal_interval = ATH_LONG_CALINTERVAL;  	cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); -	if (!common->ani.caldone) +	/* +	 * Short calibration applies only while caldone +	 * is false or -ETIMEDOUT +	 */ +	if (common->ani.caldone <= 0)  		cal_interval = min(cal_interval, (u32)short_cal_interval);  	ieee80211_queue_delayed_work(common->hw, &priv->ani_work, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index d2408da38c1c..2294709ee8b0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -146,7 +146,8 @@ static int htc_config_pipe_credits(struct htc_target *target)  {  	struct sk_buff *skb;  	struct htc_config_pipe_msg *cp_msg; -	int ret, time_left; +	int ret; +	unsigned long time_left;  	skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);  	if (!skb) { @@ -184,7 +185,8 @@ static int htc_setup_complete(struct htc_target *target)  {  	struct sk_buff *skb;  	struct htc_comp_msg *comp_msg; -	int ret = 0, time_left; +	int ret = 0; +	unsigned long time_left;  	skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);  	if (!skb) { @@ -236,7 +238,8 @@ int htc_connect_service(struct htc_target *target,  	struct sk_buff *skb;  	struct htc_endpoint *endpoint;  	struct htc_conn_svc_msg *conn_msg; -	int ret, time_left; +	int ret; +	unsigned long time_left;  	/* Find an available endpoint */  	endpoint = get_next_avail_ep(target->endpoint); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5e15e8e10ed3..1dd0339de372 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)  		return;  	case AR9300_DEVID_QCA956X:  		ah->hw_version.macVersion = AR_SREV_VERSION_9561; +		return;  	}  	val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -3185,6 +3186,7 @@ static struct {  	{ AR_SREV_VERSION_9550,         "9550" },  	{ AR_SREV_VERSION_9565,         "9565" },  	{ AR_SREV_VERSION_9531,         "9531" }, +	{ AR_SREV_VERSION_9561,         "9561" },  };  /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index eff0e5325e6a..57f95f2dca5b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -736,13 +736,14 @@ static const struct ieee80211_iface_limit if_limits_multi[] = {  				 BIT(NL80211_IFTYPE_P2P_CLIENT) |  				 BIT(NL80211_IFTYPE_P2P_GO) },  	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) }, +	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_DEVICE) },  };  static const struct ieee80211_iface_combination if_comb_multi[] = {  	{  		.limits = if_limits_multi,  		.n_limits = ARRAY_SIZE(if_limits_multi), -		.max_interfaces = 2, +		.max_interfaces = 3,  		.num_different_channels = 2,  		.beacon_int_infra_match = true,  	}, @@ -826,6 +827,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  	ieee80211_hw_set(hw, SIGNAL_DBM);  	ieee80211_hw_set(hw, RX_INCLUDES_FCS);  	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); +	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);  	if (ath9k_ps_enable)  		ieee80211_hw_set(hw, SUPPORTS_PS); @@ -855,6 +857,10 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  			BIT(NL80211_IFTYPE_MESH_POINT) |  			BIT(NL80211_IFTYPE_WDS); +		if (ath9k_is_chanctx_enabled()) +			hw->wiphy->interface_modes |= +					BIT(NL80211_IFTYPE_P2P_DEVICE); +  			hw->wiphy->iface_combinations = if_comb;  			hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);  	} diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 90631d768a60..5ad0feeebc86 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -172,7 +172,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath_tx_control txctl; -	int time_left; +	unsigned long time_left;  	memset(&txctl, 0, sizeof(txctl));  	txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc..c27143ba9ffb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1459,13 +1459,18 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,  				   u64 multicast)  {  	struct ath_softc *sc = hw->priv; +	struct ath_chanctx *ctx;  	u32 rfilt;  	changed_flags &= SUPPORTED_FILTERS;  	*total_flags &= SUPPORTED_FILTERS;  	spin_lock_bh(&sc->chan_lock); -	sc->cur_chan->rxfilter = *total_flags; +	ath_for_each_chanctx(sc, ctx) +		ctx->rxfilter = *total_flags; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +	sc->offchannel.chan.rxfilter = *total_flags; +#endif  	spin_unlock_bh(&sc->chan_lock);  	ath9k_ps_wakeup(sc); @@ -2246,7 +2251,7 @@ static void ath9k_cancel_pending_offchannel(struct ath_softc *sc)  		del_timer_sync(&sc->offchannel.timer);  		if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) -			ath_roc_complete(sc, true); +			ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT);  	}  	if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { @@ -2355,7 +2360,7 @@ static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)  	if (sc->offchannel.roc_vif) {  		if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) -			ath_roc_complete(sc, true); +			ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL);  	}  	mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6c75fb1ab77d..d3189daf9996 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc)  	if (!(ah->ah_flags & AH_UNPLUGGED) &&  	    unlikely(!stopped)) { -		ath_err(ath9k_hw_common(sc->sc_ah), -			"Could not stop RX, we could be " -			"confusing the DMA engine when we start RX up\n"); -		ATH_DBG_WARN_ON_ONCE(!stopped); +		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, +			"Failed to stop Rx DMA\n"); +		RESET_STAT_INC(sc, RESET_RX_DMA_ERROR);  	}  	return stopped && !reset;  } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index ca533b4321bd..9c16e2a6d185 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -299,7 +299,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,  		       sizeof(struct wmi_cmd_hdr);  	struct sk_buff *skb;  	u8 *data; -	int time_left, ret = 0; +	unsigned long time_left; +	int ret = 0;  	if (ah->ah_flags & AH_UNPLUGGED)  		return 0; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3ad79bb4f2c2..3e3dac3d7060 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)  static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,  			     struct ath_atx_tid *tid)  { -	struct ath_atx_ac *ac = tid->ac;  	struct list_head *list;  	struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;  	struct ath_chanctx *ctx = avp->chanctx; @@ -114,19 +113,9 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,  	if (!ctx)  		return; -	if (tid->sched) -		return; - -	tid->sched = true; -	list_add_tail(&tid->list, &ac->tid_q); - -	if (ac->sched) -		return; - -	ac->sched = true; -  	list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; -	list_add_tail(&ac->list, list); +	if (list_empty(&tid->list)) +		list_add_tail(&tid->list, list);  }  static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -208,7 +197,7 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)  static void  ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)  { -	struct ath_txq *txq = tid->ac->txq; +	struct ath_txq *txq = tid->txq;  	struct ieee80211_tx_info *tx_info;  	struct sk_buff *skb, *tskb;  	struct ath_buf *bf; @@ -237,7 +226,7 @@ ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)  static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)  { -	struct ath_txq *txq = tid->ac->txq; +	struct ath_txq *txq = tid->txq;  	struct sk_buff *skb;  	struct ath_buf *bf;  	struct list_head bf_head; @@ -644,7 +633,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,  			ath_tx_queue_tid(sc, txq, tid);  			if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) -				tid->ac->clear_ps_filter = true; +				tid->clear_ps_filter = true;  		}  	} @@ -734,7 +723,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  	struct ieee80211_tx_rate *rates;  	u32 max_4ms_framelen, frmlen;  	u16 aggr_limit, bt_aggr_limit, legacy = 0; -	int q = tid->ac->txq->mac80211_qnum; +	int q = tid->txq->mac80211_qnum;  	int i;  	skb = bf->bf_mpdu; @@ -1471,8 +1460,8 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,  	if (list_empty(&bf_q))  		return false; -	if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) { -		tid->ac->clear_ps_filter = false; +	if (tid->clear_ps_filter || tid->an->no_ps_filter) { +		tid->clear_ps_filter = false;  		tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;  	} @@ -1491,7 +1480,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,  	an = (struct ath_node *)sta->drv_priv;  	txtid = ATH_AN_2_TID(an, tid); -	txq = txtid->ac->txq; +	txq = txtid->txq;  	ath_txq_lock(sc, txq); @@ -1525,7 +1514,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)  {  	struct ath_node *an = (struct ath_node *)sta->drv_priv;  	struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); -	struct ath_txq *txq = txtid->ac->txq; +	struct ath_txq *txq = txtid->txq;  	ath_txq_lock(sc, txq);  	txtid->active = false; @@ -1538,7 +1527,6 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,  		       struct ath_node *an)  {  	struct ath_atx_tid *tid; -	struct ath_atx_ac *ac;  	struct ath_txq *txq;  	bool buffered;  	int tidno; @@ -1546,25 +1534,18 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,  	for (tidno = 0, tid = &an->tid[tidno];  	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		ac = tid->ac; -		txq = ac->txq; +		txq = tid->txq;  		ath_txq_lock(sc, txq); -		if (!tid->sched) { +		if (list_empty(&tid->list)) {  			ath_txq_unlock(sc, txq);  			continue;  		}  		buffered = ath_tid_has_buffered(tid); -		tid->sched = false; -		list_del(&tid->list); - -		if (ac->sched) { -			ac->sched = false; -			list_del(&ac->list); -		} +		list_del_init(&tid->list);  		ath_txq_unlock(sc, txq); @@ -1575,18 +1556,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,  void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)  {  	struct ath_atx_tid *tid; -	struct ath_atx_ac *ac;  	struct ath_txq *txq;  	int tidno;  	for (tidno = 0, tid = &an->tid[tidno];  	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		ac = tid->ac; -		txq = ac->txq; +		txq = tid->txq;  		ath_txq_lock(sc, txq); -		ac->clear_ps_filter = true; +		tid->clear_ps_filter = true;  		if (ath_tid_has_buffered(tid)) {  			ath_tx_queue_tid(sc, txq, tid); @@ -1606,7 +1585,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,  	an = (struct ath_node *)sta->drv_priv;  	tid = ATH_AN_2_TID(an, tidno); -	txq = tid->ac->txq; +	txq = tid->txq;  	ath_txq_lock(sc, txq); @@ -1645,7 +1624,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,  		tid = ATH_AN_2_TID(an, i); -		ath_txq_lock(sc, tid->ac->txq); +		ath_txq_lock(sc, tid->txq);  		while (nframes > 0) {  			bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);  			if (!bf) @@ -1669,7 +1648,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,  			if (an->sta && !ath_tid_has_buffered(tid))  				ieee80211_sta_set_buffered(an->sta, i, false);  		} -		ath_txq_unlock_complete(sc, tid->ac->txq); +		ath_txq_unlock_complete(sc, tid->txq);  	}  	if (list_empty(&bf_q)) @@ -1883,8 +1862,11 @@ bool ath_drain_all_txq(struct ath_softc *sc)  			npend |= BIT(i);  	} -	if (npend) -		ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend); +	if (npend) { +		RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); +		ath_dbg(common, RESET, +			"Failed to stop TX DMA, queues=0x%03x!\n", npend); +	}  	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {  		if (!ATH_TXQ_SETUP(sc, i)) @@ -1915,9 +1897,8 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	struct ath_atx_ac *ac, *last_ac;  	struct ath_atx_tid *tid, *last_tid; -	struct list_head *ac_list; +	struct list_head *tid_list;  	bool sent = false;  	if (txq->mac80211_qnum < 0) @@ -1927,63 +1908,45 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)  		return;  	spin_lock_bh(&sc->chan_lock); -	ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; +	tid_list = &sc->cur_chan->acq[txq->mac80211_qnum]; -	if (list_empty(ac_list)) { +	if (list_empty(tid_list)) {  		spin_unlock_bh(&sc->chan_lock);  		return;  	}  	rcu_read_lock(); -	last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); -	while (!list_empty(ac_list)) { +	last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list); +	while (!list_empty(tid_list)) {  		bool stop = false;  		if (sc->cur_chan->stopped)  			break; -		ac = list_first_entry(ac_list, struct ath_atx_ac, list); -		last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); -		list_del(&ac->list); -		ac->sched = false; - -		while (!list_empty(&ac->tid_q)) { - -			tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, -					       list); -			list_del(&tid->list); -			tid->sched = false; - -			if (ath_tx_sched_aggr(sc, txq, tid, &stop)) -				sent = true; - -			/* -			 * add tid to round-robin queue if more frames -			 * are pending for the tid -			 */ -			if (ath_tid_has_buffered(tid)) -				ath_tx_queue_tid(sc, txq, tid); +		tid = list_first_entry(tid_list, struct ath_atx_tid, list); +		list_del_init(&tid->list); -			if (stop || tid == last_tid) -				break; -		} +		if (ath_tx_sched_aggr(sc, txq, tid, &stop)) +			sent = true; -		if (!list_empty(&ac->tid_q) && !ac->sched) { -			ac->sched = true; -			list_add_tail(&ac->list, ac_list); -		} +		/* +		 * add tid to round-robin queue if more frames +		 * are pending for the tid +		 */ +		if (ath_tid_has_buffered(tid)) +			ath_tx_queue_tid(sc, txq, tid);  		if (stop)  			break; -		if (ac == last_ac) { +		if (tid == last_tid) {  			if (!sent)  				break;  			sent = false; -			last_ac = list_entry(ac_list->prev, -					     struct ath_atx_ac, list); +			last_tid = list_entry(tid_list->prev, +					      struct ath_atx_tid, list);  		}  	} @@ -2373,10 +2336,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,  		txq = sc->tx.uapsdq;  		ath_txq_lock(sc, txq);  	} else if (txctl->an && queue) { -		WARN_ON(tid->ac->txq != txctl->txq); +		WARN_ON(tid->txq != txctl->txq);  		if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) -			tid->ac->clear_ps_filter = true; +			tid->clear_ps_filter = true;  		/*  		 * Add this frame to software queue for scheduling later @@ -2470,8 +2433,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	bf = list_first_entry(&bf_q, struct ath_buf, list);  	hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; -	if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) { -		hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA; +	if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) { +		hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);  		dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,  			sizeof(*hdr), DMA_TO_DEVICE);  	} @@ -2870,7 +2833,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)  void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)  {  	struct ath_atx_tid *tid; -	struct ath_atx_ac *ac;  	int tidno, acno;  	for (tidno = 0, tid = &an->tid[tidno]; @@ -2881,26 +2843,18 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)  		tid->seq_start = tid->seq_next = 0;  		tid->baw_size  = WME_MAX_BA;  		tid->baw_head  = tid->baw_tail = 0; -		tid->sched     = false;  		tid->active	   = false; +		tid->clear_ps_filter = true;  		__skb_queue_head_init(&tid->buf_q);  		__skb_queue_head_init(&tid->retry_q); +		INIT_LIST_HEAD(&tid->list);  		acno = TID_TO_WME_AC(tidno); -		tid->ac = &an->ac[acno]; -	} - -	for (acno = 0, ac = &an->ac[acno]; -	     acno < IEEE80211_NUM_ACS; acno++, ac++) { -		ac->sched    = false; -		ac->clear_ps_filter = true; -		ac->txq = sc->tx.txq_map[acno]; -		INIT_LIST_HEAD(&ac->tid_q); +		tid->txq = sc->tx.txq_map[acno];  	}  }  void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)  { -	struct ath_atx_ac *ac;  	struct ath_atx_tid *tid;  	struct ath_txq *txq;  	int tidno; @@ -2908,20 +2862,12 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)  	for (tidno = 0, tid = &an->tid[tidno];  	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		ac = tid->ac; -		txq = ac->txq; +		txq = tid->txq;  		ath_txq_lock(sc, txq); -		if (tid->sched) { -			list_del(&tid->list); -			tid->sched = false; -		} - -		if (ac->sched) { -			list_del(&ac->list); -			tid->ac->sched = false; -		} +		if (!list_empty(&tid->list)) +			list_del_init(&tid->list);  		ath_tid_drain(sc, txq, tid);  		tid->active = false; diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 508eccf5d982..d59d83e0ce4b 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -40,6 +40,8 @@ const char *ath_opmode_to_string(enum nl80211_iftype opmode)  		return "P2P-CLIENT";  	case NL80211_IFTYPE_P2P_GO:  		return "P2P-GO"; +	case NL80211_IFTYPE_OCB: +		return "OCB";  	default:  		return "UNKNOWN";  	} diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 1b5ad1965607..cc5c592fc4c0 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -273,7 +273,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,  				tmp_false_count++;  			}  		} -		if (ps.count < min_count) +		if (ps.count <= min_count)  			/* did not reach minimum count, drop sequence */  			continue; diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 050506f842e9..64b432625fbb 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -12,6 +12,7 @@ wil6210-y += debug.o  wil6210-y += rx_reorder.o  wil6210-y += ioctl.o  wil6210-y += fw.o +wil6210-y += pm.o  wil6210-y += pmc.o  wil6210-$(CONFIG_WIL6210_TRACING) += trace.o  wil6210-y += wil_platform.o diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h new file mode 100644 index 000000000000..c131b5e1292f --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This file contains the definitions for the boot loader + * for the Qualcomm "Sparrow" 60 Gigabit wireless solution. + */ +#ifndef BOOT_LOADER_EXPORT_H_ +#define BOOT_LOADER_EXPORT_H_ + +struct bl_dedicated_registers_v1 { +	__le32	boot_loader_ready;		/* 0x880A3C driver will poll +						 * this Dword until BL will +						 * set it to 1 (initial value +						 * should be 0) +						 */ +	__le32	boot_loader_struct_version;	/* 0x880A40 BL struct ver. */ +	__le16	rf_type;			/* 0x880A44 connected RF ID */ +	__le16	rf_status;			/* 0x880A46 RF status, +						 * 0 is OK else error +						 */ +	__le32	baseband_type;			/* 0x880A48 board type ID */ +	u8	mac_address[6];			/* 0x880A4c BL mac address */ +	u8	bl_version_major;		/* 0x880A52 BL ver. major */ +	u8	bl_version_minor;		/* 0x880A53 BL ver. minor */ +	__le16	bl_version_subminor;		/* 0x880A54 BL ver. subminor */ +	__le16	bl_version_build;		/* 0x880A56 BL ver. build */ +	/* valid only for version 2 and above */ +	__le32  bl_assert_code;         /* 0x880A58 BL Assert code */ +	__le32  bl_assert_blink;        /* 0x880A5C BL Assert Branch */ +	__le32  bl_reserved[22];        /* 0x880A60 - 0x880AB4 */ +	__le32  bl_magic_number;        /* 0x880AB8 BL Magic number */ +} __packed; + +/* the following struct is the version 0 struct */ + +struct bl_dedicated_registers_v0 { +	__le32	boot_loader_ready;		/* 0x880A3C driver will poll +						 * this Dword until BL will +						 * set it to 1 (initial value +						 * should be 0) +						 */ +#define BL_READY (1)	/* ready indication */ +	__le32	boot_loader_struct_version;	/* 0x880A40 BL struct ver. */ +	__le32	rf_type;			/* 0x880A44 connected RF ID */ +	__le32	baseband_type;			/* 0x880A48 board type ID */ +	u8	mac_address[6];			/* 0x880A4c BL mac address */ +} __packed; + +#endif /* BOOT_LOADER_EXPORT_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c79cfe02ec80..20d07ef679e8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -336,12 +336,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,  	else  		wil_dbg_misc(wil, "Scan has no IE's\n"); -	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, -			request->ie); -	if (rc) { -		wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc); +	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); +	if (rc)  		goto out; -	}  	rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +  			cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); @@ -462,10 +459,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,  	 * ies in FW.  	 */  	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); -	if (rc) { -		wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); +	if (rc)  		goto out; -	}  	/* WMI_CONNECT_CMD */  	memset(&conn, 0, sizeof(conn)); @@ -722,17 +717,98 @@ static int wil_fix_bcon(struct wil6210_priv *wil,  {  	struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;  	size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); -	int rc = 0;  	if (bcon->probe_resp_len <= hlen)  		return 0; +/* always use IE's from full probe frame, they has more info + * notable RSN + */ +	bcon->proberesp_ies = f->u.probe_resp.variable; +	bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;  	if (!bcon->assocresp_ies) { -		bcon->assocresp_ies = f->u.probe_resp.variable; -		bcon->assocresp_ies_len = bcon->probe_resp_len - hlen; -		rc = 1; +		bcon->assocresp_ies = bcon->proberesp_ies; +		bcon->assocresp_ies_len = bcon->proberesp_ies_len;  	} +	return 1; +} + +/* internal functions for device reset and starting AP */ +static int _wil_cfg80211_set_ies(struct wiphy *wiphy, +				 struct cfg80211_beacon_data *bcon) +{ +	int rc; +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); + +	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, +			bcon->proberesp_ies); +	if (rc) +		return rc; + +	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, +			bcon->assocresp_ies); +#if 0 /* to use beacon IE's, remove this #if 0 */ +	if (rc) +		return rc; + +	rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail); +#endif + +	return rc; +} + +static int _wil_cfg80211_start_ap(struct wiphy *wiphy, +				  struct net_device *ndev, +				  const u8 *ssid, size_t ssid_len, u32 privacy, +				  int bi, u8 chan, +				  struct cfg80211_beacon_data *bcon, +				  u8 hidden_ssid) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; +	struct wireless_dev *wdev = ndev->ieee80211_ptr; +	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); + +	wil_set_recovery_state(wil, fw_recovery_idle); + +	mutex_lock(&wil->mutex); + +	__wil_down(wil); +	rc = __wil_up(wil); +	if (rc) +		goto out; + +	rc = wmi_set_ssid(wil, ssid_len, ssid); +	if (rc) +		goto out; + +	rc = _wil_cfg80211_set_ies(wiphy, bcon); +	if (rc) +		goto out; + +	wil->privacy = privacy; +	wil->channel = chan; +	wil->hidden_ssid = hidden_ssid; + +	netif_carrier_on(ndev); + +	rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid); +	if (rc) +		goto err_pcp_start; + +	rc = wil_bcast_init(wil); +	if (rc) +		goto err_bcast; + +	goto out; /* success */ + +err_bcast: +	wmi_pcp_stop(wil); +err_pcp_start: +	netif_carrier_off(ndev); +out: +	mutex_unlock(&wil->mutex);  	return rc;  } @@ -741,63 +817,50 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,  				      struct cfg80211_beacon_data *bcon)  {  	struct wil6210_priv *wil = wiphy_to_wil(wiphy); -	struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; -	size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); -	const u8 *pr_ies = NULL; -	size_t pr_ies_len = 0;  	int rc; +	u32 privacy = 0;  	wil_dbg_misc(wil, "%s()\n", __func__);  	wil_print_bcon_data(bcon); -	if (bcon->probe_resp_len > hlen) { -		pr_ies = f->u.probe_resp.variable; -		pr_ies_len = bcon->probe_resp_len - hlen; -	} -  	if (wil_fix_bcon(wil, bcon)) {  		wil_dbg_misc(wil, "Fixed bcon\n");  		wil_print_bcon_data(bcon);  	} -	/* FW do not form regular beacon, so bcon IE's are not set -	 * For the DMG bcon, when it will be supported, bcon IE's will -	 * be reused; add something like: -	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, -	 * bcon->beacon_ies); -	 */ -	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); -	if (rc) { -		wil_err(wil, "set_ie(PROBE_RESP) failed\n"); -		return rc; -	} +	if (bcon->proberesp_ies && +	    cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies, +			     bcon->proberesp_ies_len)) +		privacy = 1; -	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, -			bcon->assocresp_ies_len, -			bcon->assocresp_ies); -	if (rc) { -		wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); -		return rc; +	/* in case privacy has changed, need to restart the AP */ +	if (wil->privacy != privacy) { +		struct wireless_dev *wdev = ndev->ieee80211_ptr; + +		wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", +			     wil->privacy, privacy); + +		rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, +					    wdev->ssid_len, privacy, +					    wdev->beacon_interval, +					    wil->channel, bcon, +					    wil->hidden_ssid); +	} else { +		rc = _wil_cfg80211_set_ies(wiphy, bcon);  	} -	return 0; +	return rc;  }  static int wil_cfg80211_start_ap(struct wiphy *wiphy,  				 struct net_device *ndev,  				 struct cfg80211_ap_settings *info)  { -	int rc = 0; +	int rc;  	struct wil6210_priv *wil = wiphy_to_wil(wiphy); -	struct wireless_dev *wdev = ndev->ieee80211_ptr;  	struct ieee80211_channel *channel = info->chandef.chan;  	struct cfg80211_beacon_data *bcon = &info->beacon;  	struct cfg80211_crypto_settings *crypto = &info->crypto; -	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); -	struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; -	size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); -	const u8 *pr_ies = NULL; -	size_t pr_ies_len = 0;  	u8 hidden_ssid;  	wil_dbg_misc(wil, "%s()\n", __func__); @@ -807,6 +870,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,  		return -EINVAL;  	} +	switch (info->hidden_ssid) { +	case NL80211_HIDDEN_SSID_NOT_IN_USE: +		hidden_ssid = WMI_HIDDEN_SSID_DISABLED; +		break; + +	case NL80211_HIDDEN_SSID_ZERO_LEN: +		hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; +		break; + +	case NL80211_HIDDEN_SSID_ZERO_CONTENTS: +		hidden_ssid = WMI_HIDDEN_SSID_CLEAR; +		break; + +	default: +		wil_err(wil, "AP: Invalid hidden SSID %d\n", info->hidden_ssid); +		return -EOPNOTSUPP; +	}  	wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,  		     channel->center_freq, info->privacy ? "secure" : "open");  	wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", @@ -820,80 +900,16 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,  	wil_print_bcon_data(bcon);  	wil_print_crypto(wil, crypto); -	if (bcon->probe_resp_len > hlen) { -		pr_ies = f->u.probe_resp.variable; -		pr_ies_len = bcon->probe_resp_len - hlen; -	} -  	if (wil_fix_bcon(wil, bcon)) {  		wil_dbg_misc(wil, "Fixed bcon\n");  		wil_print_bcon_data(bcon);  	} -	wil_set_recovery_state(wil, fw_recovery_idle); - -	mutex_lock(&wil->mutex); - -	__wil_down(wil); -	rc = __wil_up(wil); -	if (rc) -		goto out; - -	rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); -	if (rc) -		goto out; - -	/* IE's */ -	/* bcon 'head IE's are not relevant for 60g band */ -	/* -	 * FW do not form regular beacon, so bcon IE's are not set -	 * For the DMG bcon, when it will be supported, bcon IE's will -	 * be reused; add something like: -	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, -	 * bcon->beacon_ies); -	 */ -	wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); -	wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, -		   bcon->assocresp_ies); - -	wil->privacy = info->privacy; - -	switch (info->hidden_ssid) { -	case NL80211_HIDDEN_SSID_NOT_IN_USE: -		hidden_ssid = WMI_HIDDEN_SSID_DISABLED; -		break; - -	case NL80211_HIDDEN_SSID_ZERO_LEN: -		hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; -		break; - -	case NL80211_HIDDEN_SSID_ZERO_CONTENTS: -		hidden_ssid = WMI_HIDDEN_SSID_CLEAR; -		break; - -	default: -		rc = -EOPNOTSUPP; -		goto out; -	} - -	netif_carrier_on(ndev); - -	rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, -			   channel->hw_value, hidden_ssid); -	if (rc) -		goto err_pcp_start; +	rc = _wil_cfg80211_start_ap(wiphy, ndev, +				    info->ssid, info->ssid_len, info->privacy, +				    info->beacon_interval, channel->hw_value, +				    bcon, hidden_ssid); -	rc = wil_bcast_init(wil); -	if (rc) -		goto err_bcast; - -	goto out; /* success */ -err_bcast: -	wmi_pcp_stop(wil); -err_pcp_start: -	netif_carrier_off(ndev); -out: -	mutex_unlock(&wil->mutex);  	return rc;  } diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 75219a1b8805..d1a1e160ef31 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -62,7 +62,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,  	seq_printf(s, "  swhead = %d\n", vring->swhead);  	seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);  	if (x) { -		v = ioread32(x); +		v = readl(x);  		seq_printf(s, "0x%08x = %d\n", v, v);  	} else {  		seq_puts(s, "???\n"); @@ -156,6 +156,12 @@ static const struct file_operations fops_vring = {  	.llseek		= seq_lseek,  }; +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, +			    const char *prefix) +{ +	seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false); +} +  static void wil_print_ring(struct seq_file *s, const char *prefix,  			   void __iomem *off)  { @@ -212,8 +218,6 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,  				   le16_to_cpu(hdr.seq), len,  				   le16_to_cpu(hdr.type), hdr.flags);  			if (len <= MAX_MBOXITEM_SIZE) { -				int n = 0; -				char printbuf[16 * 3 + 2];  				unsigned char databuf[MAX_MBOXITEM_SIZE];  				void __iomem *src = wmi_buffer(wil, d.addr) +  					sizeof(struct wil6210_mbox_hdr); @@ -223,16 +227,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,  				 * reading header  				 */  				wil_memcpy_fromio_32(databuf, src, len); -				while (n < len) { -					int l = min(len - n, 16); - -					hex_dump_to_buffer(databuf + n, l, -							   16, 1, printbuf, -							   sizeof(printbuf), -							   false); -					seq_printf(s, "      : %s\n", printbuf); -					n += l; -				} +				wil_seq_hexdump(s, databuf, len, "      : ");  			}  		} else {  			seq_puts(s, "\n"); @@ -268,7 +263,7 @@ static const struct file_operations fops_mbox = {  static int wil_debugfs_iomem_x32_set(void *data, u64 val)  { -	iowrite32(val, (void __iomem *)data); +	writel(val, (void __iomem *)data);  	wmb(); /* make sure write propagated to HW */  	return 0; @@ -276,7 +271,7 @@ static int wil_debugfs_iomem_x32_set(void *data, u64 val)  static int wil_debugfs_iomem_x32_get(void *data, u64 *val)  { -	*val = ioread32((void __iomem *)data); +	*val = readl((void __iomem *)data);  	return 0;  } @@ -306,7 +301,7 @@ static int wil_debugfs_ulong_get(void *data, u64 *val)  }  DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, -			wil_debugfs_ulong_set, "%llu\n"); +			wil_debugfs_ulong_set, "0x%llx\n");  static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,  					       struct dentry *parent, @@ -477,7 +472,7 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data)  	void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));  	if (a) -		seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); +		seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));  	else  		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); @@ -867,22 +862,6 @@ static const struct file_operations fops_wmi = {  	.open  = simple_open,  }; -static void wil_seq_hexdump(struct seq_file *s, void *p, int len, -			    const char *prefix) -{ -	char printbuf[16 * 3 + 2]; -	int i = 0; - -	while (i < len) { -		int l = min(len - i, 16); - -		hex_dump_to_buffer(p + i, l, 16, 1, printbuf, -				   sizeof(printbuf), false); -		seq_printf(s, "%s%s\n", prefix, printbuf); -		i += l; -	} -} -  static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb)  {  	int i = 0; @@ -1344,6 +1323,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)  {  	int i;  	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; +	unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;  	seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,  		   r->head_seq_num); @@ -1353,7 +1333,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)  		else  			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');  	} -	seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); +	seq_printf(s, +		   "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n", +		   r->total, drop_dup + drop_old, drop_dup, drop_old, +		   r->ssn_last_drop);  }  static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 0ea695ff98ad..7053b62ca8d3 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,19 +50,13 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,  	wil_dbg_misc(wil, "%s()\n", __func__); -	tx_itr_en = ioread32(wil->csr + -			     HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); +	tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);  	if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) -		tx_itr_val = -			ioread32(wil->csr + -				 HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); +		tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); -	rx_itr_en = ioread32(wil->csr + -			     HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); +	rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL);  	if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) -		rx_itr_val = -			ioread32(wil->csr + -				 HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); +		rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);  	cp->tx_coalesce_usecs = tx_itr_val;  	cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 4428345e5a47..82aae2d705b4 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -22,16 +22,6 @@  MODULE_FIRMWARE(WIL_FW_NAME);  MODULE_FIRMWARE(WIL_FW2_NAME); -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#define S(a, v) W(a, R(a) | v) -/* register clear = read, AND with inverted, write */ -#define C(a, v) W(a, R(a) & ~v) -  static  void wil_memset_toio_32(volatile void __iomem *dst, u32 val,  			size_t count) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 157f5ef384e0..d30657ee7e83 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -221,12 +221,12 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,  		FW_ADDR_CHECK(dst, block[i].addr, "address"); -		x = ioread32(dst); +		x = readl(dst);  		y = (x & m) | (v & ~m);  		wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "  			   "(old 0x%08x val 0x%08x mask 0x%08x)\n",  			   le32_to_cpu(block[i].addr), y, x, v, m); -		iowrite32(y, dst); +		writel(y, dst);  		wmb(); /* finish before processing next record */  	} @@ -239,18 +239,18 @@ static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,  {  	unsigned delay = 0; -	iowrite32(a, gwa_addr); -	iowrite32(gw_cmd, gwa_cmd); +	writel(a, gwa_addr); +	writel(gw_cmd, gwa_cmd);  	wmb(); /* finish before activate gw */ -	iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ +	writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */  	do {  		udelay(1); /* typical time is few usec */  		if (delay++ > 100) {  			wil_err_fw(wil, "gw timeout\n");  			return -EINVAL;  		} -	} while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ +	} while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */  	return 0;  } @@ -305,7 +305,7 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,  		wil_dbg_fw(wil, "  gw write[%3d] [0x%08x] <== 0x%08x\n",  			   i, a, v); -		iowrite32(v, gwa_val); +		writel(v, gwa_val);  		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);  		if (rc)  			return rc; @@ -372,7 +372,7 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,  				sizeof(v), false);  		for (k = 0; k < ARRAY_SIZE(block->value); k++) -			iowrite32(v[k], gwa_val[k]); +			writel(v[k], gwa_val[k]);  		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);  		if (rc)  			return rc; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 28ffc18466c4..a371f036d054 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -61,13 +61,13 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr)  static inline void wil_icr_clear(u32 x, void __iomem *addr)  { -	iowrite32(x, addr); +	writel(x, addr);  }  #endif /* defined(CONFIG_WIL6210_ISR_COR) */  static inline u32 wil_ioread32_and_clear(void __iomem *addr)  { -	u32 x = ioread32(addr); +	u32 x = readl(addr);  	wil_icr_clear(x, addr); @@ -76,54 +76,47 @@ static inline u32 wil_ioread32_and_clear(void __iomem *addr)  static void wil6210_mask_irq_tx(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IRQ_DISABLE, wil->csr + -		  HOSTADDR(RGF_DMA_EP_TX_ICR) + -		  offsetof(struct RGF_ICR, IMS)); +	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS), +	      WIL6210_IRQ_DISABLE);  }  static void wil6210_mask_irq_rx(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IRQ_DISABLE, wil->csr + -		  HOSTADDR(RGF_DMA_EP_RX_ICR) + -		  offsetof(struct RGF_ICR, IMS)); +	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS), +	      WIL6210_IRQ_DISABLE);  }  static void wil6210_mask_irq_misc(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IRQ_DISABLE, wil->csr + -		  HOSTADDR(RGF_DMA_EP_MISC_ICR) + -		  offsetof(struct RGF_ICR, IMS)); +	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS), +	      WIL6210_IRQ_DISABLE);  }  static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)  {  	wil_dbg_irq(wil, "%s()\n", __func__); -	iowrite32(WIL6210_IRQ_DISABLE, wil->csr + -		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); +	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE);  	clear_bit(wil_status_irqen, wil->status);  }  void wil6210_unmask_irq_tx(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IMC_TX, wil->csr + -		  HOSTADDR(RGF_DMA_EP_TX_ICR) + -		  offsetof(struct RGF_ICR, IMC)); +	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC), +	      WIL6210_IMC_TX);  }  void wil6210_unmask_irq_rx(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IMC_RX, wil->csr + -		  HOSTADDR(RGF_DMA_EP_RX_ICR) + -		  offsetof(struct RGF_ICR, IMC)); +	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), +	      WIL6210_IMC_RX);  }  static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)  { -	iowrite32(WIL6210_IMC_MISC, wil->csr + -		  HOSTADDR(RGF_DMA_EP_MISC_ICR) + -		  offsetof(struct RGF_ICR, IMC)); +	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC), +	      WIL6210_IMC_MISC);  }  static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) @@ -132,8 +125,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)  	set_bit(wil_status_irqen, wil->status); -	iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + -		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); +	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK);  }  void wil_mask_irq(struct wil6210_priv *wil) @@ -150,12 +142,12 @@ void wil_unmask_irq(struct wil6210_priv *wil)  {  	wil_dbg_irq(wil, "%s()\n", __func__); -	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + -		  offsetof(struct RGF_ICR, ICC)); -	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + -		  offsetof(struct RGF_ICR, ICC)); -	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + -		  offsetof(struct RGF_ICR, ICC)); +	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), +	      WIL_ICR_ICC_VALUE); +	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), +	      WIL_ICR_ICC_VALUE); +	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), +	      WIL_ICR_ICC_VALUE);  	wil6210_unmask_irq_pseudo(wil);  	wil6210_unmask_irq_tx(wil); @@ -163,9 +155,6 @@ void wil_unmask_irq(struct wil6210_priv *wil)  	wil6210_unmask_irq_misc(wil);  } -/* target write operation */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -  void wil_configure_interrupt_moderation(struct wil6210_priv *wil)  {  	wil_dbg_irq(wil, "%s()\n", __func__); @@ -177,44 +166,42 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil)  		return;  	/* Disable and clear tx counter before (re)configuration */ -	W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); -	W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); +	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); +	wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);  	wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",  		 wil->tx_max_burst_duration);  	/* Configure TX max burst duration timer to use usec units */ -	W(RGF_DMA_ITR_TX_CNT_CTL, -	  BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); +	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, +	      BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);  	/* Disable and clear tx idle counter before (re)configuration */ -	W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); -	W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); +	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); +	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);  	wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",  		 wil->tx_interframe_timeout);  	/* Configure TX max burst duration timer to use usec units */ -	W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | -				      BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); +	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | +	      BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);  	/* Disable and clear rx counter before (re)configuration */ -	W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); -	W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); +	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); +	wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);  	wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",  		 wil->rx_max_burst_duration);  	/* Configure TX max burst duration timer to use usec units */ -	W(RGF_DMA_ITR_RX_CNT_CTL, -	  BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); +	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, +	      BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);  	/* Disable and clear rx idle counter before (re)configuration */ -	W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); -	W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); +	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); +	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);  	wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",  		 wil->rx_interframe_timeout);  	/* Configure TX max burst duration timer to use usec units */ -	W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | -				      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); +	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | +	      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);  } -#undef W -  static irqreturn_t wil6210_irq_rx(int irq, void *cookie)  {  	struct wil6210_priv *wil = cookie; @@ -452,27 +439,24 @@ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)  		u32 icr_rx = wil_ioread32_and_clear(wil->csr +  				HOSTADDR(RGF_DMA_EP_RX_ICR) +  				offsetof(struct RGF_ICR, ICR)); -		u32 imv_rx = ioread32(wil->csr + -				HOSTADDR(RGF_DMA_EP_RX_ICR) + -				offsetof(struct RGF_ICR, IMV)); +		u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + +				   offsetof(struct RGF_ICR, IMV));  		u32 icm_tx = wil_ioread32_and_clear(wil->csr +  				HOSTADDR(RGF_DMA_EP_TX_ICR) +  				offsetof(struct RGF_ICR, ICM));  		u32 icr_tx = wil_ioread32_and_clear(wil->csr +  				HOSTADDR(RGF_DMA_EP_TX_ICR) +  				offsetof(struct RGF_ICR, ICR)); -		u32 imv_tx = ioread32(wil->csr + -				HOSTADDR(RGF_DMA_EP_TX_ICR) + -				offsetof(struct RGF_ICR, IMV)); +		u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + +				   offsetof(struct RGF_ICR, IMV));  		u32 icm_misc = wil_ioread32_and_clear(wil->csr +  				HOSTADDR(RGF_DMA_EP_MISC_ICR) +  				offsetof(struct RGF_ICR, ICM));  		u32 icr_misc = wil_ioread32_and_clear(wil->csr +  				HOSTADDR(RGF_DMA_EP_MISC_ICR) +  				offsetof(struct RGF_ICR, ICR)); -		u32 imv_misc = ioread32(wil->csr + -				HOSTADDR(RGF_DMA_EP_MISC_ICR) + -				offsetof(struct RGF_ICR, IMV)); +		u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + +				     offsetof(struct RGF_ICR, IMV));  		wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"  				"Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"  				"Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n" @@ -492,7 +476,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)  {  	irqreturn_t rc = IRQ_HANDLED;  	struct wil6210_priv *wil = cookie; -	u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); +	u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);  	/**  	 * pseudo_cause is Clear-On-Read, no need to ACK @@ -541,48 +525,12 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)  	return rc;  } -static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) -{ -	int rc; -	/* -	 * IRQ's are in the following order: -	 * - Tx -	 * - Rx -	 * - Misc -	 */ - -	rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, -			 WIL_NAME"_tx", wil); -	if (rc) -		return rc; - -	rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, -			 WIL_NAME"_rx", wil); -	if (rc) -		goto free0; - -	rc = request_threaded_irq(irq + 2, wil6210_irq_misc, -				  wil6210_irq_misc_thread, -				  IRQF_SHARED, WIL_NAME"_misc", wil); -	if (rc) -		goto free1; - -	return 0; -	/* error branch */ -free1: -	free_irq(irq + 1, wil); -free0: -	free_irq(irq, wil); - -	return rc; -} -  /* can't use wil_ioread32_and_clear because ICC value is not set yet */  static inline void wil_clear32(void __iomem *addr)  { -	u32 x = ioread32(addr); +	u32 x = readl(addr); -	iowrite32(x, addr); +	writel(x, addr);  }  void wil6210_clear_irq(struct wil6210_priv *wil) @@ -596,19 +544,16 @@ void wil6210_clear_irq(struct wil6210_priv *wil)  	wmb(); /* make sure write completed */  } -int wil6210_init_irq(struct wil6210_priv *wil, int irq) +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)  {  	int rc; -	wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi); +	wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx"); -	if (wil->n_msi == 3) -		rc = wil6210_request_3msi(wil, irq); -	else -		rc = request_threaded_irq(irq, wil6210_hardirq, -					  wil6210_thread_irq, -					  wil->n_msi ? 0 : IRQF_SHARED, -					  WIL_NAME, wil); +	rc = request_threaded_irq(irq, wil6210_hardirq, +				  wil6210_thread_irq, +				  use_msi ? 0 : IRQF_SHARED, +				  WIL_NAME, wil);  	return rc;  } @@ -618,8 +563,4 @@ void wil6210_fini_irq(struct wil6210_priv *wil, int irq)  	wil_mask_irq(wil);  	free_irq(irq, wil); -	if (wil->n_msi == 3) { -		free_irq(irq + 1, wil); -		free_irq(irq + 2, wil); -	}  } diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c index e9c0673819c6..f7f948621951 100644 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ b/drivers/net/wireless/ath/wil6210/ioctl.c @@ -76,11 +76,11 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)  	/* operation */  	switch (io.op & wil_mmio_op_mask) {  	case wil_mmio_read: -		io.val = ioread32(a); +		io.val = readl(a);  		need_copy = true;  		break;  	case wil_mmio_write: -		iowrite32(io.val, a); +		writel(io.val, a);  		wmb(); /* make sure write propagated to HW */  		break;  	default: diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6ca6193ab8a6..2fb04c51da53 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,6 +21,7 @@  #include "wil6210.h"  #include "txrx.h"  #include "wmi.h" +#include "boot_loader.h"  #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000  #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 @@ -270,8 +271,7 @@ static void wil_scan_timer_fn(ulong x)  	clear_bit(wil_status_fwready, wil->status);  	wil_err(wil, "Scan timeout detected, start fw error recovery\n"); -	wil->recovery_state = fw_recovery_pending; -	schedule_work(&wil->fw_error_worker); +	wil_fw_error_recovery(wil);  }  static int wil_wait_for_recovery(struct wil6210_priv *wil) @@ -528,26 +528,16 @@ void wil_priv_deinit(struct wil6210_priv *wil)  	destroy_workqueue(wil->wmi_wq);  } -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#define S(a, v) W(a, R(a) | v) -/* register clear = read, AND with inverted, write */ -#define C(a, v) W(a, R(a) & ~v) -  static inline void wil_halt_cpu(struct wil6210_priv *wil)  { -	W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); -	W(RGF_USER_MAC_CPU_0,  BIT_USER_MAC_CPU_MAN_RST); +	wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); +	wil_w(wil, RGF_USER_MAC_CPU_0,  BIT_USER_MAC_CPU_MAN_RST);  }  static inline void wil_release_cpu(struct wil6210_priv *wil)  {  	/* Start CPU */ -	W(RGF_USER_USER_CPU_0, 1); +	wil_w(wil, RGF_USER_USER_CPU_0, 1);  }  static int wil_target_reset(struct wil6210_priv *wil) @@ -558,56 +548,60 @@ static int wil_target_reset(struct wil6210_priv *wil)  	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);  	/* Clear MAC link up */ -	S(RGF_HP_CTRL, BIT(15)); -	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); -	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); +	wil_s(wil, RGF_HP_CTRL, BIT(15)); +	wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); +	wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);  	wil_halt_cpu(wil);  	/* clear all boot loader "ready" bits */ -	W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); +	wil_w(wil, RGF_USER_BL + +	      offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);  	/* Clear Fw Download notification */ -	C(RGF_USER_USAGE_6, BIT(0)); +	wil_c(wil, RGF_USER_USAGE_6, BIT(0)); -	S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); +	wil_s(wil, RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);  	/* XTAL stabilization should take about 3ms */  	usleep_range(5000, 7000); -	x = R(RGF_CAF_PLL_LOCK_STATUS); +	x = wil_r(wil, RGF_CAF_PLL_LOCK_STATUS);  	if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {  		wil_err(wil, "Xtal stabilization timeout\n"  			"RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);  		return -ETIME;  	}  	/* switch 10k to XTAL*/ -	C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); +	wil_c(wil, RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);  	/* 40 MHz */ -	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); +	wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); -	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); -	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); +	wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); +	wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); -	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); -	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); +	wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); +	wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); +	/* reset A2 PCIE AHB */ +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); +	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);  	/* wait until device ready. typical time is 20..80 msec */  	do {  		msleep(RST_DELAY); -		x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); +		x = wil_r(wil, RGF_USER_BL + +			  offsetof(struct bl_dedicated_registers_v0, +				   boot_loader_ready));  		if (x1 != x) {  			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);  			x1 = x; @@ -617,13 +611,13 @@ static int wil_target_reset(struct wil6210_priv *wil)  				x);  			return -ETIME;  		} -	} while (x != BIT_BL_READY); +	} while (x != BL_READY); -	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); +	wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);  	/* enable fix for HW bug related to the SA/DA swap in AP Rx */ -	S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | -	  BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); +	wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | +	      BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);  	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);  	return 0; @@ -641,29 +635,93 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)  static int wil_get_bl_info(struct wil6210_priv *wil)  {  	struct net_device *ndev = wil_to_ndev(wil); -	struct RGF_BL bl; - -	wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); -	le32_to_cpus(&bl.ready); -	le32_to_cpus(&bl.version); -	le32_to_cpus(&bl.rf_type); -	le32_to_cpus(&bl.baseband_type); +	union { +		struct bl_dedicated_registers_v0 bl0; +		struct bl_dedicated_registers_v1 bl1; +	} bl; +	u32 bl_ver; +	u8 *mac; +	u16 rf_status; + +	wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), +			     sizeof(bl)); +	bl_ver = le32_to_cpu(bl.bl0.boot_loader_struct_version); +	mac = bl.bl0.mac_address; + +	if (bl_ver == 0) { +		le32_to_cpus(&bl.bl0.rf_type); +		le32_to_cpus(&bl.bl0.baseband_type); +		rf_status = 0; /* actually, unknown */ +		wil_info(wil, +			 "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n", +			 bl_ver, mac, +			 bl.bl0.rf_type, bl.bl0.baseband_type); +		wil_info(wil, "Boot Loader build unknown for struct v0\n"); +	} else { +		le16_to_cpus(&bl.bl1.rf_type); +		rf_status = le16_to_cpu(bl.bl1.rf_status); +		le32_to_cpus(&bl.bl1.baseband_type); +		le16_to_cpus(&bl.bl1.bl_version_subminor); +		le16_to_cpus(&bl.bl1.bl_version_build); +		wil_info(wil, +			 "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n", +			 bl_ver, mac, +			 bl.bl1.rf_type, rf_status, +			 bl.bl1.baseband_type); +		wil_info(wil, "Boot Loader build %d.%d.%d.%d\n", +			 bl.bl1.bl_version_major, bl.bl1.bl_version_minor, +			 bl.bl1.bl_version_subminor, bl.bl1.bl_version_build); +	} -	if (!is_valid_ether_addr(bl.mac_address)) { -		wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); +	if (!is_valid_ether_addr(mac)) { +		wil_err(wil, "BL: Invalid MAC %pM\n", mac);  		return -EINVAL;  	} -	ether_addr_copy(ndev->perm_addr, bl.mac_address); +	ether_addr_copy(ndev->perm_addr, mac);  	if (!is_valid_ether_addr(ndev->dev_addr)) -		ether_addr_copy(ndev->dev_addr, bl.mac_address); -	wil_info(wil, -		 "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", -		 bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); +		ether_addr_copy(ndev->dev_addr, mac); + +	if (rf_status) {/* bad RF cable? */ +		wil_err(wil, "RF communication error 0x%04x", +			rf_status); +		return -EAGAIN; +	}  	return 0;  } +static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) +{ +	u32 bl_assert_code, bl_assert_blink, bl_magic_number; +	u32 bl_ver = wil_r(wil, RGF_USER_BL + +			   offsetof(struct bl_dedicated_registers_v0, +				    boot_loader_struct_version)); + +	if (bl_ver < 2) +		return; + +	bl_assert_code = wil_r(wil, RGF_USER_BL + +			       offsetof(struct bl_dedicated_registers_v1, +					bl_assert_code)); +	bl_assert_blink = wil_r(wil, RGF_USER_BL + +				offsetof(struct bl_dedicated_registers_v1, +					 bl_assert_blink)); +	bl_magic_number = wil_r(wil, RGF_USER_BL + +				offsetof(struct bl_dedicated_registers_v1, +					 bl_magic_number)); + +	if (is_err) { +		wil_err(wil, +			"BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", +			bl_assert_code, bl_assert_blink, bl_magic_number); +	} else { +		wil_dbg_misc(wil, +			     "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", +			     bl_assert_code, bl_assert_blink, bl_magic_number); +	} +} +  static int wil_wait_for_fw_ready(struct wil6210_priv *wil)  {  	ulong to = msecs_to_jiffies(1000); @@ -690,9 +748,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  	wil_dbg_misc(wil, "%s()\n", __func__); -	if (wil->hw_version == HW_VER_UNKNOWN) -		return -ENODEV; -  	WARN_ON(!mutex_is_locked(&wil->mutex));  	WARN_ON(test_bit(wil_status_napi_en, wil->status)); @@ -707,6 +762,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  		return 0;  	} +	if (wil->hw_version == HW_VER_UNKNOWN) +		return -ENODEV; +  	cancel_work_sync(&wil->disconnect_worker);  	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);  	wil_bcast_fini(wil); @@ -729,12 +787,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  	flush_workqueue(wil->wq_service);  	flush_workqueue(wil->wmi_wq); +	wil_bl_crash_info(wil, false);  	rc = wil_target_reset(wil);  	wil_rx_fini(wil); -	if (rc) +	if (rc) { +		wil_bl_crash_info(wil, true);  		return rc; +	}  	rc = wil_get_bl_info(wil); +	if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ +		rc = 0;  	if (rc)  		return rc; @@ -752,7 +815,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  			return rc;  		/* Mark FW as loaded from host */ -		S(RGF_USER_USAGE_6, 1); +		wil_s(wil, RGF_USER_USAGE_6, 1);  		/* clear any interrupts which on-card-firmware  		 * may have set @@ -760,8 +823,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  		wil6210_clear_irq(wil);  		/* CAF_ICR - clear and mask */  		/* it is W1C, clear by writing back same value */ -		S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); -		W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); +		wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); +		wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);  		wil_release_cpu(wil);  	} @@ -785,11 +848,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)  	return rc;  } -#undef R -#undef W -#undef S -#undef C -  void wil_fw_error_recovery(struct wil6210_priv *wil)  {  	wil_dbg_misc(wil, "starting fw error recovery\n"); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 8ef18ace110f..e3b3c8fb4605 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -173,7 +173,10 @@ void *wil_if_alloc(struct device *dev)  	wil_set_ethtoolops(ndev);  	ndev->ieee80211_ptr = wdev;  	ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | -			    NETIF_F_SG | NETIF_F_GRO; +			    NETIF_F_SG | NETIF_F_GRO | +			    NETIF_F_TSO | NETIF_F_TSO6 | +			    NETIF_F_RXHASH; +  	ndev->features |= ndev->hw_features;  	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));  	wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index aa3ecc607ca3..feff1ef10fb3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -21,16 +21,14 @@  #include "wil6210.h" -static int use_msi = 1; -module_param(use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, -		 " Use MSI interrupt: " -		 "0 - don't, 1 - (default) - single, or 3"); +static bool use_msi = true; +module_param(use_msi, bool, S_IRUGO); +MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");  static  void wil_set_capabilities(struct wil6210_priv *wil)  { -	u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); +	u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);  	bitmap_zero(wil->hw_capabilities, hw_capability_last); @@ -50,24 +48,12 @@ void wil_set_capabilities(struct wil6210_priv *wil)  void wil_disable_irq(struct wil6210_priv *wil)  { -	int irq = wil->pdev->irq; - -	disable_irq(irq); -	if (wil->n_msi == 3) { -		disable_irq(irq + 1); -		disable_irq(irq + 2); -	} +	disable_irq(wil->pdev->irq);  }  void wil_enable_irq(struct wil6210_priv *wil)  { -	int irq = wil->pdev->irq; - -	enable_irq(irq); -	if (wil->n_msi == 3) { -		enable_irq(irq + 1); -		enable_irq(irq + 2); -	} +	enable_irq(wil->pdev->irq);  }  /* Bus ops */ @@ -80,6 +66,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)  	 * and only MSI should be used  	 */  	int msi_only = pdev->msi_enabled; +	bool _use_msi = use_msi;  	wil_dbg_misc(wil, "%s()\n", __func__); @@ -87,41 +74,20 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)  	pci_set_master(pdev); -	/* -	 * how many MSI interrupts to request? -	 */ -	switch (use_msi) { -	case 3: -	case 1: -		wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); -		break; -	case 0: -		wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); -		break; -	default: -		wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); -		use_msi = 1; -	} - -	if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { -		wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); -		use_msi = 1; -	} +	wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); -	if (use_msi == 1 && pci_enable_msi(pdev)) { +	if (use_msi && pci_enable_msi(pdev)) {  		wil_err(wil, "pci_enable_msi failed, use INTx\n"); -		use_msi = 0; +		_use_msi = false;  	} -	wil->n_msi = use_msi; - -	if ((wil->n_msi == 0) && msi_only) { +	if (!_use_msi && msi_only) {  		wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");  		rc = -ENODEV;  		goto stop_master;  	} -	rc = wil6210_init_irq(wil, pdev->irq); +	rc = wil6210_init_irq(wil, pdev->irq, _use_msi);  	if (rc)  		goto stop_master; @@ -293,11 +259,80 @@ static const struct pci_device_id wil6210_pcie_ids[] = {  };  MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); +#ifdef CONFIG_PM + +static int wil6210_suspend(struct device *dev, bool is_runtime) +{ +	int rc = 0; +	struct pci_dev *pdev = to_pci_dev(dev); +	struct wil6210_priv *wil = pci_get_drvdata(pdev); + +	wil_dbg_pm(wil, "%s(%s)\n", __func__, +		   is_runtime ? "runtime" : "system"); + +	rc = wil_can_suspend(wil, is_runtime); +	if (rc) +		goto out; + +	rc = wil_suspend(wil, is_runtime); +	if (rc) +		goto out; + +	/* TODO: how do I bring card in low power state? */ + +	/* disable bus mastering */ +	pci_clear_master(pdev); +	/* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + +out: +	return rc; +} + +static int wil6210_resume(struct device *dev, bool is_runtime) +{ +	int rc = 0; +	struct pci_dev *pdev = to_pci_dev(dev); +	struct wil6210_priv *wil = pci_get_drvdata(pdev); + +	wil_dbg_pm(wil, "%s(%s)\n", __func__, +		   is_runtime ? "runtime" : "system"); + +	/* allow master */ +	pci_set_master(pdev); + +	rc = wil_resume(wil, is_runtime); +	if (rc) +		pci_clear_master(pdev); + +	return rc; +} + +#ifdef CONFIG_PM_SLEEP +static int wil6210_pm_suspend(struct device *dev) +{ +	return wil6210_suspend(dev, false); +} + +static int wil6210_pm_resume(struct device *dev) +{ +	return wil6210_resume(dev, false); +} +#endif /* CONFIG_PM_SLEEP */ + +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops wil6210_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) +}; +  static struct pci_driver wil6210_driver = {  	.probe		= wil_pcie_probe,  	.remove		= wil_pcie_remove,  	.id_table	= wil6210_pcie_ids,  	.name		= WIL_NAME, +	.driver		= { +		.pm = &wil6210_pm_ops, +	},  };  static int __init wil6210_driver_init(void) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c new file mode 100644 index 000000000000..0b7ecbcac19c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wil6210.h" + +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) +{ +	int rc = 0; +	struct wireless_dev *wdev = wil->wdev; + +	wil_dbg_pm(wil, "%s(%s)\n", __func__, +		   is_runtime ? "runtime" : "system"); + +	switch (wdev->iftype) { +	case NL80211_IFTYPE_MONITOR: +	case NL80211_IFTYPE_STATION: +	case NL80211_IFTYPE_P2P_CLIENT: +		break; +	/* AP-like interface - can't suspend */ +	default: +		wil_dbg_pm(wil, "AP-like interface\n"); +		rc = -EBUSY; +		break; +	} + +	wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__, +		   is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + +	return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ +	int rc = 0; +	struct net_device *ndev = wil_to_ndev(wil); + +	wil_dbg_pm(wil, "%s(%s)\n", __func__, +		   is_runtime ? "runtime" : "system"); + +	/* if netif up, hardware is alive, shut it down */ +	if (ndev->flags & IFF_UP) { +		rc = wil_down(wil); +		if (rc) { +			wil_err(wil, "wil_down : %d\n", rc); +			goto out; +		} +	} + +	if (wil->platform_ops.suspend) +		rc = wil->platform_ops.suspend(wil->platform_handle); + +out: +	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, +		   is_runtime ? "runtime" : "system", rc); +	return rc; +} + +int wil_resume(struct wil6210_priv *wil, bool is_runtime) +{ +	int rc = 0; +	struct net_device *ndev = wil_to_ndev(wil); + +	wil_dbg_pm(wil, "%s(%s)\n", __func__, +		   is_runtime ? "runtime" : "system"); + +	if (wil->platform_ops.resume) { +		rc = wil->platform_ops.resume(wil->platform_handle); +		if (rc) { +			wil_err(wil, "platform_ops.resume : %d\n", rc); +			goto out; +		} +	} + +	/* if netif up, bring hardware up +	 * During open(), IFF_UP set after actual device method +	 * invocation. This prevent recursive call to wil_up() +	 */ +	if (ndev->flags & IFF_UP) +		rc = wil_up(wil); + +out: +	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, +		   is_runtime ? "runtime" : "system", rc); +	return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index ca10dcf0986e..9238c1ac23dd 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -121,6 +121,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)  		goto out;  	} +	r->total++;  	hseq = r->head_seq_num;  	/** Due to the race between WMI events, where BACK establishment @@ -153,6 +154,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)  	/* frame with out of date sequence number */  	if (seq_less(seq, r->head_seq_num)) {  		r->ssn_last_drop = seq; +		r->drop_old++; +		wil_dbg_txrx(wil, "Rx drop: old seq 0x%03x head 0x%03x\n", +			     seq, r->head_seq_num);  		dev_kfree_skb(skb);  		goto out;  	} @@ -173,6 +177,8 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)  	/* check if we already stored this frame */  	if (r->reorder_buf[index]) { +		r->drop_dup++; +		wil_dbg_txrx(wil, "Rx drop: dup seq 0x%03x\n", seq);  		dev_kfree_skb(skb);  		goto out;  	} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index aa20af86e1d6..6229110d558a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -509,7 +509,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)  			break;  		}  	} -	iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); +	wil_w(wil, v->hwtail, v->swtail);  	return rc;  } @@ -541,6 +541,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)  		[GRO_DROP]		= "GRO_DROP",  	}; +	if (ndev->features & NETIF_F_RXHASH) +		/* fake L4 to ensure it won't be re-calculated later +		 * set hash to any non-zero value to activate rps +		 * mechanism, core will be chosen according +		 * to user-level rps configuration. +		 */ +		skb_set_hash(skb, 1, PKT_HASH_TYPE_L4); +  	skb_orphan(skb);  	if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { @@ -1058,14 +1066,52 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,  static inline  void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)  { -	d->mac.d[2] |= ((nr_frags + 1) << -		       MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +	d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);  } -static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, -					 struct vring_tx_desc *d, -					 struct sk_buff *skb) +/** + * Sets the descriptor @d up for csum and/or TSO offloading. The corresponding + * @skb is used to obtain the protocol and headers length. + * @tso_desc_type is a descriptor type for TSO: 0 - a header, 1 - first data, + * 2 - middle, 3 - last descriptor. + */ + +static void wil_tx_desc_offload_setup_tso(struct vring_tx_desc *d, +					  struct sk_buff *skb, +					  int tso_desc_type, bool is_ipv4, +					  int tcp_hdr_len, int skb_net_hdr_len)  { +	d->dma.b11 = ETH_HLEN; /* MAC header length */ +	d->dma.b11 |= is_ipv4 << DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS; + +	d->dma.d0 |= (2 << DMA_CFG_DESC_TX_0_L4_TYPE_POS); +	/* L4 header len: TCP header length */ +	d->dma.d0 |= (tcp_hdr_len & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK); + +	/* Setup TSO: bit and desc type */ +	d->dma.d0 |= (BIT(DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS)) | +		(tso_desc_type << DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS); +	d->dma.d0 |= (is_ipv4 << DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS); + +	d->dma.ip_length = skb_net_hdr_len; +	/* Enable TCP/UDP checksum */ +	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS); +	/* Calculate pseudo-header */ +	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS); +} + +/** + * Sets the descriptor @d up for csum. The corresponding + * @skb is used to obtain the protocol and headers length. + * Returns the protocol: 0 - not TCP, 1 - TCPv4, 2 - TCPv6. + * Note, if d==NULL, the function only returns the protocol result. + * + * It is very similar to previous wil_tx_desc_offload_setup_tso. This + * is "if unrolling" to optimize the critical path. + */ + +static int wil_tx_desc_offload_setup(struct vring_tx_desc *d, +				     struct sk_buff *skb){  	int protocol;  	if (skb->ip_summed != CHECKSUM_PARTIAL) @@ -1110,6 +1156,305 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,  	return 0;  } +static inline void wil_tx_last_desc(struct vring_tx_desc *d) +{ +	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS) | +	      BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS) | +	      BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); +} + +static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d) +{ +	d->dma.d0 |= wil_tso_type_lst << +		  DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS; +} + +static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, +			      struct sk_buff *skb) +{ +	struct device *dev = wil_to_dev(wil); + +	/* point to descriptors in shared memory */ +	volatile struct vring_tx_desc *_desc = NULL, *_hdr_desc, +				      *_first_desc = NULL; + +	/* pointers to shadow descriptors */ +	struct vring_tx_desc desc_mem, hdr_desc_mem, first_desc_mem, +			     *d = &hdr_desc_mem, *hdr_desc = &hdr_desc_mem, +			     *first_desc = &first_desc_mem; + +	/* pointer to shadow descriptors' context */ +	struct wil_ctx *hdr_ctx, *first_ctx = NULL; + +	int descs_used = 0; /* total number of used descriptors */ +	int sg_desc_cnt = 0; /* number of descriptors for current mss*/ + +	u32 swhead = vring->swhead; +	int used, avail = wil_vring_avail_tx(vring); +	int nr_frags = skb_shinfo(skb)->nr_frags; +	int min_desc_required = nr_frags + 1; +	int mss = skb_shinfo(skb)->gso_size;	/* payload size w/o headers */ +	int f, len, hdrlen, headlen; +	int vring_index = vring - wil->vring_tx; +	struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; +	uint i = swhead; +	dma_addr_t pa; +	const skb_frag_t *frag = NULL; +	int rem_data = mss; +	int lenmss; +	int hdr_compensation_need = true; +	int desc_tso_type = wil_tso_type_first; +	bool is_ipv4; +	int tcp_hdr_len; +	int skb_net_hdr_len; +	int gso_type; + +	wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", +		     __func__, skb->len, vring_index); + +	if (unlikely(!txdata->enabled)) +		return -EINVAL; + +	/* A typical page 4K is 3-4 payloads, we assume each fragment +	 * is a full payload, that's how min_desc_required has been +	 * calculated. In real we might need more or less descriptors, +	 * this is the initial check only. +	 */ +	if (unlikely(avail < min_desc_required)) { +		wil_err_ratelimited(wil, +				    "TSO: Tx ring[%2d] full. No space for %d fragments\n", +				    vring_index, min_desc_required); +		return -ENOMEM; +	} + +	/* Header Length = MAC header len + IP header len + TCP header len*/ +	hdrlen = ETH_HLEN + +		(int)skb_network_header_len(skb) + +		tcp_hdrlen(skb); + +	gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV6 | SKB_GSO_TCPV4); +	switch (gso_type) { +	case SKB_GSO_TCPV4: +		/* TCP v4, zero out the IP length and IPv4 checksum fields +		 * as required by the offloading doc +		 */ +		ip_hdr(skb)->tot_len = 0; +		ip_hdr(skb)->check = 0; +		is_ipv4 = true; +		break; +	case SKB_GSO_TCPV6: +		/* TCP v6, zero out the payload length */ +		ipv6_hdr(skb)->payload_len = 0; +		is_ipv4 = false; +		break; +	default: +		/* other than TCPv4 or TCPv6 types are not supported for TSO. +		 * It is also illegal for both to be set simultaneously +		 */ +		return -EINVAL; +	} + +	if (skb->ip_summed != CHECKSUM_PARTIAL) +		return -EINVAL; + +	/* tcp header length and skb network header length are fixed for all +	 * packet's descriptors - read then once here +	 */ +	tcp_hdr_len = tcp_hdrlen(skb); +	skb_net_hdr_len = skb_network_header_len(skb); + +	_hdr_desc = &vring->va[i].tx; + +	pa = dma_map_single(dev, skb->data, hdrlen, DMA_TO_DEVICE); +	if (unlikely(dma_mapping_error(dev, pa))) { +		wil_err(wil, "TSO: Skb head DMA map error\n"); +		goto err_exit; +	} + +	wil_tx_desc_map(hdr_desc, pa, hdrlen, vring_index); +	wil_tx_desc_offload_setup_tso(hdr_desc, skb, wil_tso_type_hdr, is_ipv4, +				      tcp_hdr_len, skb_net_hdr_len); +	wil_tx_last_desc(hdr_desc); + +	vring->ctx[i].mapped_as = wil_mapped_as_single; +	hdr_ctx = &vring->ctx[i]; + +	descs_used++; +	headlen = skb_headlen(skb) - hdrlen; + +	for (f = headlen ? -1 : 0; f < nr_frags; f++)  { +		if (headlen) { +			len = headlen; +			wil_dbg_txrx(wil, "TSO: process skb head, len %u\n", +				     len); +		} else { +			frag = &skb_shinfo(skb)->frags[f]; +			len = frag->size; +			wil_dbg_txrx(wil, "TSO: frag[%d]: len %u\n", f, len); +		} + +		while (len) { +			wil_dbg_txrx(wil, +				     "TSO: len %d, rem_data %d, descs_used %d\n", +				     len, rem_data, descs_used); + +			if (descs_used == avail)  { +				wil_err(wil, "TSO: ring overflow\n"); +				goto dma_error; +			} + +			lenmss = min_t(int, rem_data, len); +			i = (swhead + descs_used) % vring->size; +			wil_dbg_txrx(wil, "TSO: lenmss %d, i %d\n", lenmss, i); + +			if (!headlen) { +				pa = skb_frag_dma_map(dev, frag, +						      frag->size - len, lenmss, +						      DMA_TO_DEVICE); +				vring->ctx[i].mapped_as = wil_mapped_as_page; +			} else { +				pa = dma_map_single(dev, +						    skb->data + +						    skb_headlen(skb) - headlen, +						    lenmss, +						    DMA_TO_DEVICE); +				vring->ctx[i].mapped_as = wil_mapped_as_single; +				headlen -= lenmss; +			} + +			if (unlikely(dma_mapping_error(dev, pa))) +				goto dma_error; + +			_desc = &vring->va[i].tx; + +			if (!_first_desc) { +				_first_desc = _desc; +				first_ctx = &vring->ctx[i]; +				d = first_desc; +			} else { +				d = &desc_mem; +			} + +			wil_tx_desc_map(d, pa, lenmss, vring_index); +			wil_tx_desc_offload_setup_tso(d, skb, desc_tso_type, +						      is_ipv4, tcp_hdr_len, +						      skb_net_hdr_len); + +			/* use tso_type_first only once */ +			desc_tso_type = wil_tso_type_mid; + +			descs_used++;  /* desc used so far */ +			sg_desc_cnt++; /* desc used for this segment */ +			len -= lenmss; +			rem_data -= lenmss; + +			wil_dbg_txrx(wil, +				     "TSO: len %d, rem_data %d, descs_used %d, sg_desc_cnt %d,\n", +				     len, rem_data, descs_used, sg_desc_cnt); + +			/* Close the segment if reached mss size or last frag*/ +			if (rem_data == 0 || (f == nr_frags - 1 && len == 0)) { +				if (hdr_compensation_need) { +					/* first segment include hdr desc for +					 * release +					 */ +					hdr_ctx->nr_frags = sg_desc_cnt; +					wil_tx_desc_set_nr_frags(first_desc, +								 sg_desc_cnt + +								 1); +					hdr_compensation_need = false; +				} else { +					wil_tx_desc_set_nr_frags(first_desc, +								 sg_desc_cnt); +				} +				first_ctx->nr_frags = sg_desc_cnt - 1; + +				wil_tx_last_desc(d); + +				/* first descriptor may also be the last +				 * for this mss - make sure not to copy +				 * it twice +				 */ +				if (first_desc != d) +					*_first_desc = *first_desc; + +				/*last descriptor will be copied at the end +				 * of this TS processing +				 */ +				if (f < nr_frags - 1 || len > 0) +					*_desc = *d; + +				rem_data = mss; +				_first_desc = NULL; +				sg_desc_cnt = 0; +			} else if (first_desc != d) /* update mid descriptor */ +					*_desc = *d; +		} +	} + +	/* first descriptor may also be the last. +	 * in this case d pointer is invalid +	 */ +	if (_first_desc == _desc) +		d = first_desc; + +	/* Last data descriptor */ +	wil_set_tx_desc_last_tso(d); +	*_desc = *d; + +	/* Fill the total number of descriptors in first desc (hdr)*/ +	wil_tx_desc_set_nr_frags(hdr_desc, descs_used); +	*_hdr_desc = *hdr_desc; + +	/* hold reference to skb +	 * to prevent skb release before accounting +	 * in case of immediate "tx done" +	 */ +	vring->ctx[i].skb = skb_get(skb); + +	/* performance monitoring */ +	used = wil_vring_used_tx(vring); +	if (wil_val_in_range(vring_idle_trsh, +			     used, used + descs_used)) { +		txdata->idle += get_cycles() - txdata->last_idle; +		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n", +			     vring_index, used, used + descs_used); +	} + +	/* advance swhead */ +	wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead); +	wil_vring_advance_head(vring, descs_used); + +	/* make sure all writes to descriptors (shared memory) are done before +	 * committing them to HW +	 */ +	wmb(); + +	wil_w(wil, vring->hwtail, vring->swhead); +	return 0; + +dma_error: +	wil_err(wil, "TSO: DMA map page error\n"); +	while (descs_used > 0) { +		struct wil_ctx *ctx; + +		i = (swhead + descs_used) % vring->size; +		d = (struct vring_tx_desc *)&vring->va[i].tx; +		_desc = &vring->va[i].tx; +		*d = *_desc; +		_desc->dma.status = TX_DMA_STATUS_DU; +		ctx = &vring->ctx[i]; +		wil_txdesc_unmap(dev, d, ctx); +		if (ctx->skb) +			dev_kfree_skb_any(ctx->skb); +		memset(ctx, 0, sizeof(*ctx)); +		descs_used--; +	} + +err_exit: +	return -EINVAL; +} +  static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  			  struct sk_buff *skb)  { @@ -1128,7 +1473,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	bool mcast = (vring_index == wil->bcast_vring);  	uint len = skb_headlen(skb); -	wil_dbg_txrx(wil, "%s()\n", __func__); +	wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", +		     __func__, skb->len, vring_index);  	if (unlikely(!txdata->enabled))  		return -EINVAL; @@ -1159,14 +1505,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  			d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);  	}  	/* Process TCP/UDP checksum offloading */ -	if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { +	if (unlikely(wil_tx_desc_offload_setup(d, skb))) {  		wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n",  			vring_index);  		goto dma_error;  	}  	vring->ctx[i].nr_frags = nr_frags; -	wil_tx_desc_set_nr_frags(d, nr_frags); +	wil_tx_desc_set_nr_frags(d, nr_frags + 1);  	/* middle segments */  	for (; f < nr_frags; f++) { @@ -1190,7 +1536,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  		 * if it succeeded for 1-st descriptor,  		 * it will succeed here too  		 */ -		wil_tx_desc_offload_cksum_set(wil, d, skb); +		wil_tx_desc_offload_setup(d, skb);  	}  	/* for the last seg only */  	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); @@ -1221,7 +1567,13 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead,  		     vring->swhead);  	trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); -	iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + +	/* make sure all writes to descriptors (shared memory) are done before +	 * committing them to HW +	 */ +	wmb(); + +	wil_w(wil, vring->hwtail, vring->swhead);  	return 0;   dma_error: @@ -1254,8 +1606,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	int rc;  	spin_lock(&txdata->lock); -	rc = __wil_tx_vring(wil, vring, skb); + +	rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) +	     (wil, vring, skb); +  	spin_unlock(&txdata->lock); +  	return rc;  } @@ -1382,7 +1738,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)  		struct wil_ctx *ctx = &vring->ctx[vring->swtail];  		/**  		 * For the fragmented skb, HW will set DU bit only for the -		 * last fragment. look for it +		 * last fragment. look for it. +		 * In TSO the first DU will include hdr desc  		 */  		int lf = (vring->swtail + ctx->nr_frags) % vring->size;  		/* TODO: check we are not past head */ diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 0c4638487c74..82a8f9a030e7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -291,6 +291,14 @@ struct vring_tx_dma {  	__le16 length;  } __packed; +/* TSO type used in dma descriptor d0 bits 11-12 */ +enum { +	wil_tso_type_hdr = 0, +	wil_tso_type_first = 1, +	wil_tso_type_mid  = 2, +	wil_tso_type_lst  = 3, +}; +  /* Rx descriptor - MAC part   * [dword 0]   * bit  0.. 3 : tid:4 The QoS (b3-0) TID Field diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 275355d46a36..dd4ea926b8e3 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -127,16 +127,6 @@ struct RGF_ICR {  	u32 IMC; /* Mask Clear, write 1 to clear */  } __packed; -struct RGF_BL { -	u32 ready;		/* 0x880A3C bit [0] */ -#define BIT_BL_READY	BIT(0) -	u32 version;		/* 0x880A40 version of the BL struct */ -	u32 rf_type;		/* 0x880A44 ID of the connected RF */ -	u32 baseband_type;	/* 0x880A48 ID of the baseband */ -	u8  mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ -	u8 pad[2]; -} __packed; -  /* registers - FW addresses */  #define RGF_USER_USAGE_1		(0x880004)  #define RGF_USER_USAGE_6		(0x880018) @@ -262,9 +252,8 @@ enum {  };  /* popular locations */ -#define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD) -#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ -	offsetof(struct RGF_ICR, ICS)) +#define RGF_MBOX   RGF_USER_USER_SCRATCH_PAD +#define HOST_MBOX   HOSTADDR(RGF_MBOX)  #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2  /* ISR register bits */ @@ -434,12 +423,12 @@ struct pci_dev;   * @ssn: Starting Sequence Number expected to be aggregated.   * @buf_size: buffer size for incoming A-MPDUs   * @timeout: reset timer value (in TUs). + * @ssn_last_drop: SSN of the last dropped frame + * @total: total number of processed incoming frames + * @drop_dup: duplicate frames dropped for this reorder buffer + * @drop_old: old frames dropped for this reorder buffer   * @dialog_token: dialog token for aggregation session - * @rcu_head: RCU head used for freeing this struct - * - * This structure's lifetime is managed by RCU, assignments to - * the array holding it must hold the aggregation mutex. - * + * @first_time: true when this buffer used 1-st time   */  struct wil_tid_ampdu_rx {  	struct sk_buff **reorder_buf; @@ -453,6 +442,9 @@ struct wil_tid_ampdu_rx {  	u16 buf_size;  	u16 timeout;  	u16 ssn_last_drop; +	unsigned long long total; /* frames processed */ +	unsigned long long drop_dup; +	unsigned long long drop_old;  	u8 dialog_token;  	bool first_time; /* is it 1-st time this buffer used? */  }; @@ -543,7 +535,6 @@ struct pmc_ctx {  struct wil6210_priv {  	struct pci_dev *pdev; -	int n_msi;  	struct wireless_dev *wdev;  	void __iomem *csr;  	DECLARE_BITMAP(status, wil_status_last); @@ -559,6 +550,8 @@ struct wil6210_priv {  	/* profile */  	u32 monitor_flags;  	u32 privacy; /* secure connection? */ +	u8 hidden_ssid; /* relevant in AP mode */ +	u16 channel; /* relevant in AP mode */  	int sinfo_gen;  	u32 ap_isolate; /* no intra-BSS communication */  	/* interrupt moderation */ @@ -654,6 +647,33 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...);  #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)  #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)  #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +#define wil_dbg_pm(wil, fmt, arg...) wil_dbg(wil, "DBG[ PM ]" fmt, ##arg) + +/* target operations */ +/* register read */ +static inline u32 wil_r(struct wil6210_priv *wil, u32 reg) +{ +	return readl(wil->csr + HOSTADDR(reg)); +} + +/* register write. wmb() to make sure it is completed */ +static inline void wil_w(struct wil6210_priv *wil, u32 reg, u32 val) +{ +	writel(val, wil->csr + HOSTADDR(reg)); +	wmb(); /* wait for write to propagate to the HW */ +} + +/* register set = read, OR, write */ +static inline void wil_s(struct wil6210_priv *wil, u32 reg, u32 val) +{ +	wil_w(wil, reg, wil_r(wil, reg) | val); +} + +/* register clear = read, AND with inverted, write */ +static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) +{ +	wil_w(wil, reg, wil_r(wil, reg) & ~val); +}  #if defined(CONFIG_DYNAMIC_DEBUG)  #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize,	\ @@ -744,7 +764,7 @@ void wil_back_tx_worker(struct work_struct *work);  void wil_back_tx_flush(struct wil6210_priv *wil);  void wil6210_clear_irq(struct wil6210_priv *wil); -int wil6210_init_irq(struct wil6210_priv *wil, int irq); +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi);  void wil6210_fini_irq(struct wil6210_priv *wil, int irq);  void wil_mask_irq(struct wil6210_priv *wil);  void wil_unmask_irq(struct wil6210_priv *wil); @@ -796,4 +816,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type);  int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);  int wil_request_firmware(struct wil6210_priv *wil, const char *name); +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_resume(struct wil6210_priv *wil, bool is_runtime); +  #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index de15f1422fe9..2e831bf20117 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -14,7 +14,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include "linux/device.h" +#include <linux/device.h>  #include "wil_platform.h"  int __init wil_platform_modinit(void) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c759759afbb2..2f35d4c51f34 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -228,8 +228,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)  	wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);  	/* wait till FW finish with previous command */  	for (retry = 5; retry > 0; retry--) { -		r->tail = ioread32(wil->csr + HOST_MBOX + -				   offsetof(struct wil6210_mbox_ctl, tx.tail)); +		r->tail = wil_r(wil, RGF_MBOX + +				offsetof(struct wil6210_mbox_ctl, tx.tail));  		if (next_head != r->tail)  			break;  		msleep(20); @@ -254,16 +254,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)  	wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));  	wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);  	/* mark entry as full */ -	iowrite32(1, wil->csr + HOSTADDR(r->head) + -		  offsetof(struct wil6210_mbox_ring_desc, sync)); +	wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);  	/* advance next ptr */ -	iowrite32(r->head = next_head, wil->csr + HOST_MBOX + -		  offsetof(struct wil6210_mbox_ctl, tx.head)); +	wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head), +	      r->head = next_head);  	trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);  	/* interrupt to FW */ -	iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); +	wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS), +	      SW_INT_MBOX);  	return 0;  } @@ -312,22 +312,44 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)  	struct wiphy *wiphy = wil_to_wiphy(wil);  	struct ieee80211_mgmt *rx_mgmt_frame =  			(struct ieee80211_mgmt *)data->payload; -	int ch_no = data->info.channel+1; -	u32 freq = ieee80211_channel_to_frequency(ch_no, -			IEEE80211_BAND_60GHZ); -	struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); -	s32 signal = data->info.sqi; -	__le16 fc = rx_mgmt_frame->frame_control; -	u32 d_len = le32_to_cpu(data->info.len); -	u16 d_status = le16_to_cpu(data->info.status); - -	wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", +	int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload); +	int ch_no; +	u32 freq; +	struct ieee80211_channel *channel; +	s32 signal; +	__le16 fc; +	u32 d_len; +	u16 d_status; + +	if (flen < 0) { +		wil_err(wil, "MGMT Rx: short event, len %d\n", len); +		return; +	} + +	d_len = le32_to_cpu(data->info.len); +	if (d_len != flen) { +		wil_err(wil, +			"MGMT Rx: length mismatch, d_len %d should be %d\n", +			d_len, flen); +		return; +	} + +	ch_no = data->info.channel + 1; +	freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); +	channel = ieee80211_get_channel(wiphy, freq); +	signal = data->info.sqi; +	d_status = le16_to_cpu(data->info.status); +	fc = rx_mgmt_frame->frame_control; + +	wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n",  		    data->info.channel, data->info.mcs, data->info.snr,  		    data->info.sqi);  	wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,  		    le16_to_cpu(fc));  	wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",  		    data->info.qid, data->info.mid, data->info.cid); +	wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame, +			 d_len, true);  	if (!channel) {  		wil_err(wil, "Frame on unsupported channel\n"); @@ -363,6 +385,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)  	}  } +static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) +{ +	struct wmi_tx_mgmt_packet_event *data = d; +	struct ieee80211_mgmt *mgmt_frame = +			(struct ieee80211_mgmt *)data->payload; +	int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload); + +	wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame, +			 flen, true); +} +  static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,  				  void *d, int len)  { @@ -659,6 +692,7 @@ static const struct {  	{WMI_READY_EVENTID,		wmi_evt_ready},  	{WMI_FW_READY_EVENTID,		wmi_evt_fw_ready},  	{WMI_RX_MGMT_PACKET_EVENTID,	wmi_evt_rx_mgmt}, +	{WMI_TX_MGMT_PACKET_EVENTID,		wmi_evt_tx_mgmt},  	{WMI_SCAN_COMPLETE_EVENTID,	wmi_evt_scan_complete},  	{WMI_CONNECT_EVENTID,		wmi_evt_connect},  	{WMI_DISCONNECT_EVENTID,	wmi_evt_disconnect}, @@ -695,8 +729,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  		u16 len;  		bool q; -		r->head = ioread32(wil->csr + HOST_MBOX + -				   offsetof(struct wil6210_mbox_ctl, rx.head)); +		r->head = wil_r(wil, RGF_MBOX + +				offsetof(struct wil6210_mbox_ctl, rx.head));  		if (r->tail == r->head)  			break; @@ -734,8 +768,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  		cmd = (void *)&evt->event.wmi;  		wil_memcpy_fromio_32(cmd, src, len);  		/* mark entry as empty */ -		iowrite32(0, wil->csr + HOSTADDR(r->tail) + -			  offsetof(struct wil6210_mbox_ring_desc, sync)); +		wil_w(wil, r->tail + +		      offsetof(struct wil6210_mbox_ring_desc, sync), 0);  		/* indicate */  		if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&  		    (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { @@ -754,8 +788,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  		/* advance tail */  		r->tail = r->base + ((r->tail - r->base +  			  sizeof(struct wil6210_mbox_ring_desc)) % r->size); -		iowrite32(r->tail, wil->csr + HOST_MBOX + -			  offsetof(struct wil6210_mbox_ctl, rx.tail)); +		wil_w(wil, RGF_MBOX + +		      offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);  		/* add to the pending list */  		spin_lock_irqsave(&wil->wmi_ev_lock, flags); @@ -772,7 +806,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,  	     u16 reply_id, void *reply, u8 reply_size, int to_msec)  {  	int rc; -	int remain; +	unsigned long remain;  	mutex_lock(&wil->wmi_mutex); @@ -988,12 +1022,21 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,  int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)  { +	static const char *const names[] = { +		[WMI_FRAME_BEACON]	= "BEACON", +		[WMI_FRAME_PROBE_REQ]	= "PROBE_REQ", +		[WMI_FRAME_PROBE_RESP]	= "WMI_FRAME_PROBE_RESP", +		[WMI_FRAME_ASSOC_REQ]	= "WMI_FRAME_ASSOC_REQ", +		[WMI_FRAME_ASSOC_RESP]	= "WMI_FRAME_ASSOC_RESP", +	};  	int rc;  	u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;  	struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); -	if (!cmd) -		return -ENOMEM; +	if (!cmd) { +		rc = -ENOMEM; +		goto out; +	}  	if (!ie)  		ie_len = 0; @@ -1003,6 +1046,12 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)  	memcpy(cmd->ie_info, ie, ie_len);  	rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);  	kfree(cmd); +out: +	if (rc) { +		const char *name = type < ARRAY_SIZE(names) ? +				   names[type] : "??"; +		wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc); +	}  	return rc;  } @@ -1129,15 +1178,42 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)  int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)  { +	int rc; +	u16 reason_code;  	struct wmi_disconnect_sta_cmd cmd = {  		.disconnect_reason = cpu_to_le16(reason),  	}; +	struct { +		struct wil6210_mbox_hdr_wmi wmi; +		struct wmi_disconnect_event evt; +	} __packed reply;  	ether_addr_copy(cmd.dst_mac, mac);  	wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); -	return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); +	rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd), +		      WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000); +	/* failure to disconnect in reasonable time treated as FW error */ +	if (rc) { +		wil_fw_error_recovery(wil); +		return rc; +	} + +	/* call event handler manually after processing wmi_call, +	 * to avoid deadlock - disconnect event handler acquires wil->mutex +	 * while it is already held here +	 */ +	reason_code = le16_to_cpu(reply.evt.protocol_reason_status); + +	wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", +		    reply.evt.bssid, reason_code, +		    reply.evt.disconnect_reason); + +	wil->sinfo_gen++; +	wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + +	return 0;  }  int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) @@ -1279,7 +1355,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,  		/* search for handler */  		if (!wmi_evt_call_handler(wil, id, evt_data,  					  len - sizeof(*wmi))) { -			wil_err(wil, "Unhandled event 0x%04x\n", id); +			wil_info(wil, "Unhandled event 0x%04x\n", id);  		}  	} else {  		wil_err(wil, "Unknown event type\n"); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 916123a3d74e..a335f94c72ff 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -929,8 +929,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,  	b43_lo_write(dev, &cal->ctl);  } -/* Periodic LO maintanance work */ -void b43_lo_g_maintanance_work(struct b43_wldev *dev) +/* Periodic LO maintenance work */ +void b43_lo_g_maintenance_work(struct b43_wldev *dev)  {  	struct b43_phy *phy = &dev->phy;  	struct b43_phy_g *gphy = phy->g; diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 3b27e20eff80..7b4df3883bc2 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -80,7 +80,7 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,  void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_maintenance_work(struct b43_wldev *dev);  void b43_lo_g_cleanup(struct b43_wldev *dev);  void b43_lo_g_init(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 727ce6edb4b3..462310e6e88f 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3004,7 +3004,7 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)  		   phy->rev == 1) {  		//TODO: implement rev1 workaround  	} -	b43_lo_g_maintanance_work(dev); +	b43_lo_g_maintenance_work(dev);  	b43_mac_enable(dev);  } diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 25d1cbd34306..b2f0d245bcf3 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)  		switch (phy->rev) {  		case 6:  		case 5: -			if (sprom->fem.ghz5.extpa_gain == 3) +			if (sprom->fem.ghz2.extpa_gain == 3)  				return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g;  			/* fall through */  		case 4: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index d86d1f1f1c91..a293275c1b0b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 len)  	return NULL;  } +static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, +				     struct brcmf_cfg80211_vif *vif, +				     enum nl80211_iftype new_type) +{ +	int iftype_num[NUM_NL80211_IFTYPES]; +	struct brcmf_cfg80211_vif *pos; + +	memset(&iftype_num[0], 0, sizeof(iftype_num)); +	list_for_each_entry(pos, &cfg->vif_list, list) +		if (pos == vif) +			iftype_num[new_type]++; +		else +			iftype_num[pos->wdev.iftype]++; + +	return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +} + +static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, +				  enum nl80211_iftype new_type) +{ +	int iftype_num[NUM_NL80211_IFTYPES]; +	struct brcmf_cfg80211_vif *pos; + +	memset(&iftype_num[0], 0, sizeof(iftype_num)); +	list_for_each_entry(pos, &cfg->vif_list, list) +		iftype_num[pos->wdev.iftype]++; + +	iftype_num[new_type]++; +	return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +}  static void convert_key_from_CPU(struct brcmf_wsec_key *key,  				 struct brcmf_wsec_key_le *key_le) @@ -663,8 +693,14 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,  						     struct vif_params *params)  {  	struct wireless_dev *wdev; +	int err;  	brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); +	err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); +	if (err) { +		brcmf_err("iface validation failed: err=%d\n", err); +		return ERR_PTR(err); +	}  	switch (type) {  	case NL80211_IFTYPE_ADHOC:  	case NL80211_IFTYPE_STATION: @@ -823,8 +859,12 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  	s32 ap = 0;  	s32 err = 0; -	brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type); - +	brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type); +	err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type); +	if (err) { +		brcmf_err("iface validation failed: err=%d\n", err); +		return err; +	}  	switch (type) {  	case NL80211_IFTYPE_MONITOR:  	case NL80211_IFTYPE_WDS: @@ -5695,63 +5735,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {  	}  }; +/** + * brcmf_setup_ifmodes() - determine interface modes and combinations. + * + * @wiphy: wiphy object. + * @ifp: interface object needed for feat module api. + * + * The interface modes and combinations are determined dynamically here + * based on firmware functionality. + * + * no p2p and no mbss: + * + *	#STA <= 1, #AP <= 1, channels = 1, 2 total + * + * no p2p and mbss: + * + *	#STA <= 1, #AP <= 1, channels = 1, 2 total + *	#AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, no mchan, and mbss: + * + *	#STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total + *	#STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + *	#AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, mchan, and mbss: + * + *	#STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total + *	#STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + *	#AP <= 4, matching BI, channels = 1, 4 total + */  static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)  {  	struct ieee80211_iface_combination *combo = NULL; -	struct ieee80211_iface_limit *limits = NULL; -	int i = 0, max_iface_cnt; +	struct ieee80211_iface_limit *c0_limits = NULL; +	struct ieee80211_iface_limit *p2p_limits = NULL; +	struct ieee80211_iface_limit *mbss_limits = NULL; +	bool mbss, p2p; +	int i, c, n_combos; -	combo = kzalloc(sizeof(*combo), GFP_KERNEL); +	mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); +	p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); + +	n_combos = 1 + !!p2p + !!mbss; +	combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);  	if (!combo)  		goto err; -	limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL); -	if (!limits) +	c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); +	if (!c0_limits)  		goto err; +	if (p2p) { +		p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); +		if (!p2p_limits) +			goto err; +	} + +	if (mbss) { +		mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); +		if (!mbss_limits) +			goto err; +	} +  	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |  				 BIT(NL80211_IFTYPE_ADHOC) |  				 BIT(NL80211_IFTYPE_AP); -	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) -		combo->num_different_channels = 2; -	else -		combo->num_different_channels = 1; - -	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { -		limits[i].max = 1; -		limits[i++].types = BIT(NL80211_IFTYPE_STATION); -		limits[i].max = 4; -		limits[i++].types = BIT(NL80211_IFTYPE_AP); -		max_iface_cnt = 5; -	} else { -		limits[i].max = 2; -		limits[i++].types = BIT(NL80211_IFTYPE_STATION) | -				    BIT(NL80211_IFTYPE_AP); -		max_iface_cnt = 2; -	} - -	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) { +	c = 0; +	i = 0; +	combo[c].num_different_channels = 1; +	c0_limits[i].max = 1; +	c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); +	if (p2p) { +		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) +			combo[c].num_different_channels = 2;  		wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |  					  BIT(NL80211_IFTYPE_P2P_GO) |  					  BIT(NL80211_IFTYPE_P2P_DEVICE); -		limits[i].max = 1; -		limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | -				    BIT(NL80211_IFTYPE_P2P_GO); -		limits[i].max = 1; -		limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); -		max_iface_cnt += 2; -	} -	combo->max_interfaces = max_iface_cnt; -	combo->limits = limits; -	combo->n_limits = i; - +		c0_limits[i].max = 1; +		c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); +		c0_limits[i].max = 1; +		c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | +				       BIT(NL80211_IFTYPE_P2P_GO); +	} else { +		c0_limits[i].max = 1; +		c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); +	} +	combo[c].max_interfaces = i; +	combo[c].n_limits = i; +	combo[c].limits = c0_limits; + +	if (p2p) { +		c++; +		i = 0; +		combo[c].num_different_channels = 1; +		p2p_limits[i].max = 1; +		p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); +		p2p_limits[i].max = 1; +		p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP); +		p2p_limits[i].max = 1; +		p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); +		p2p_limits[i].max = 1; +		p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); +		combo[c].max_interfaces = i; +		combo[c].n_limits = i; +		combo[c].limits = p2p_limits; +	} + +	if (mbss) { +		c++; +		combo[c].beacon_int_infra_match = true; +		combo[c].num_different_channels = 1; +		mbss_limits[0].max = 4; +		mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); +		combo[c].max_interfaces = 4; +		combo[c].n_limits = 1; +		combo[c].limits = mbss_limits; +	} +	wiphy->n_iface_combinations = n_combos;  	wiphy->iface_combinations = combo; -	wiphy->n_iface_combinations = 1;  	return 0;  err: -	kfree(limits); +	kfree(c0_limits); +	kfree(p2p_limits); +	kfree(mbss_limits);  	kfree(combo);  	return -ENOMEM;  } @@ -5785,7 +5894,10 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)  static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)  { +	struct brcmf_pub *drvr = ifp->drvr; +	const struct ieee80211_iface_combination *combo;  	struct ieee80211_supported_band *band; +	u16 max_interfaces = 0;  	__le32 bandlist[3];  	u32 n_bands;  	int err, i; @@ -5798,6 +5910,24 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)  	if (err)  		return err; +	for (i = 0, combo = wiphy->iface_combinations; +	     i < wiphy->n_iface_combinations; i++, combo++) { +		max_interfaces = max(max_interfaces, combo->max_interfaces); +	} + +	for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses); +	     i++) { +		u8 *addr = drvr->addresses[i].addr; + +		memcpy(addr, drvr->mac, ETH_ALEN); +		if (i) { +			addr[0] |= BIT(1); +			addr[ETH_ALEN - 1] ^= i; +		} +	} +	wiphy->addresses = drvr->addresses; +	wiphy->n_addresses = i; +  	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;  	wiphy->cipher_suites = __wl_cipher_suites;  	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -6059,11 +6189,15 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,  static void brcmf_free_wiphy(struct wiphy *wiphy)  { +	int i; +  	if (!wiphy)  		return; -	if (wiphy->iface_combinations) -		kfree(wiphy->iface_combinations->limits); +	if (wiphy->iface_combinations) { +		for (i = 0; i < wiphy->n_iface_combinations; i++) +			kfree(wiphy->iface_combinations[i].limits); +	}  	kfree(wiphy->iface_combinations);  	if (wiphy->bands[IEEE80211_BAND_2GHZ]) {  		kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index fd74a9c6e9ac..746304121cdb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -21,6 +21,7 @@  #ifndef BRCMFMAC_CORE_H  #define BRCMFMAC_CORE_H +#include <net/cfg80211.h>  #include "fweh.h"  #define TOE_TX_CSUM_OL		0x00000001 @@ -118,6 +119,8 @@ struct brcmf_pub {  	/* Multicast data packets sent to dongle */  	unsigned long tx_multicast; +	struct mac_address addresses[BRCMF_MAX_IFS]; +  	struct brcmf_if *iflist[BRCMF_MAX_IFS];  	struct mutex proto_block; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 743f16b6a072..971920f77b68 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -19,6 +19,7 @@  #include <linux/device.h>  #include <linux/firmware.h>  #include <linux/module.h> +#include <linux/bcm47xx_nvram.h>  #include "debug.h"  #include "firmware.h" @@ -426,18 +427,32 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)  	struct brcmf_fw *fwctx = ctx;  	u32 nvram_length = 0;  	void *nvram = NULL; +	u8 *data = NULL; +	size_t data_len; +	bool raw_nvram;  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); -	if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) -		goto fail; +	if (fw && fw->data) { +		data = (u8 *)fw->data; +		data_len = fw->size; +		raw_nvram = false; +	} else { +		data = bcm47xx_nvram_get_contents(&data_len); +		if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) +			goto fail; +		raw_nvram = true; +	} -	if (fw) { -		nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length, +	if (data) +		nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,  					     fwctx->domain_nr, fwctx->bus_nr); + +	if (raw_nvram) +		bcm47xx_nvram_release_contents(data); +	if (fw)  		release_firmware(fw); -		if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) -			goto fail; -	} +	if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) +		goto fail;  	fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length);  	kfree(fwctx); @@ -473,15 +488,9 @@ static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)  	if (!ret)  		return; -	/* when nvram is optional call .done() callback here */ -	if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) { -		fwctx->done(fwctx->dev, fw, NULL, 0); -		kfree(fwctx); -		return; -	} +	brcmf_fw_request_nvram_done(NULL, fwctx); +	return; -	/* failed nvram request */ -	release_firmware(fw);  fail:  	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));  	device_release_driver(fwctx->dev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 59440631fec5..8d1ab4ab5be8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,  	spin_lock_irqsave(&flow->block_lock, flags);  	ring = flow->rings[flowid]; +	if (ring->blocked == blocked) { +		spin_unlock_irqrestore(&flow->block_lock, flags); +		return; +	}  	ifidx = brcmf_flowring_ifidx_get(flow, flowid);  	currently_blocked = false;  	for (i = 0; i < flow->nrofrings; i++) { -		if (flow->rings[i]) { +		if ((flow->rings[i]) && (i != flowid)) {  			ring = flow->rings[i];  			if ((ring->status == RING_OPEN) &&  			    (brcmf_flowring_ifidx_get(flow, i) == ifidx)) { @@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,  			}  		}  	} -	ring->blocked = blocked; -	if (currently_blocked == blocked) { +	flow->rings[flowid]->blocked = blocked; +	if (currently_blocked) {  		spin_unlock_irqrestore(&flow->block_lock, flags);  		return;  	} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index cbf033f59109..1326898d608e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -85,7 +85,6 @@ struct brcmf_event;  	BRCMF_ENUM_DEF(IF, 54) \  	BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \  	BRCMF_ENUM_DEF(RSSI, 56) \ -	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \  	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \  	BRCMF_ENUM_DEF(ACTION_FRAME, 59) \  	BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \ @@ -103,8 +102,7 @@ struct brcmf_event;  	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \  	BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \  	BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ -	BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ -	BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128) +	BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)  #define BRCMF_ENUM_DEF(id, val) \  	BRCMF_E_##id = (val), @@ -112,7 +110,11 @@ struct brcmf_event;  /* firmware event codes sent by the dongle */  enum brcmf_fweh_event_code {  	BRCMF_FWEH_EVENT_ENUM_DEFLIST -	BRCMF_E_LAST +	/* this determines event mask length which must match +	 * minimum length check in device firmware so it is +	 * hard-coded here. +	 */ +	BRCMF_E_LAST = 139  };  #undef BRCMF_ENUM_DEF diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 898c3801e658..7b2136c9badb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)  	}  } +#ifdef DEBUG +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); +	struct brcmf_pub *drvr = bus_if->drvr; +	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; +	struct brcmf_commonring *commonring; +	u16 i; +	struct brcmf_flowring_ring *ring; +	struct brcmf_flowring_hash *hash; + +	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; +	seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n", +		   commonring->r_ptr, commonring->w_ptr, commonring->depth); +	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT]; +	seq_printf(seq, "h2d_rx_submit:  rp %4u, wp %4u, depth %4u\n", +		   commonring->r_ptr, commonring->w_ptr, commonring->depth); +	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE]; +	seq_printf(seq, "d2h_ctl_cmplt:  rp %4u, wp %4u, depth %4u\n", +		   commonring->r_ptr, commonring->w_ptr, commonring->depth); +	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE]; +	seq_printf(seq, "d2h_tx_cmplt:   rp %4u, wp %4u, depth %4u\n", +		   commonring->r_ptr, commonring->w_ptr, commonring->depth); +	commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; +	seq_printf(seq, "d2h_rx_cmplt:   rp %4u, wp %4u, depth %4u\n", +		   commonring->r_ptr, commonring->w_ptr, commonring->depth); + +	seq_printf(seq, "\nh2d_flowrings: depth %u\n", +		   BRCMF_H2D_TXFLOWRING_MAX_ITEM); +	seq_puts(seq, "Active flowrings:\n"); +	hash = msgbuf->flow->hash; +	for (i = 0; i < msgbuf->flow->nrofrings; i++) { +		if (!msgbuf->flow->rings[i]) +			continue; +		ring = msgbuf->flow->rings[i]; +		if (ring->status != RING_OPEN) +			continue; +		commonring = msgbuf->flowrings[i]; +		hash = &msgbuf->flow->hash[ring->hash_id]; +		seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n" +				"        ifidx %u, fifo %u, da %pM\n", +				i, commonring->r_ptr, commonring->w_ptr, +				skb_queue_len(&ring->skblist), ring->blocked, +				hash->ifidx, hash->fifo, hash->mac); +	} + +	return 0; +} +#else +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ +	return 0; +} +#endif  int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)  { @@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)  	spin_lock_init(&msgbuf->flowring_work_lock);  	INIT_LIST_HEAD(&msgbuf->work_queue); +	brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); +  	return 0;  fail: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index d36f5f3d931b..f990e3d0e696 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2564,15 +2564,6 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)  	}  } -static void atomic_orr(int val, atomic_t *v) -{ -	int old_val; - -	old_val = atomic_read(v); -	while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) -		old_val = atomic_read(v); -} -  static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)  {  	struct brcmf_core *buscore; @@ -2595,7 +2586,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)  	if (val) {  		brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);  		bus->sdcnt.f1regdata++; -		atomic_orr(val, &bus->intstatus); +		atomic_or(val, &bus->intstatus);  	}  	return ret; @@ -2712,7 +2703,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)  	/* Keep still-pending events for next scheduling */  	if (intstatus) -		atomic_orr(intstatus, &bus->intstatus); +		atomic_or(intstatus, &bus->intstatus);  	brcmf_sdio_clrintr(bus); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ab775a5d5b33..d2c5747e3ac9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1472,9 +1472,7 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl,  	wl->timers = t;  #ifdef DEBUG -	t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); -	if (t->name) -		strcpy(t->name, name); +	t->name = kstrdup(name, GFP_ATOMIC);  #endif  	return t; diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 7603546d2de3..29185aeccba8 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -467,7 +467,6 @@ static struct spi_driver spi_driver = {  	.remove		= cw1200_spi_disconnect,  	.driver = {  		.name		= "cw1200_wlan_spi", -		.bus            = &spi_bus_type,  		.owner          = THIS_MODULE,  #ifdef CONFIG_PM  		.pm		= &cw1200_pm_ops, diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 01de1a3bf94e..80d4228ba754 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -865,7 +865,7 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,  	switch(type) {  	case HOSTAP_INTERFACE_AP: -		dev->tx_queue_len = 0;	/* use main radio device queue */ +		dev->priv_flags |= IFF_NO_QUEUE;	/* use main radio device queue */  		dev->netdev_ops = &hostap_mgmt_netdev_ops;  		dev->type = ARPHRD_IEEE80211;  		dev->header_ops = &hostap_80211_ops; @@ -874,7 +874,7 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,  		dev->netdev_ops = &hostap_master_ops;  		break;  	default: -		dev->tx_queue_len = 0;	/* use main radio device queue */ +		dev->priv_flags |= IFF_NO_QUEUE;	/* use main radio device queue */  		dev->netdev_ops = &hostap_netdev_ops;  	} diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 08eb229e7816..36818c7f30b9 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1410,7 +1410,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)  static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)  { -#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) +#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50))  	struct host_command cmd = {  		.host_command = CARD_DISABLE_PHY_OFF, diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index c6d78790cb0d..193947865efd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -746,7 +746,7 @@ struct ipw2100_priv {  #define IPW_REG_GPIO			IPW_REG_DOMAIN_0_OFFSET + 0x0030  #define IPW_REG_FW_TYPE                 IPW_REG_DOMAIN_1_OFFSET + 0x0188  #define IPW_REG_FW_VERSION 		IPW_REG_DOMAIN_1_OFFSET + 0x018C -#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 +#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190  #define IPW_REG_INDIRECT_ADDR_MASK	0x00FFFFFC diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 7f4cb692cc57..af1b3e6839fa 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3259,7 +3259,7 @@ il3945_show_measurement(struct device *d, struct device_attribute *attr,  	while (size && PAGE_SIZE - len) {  		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, -				   PAGE_SIZE - len, 1); +				   PAGE_SIZE - len, true);  		len = strlen(buf);  		if (PAGE_SIZE - len)  			buf[len++] = '\n'; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index 344010153196..908b9f4fef6f 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -515,12 +515,8 @@ il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count,  	    scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n",  		      eeprom_ver);  	for (ofs = 0; ofs < eeprom_len; ofs += 16) { -		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); -		hex_dump_to_buffer(ptr + ofs, 16, 16, 2, buf + pos, -				   buf_size - pos, 0); -		pos += strlen(buf + pos); -		if (buf_size - pos > 0) -			buf[pos++] = '\n'; +		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", +				 ofs, ptr + ofs);  	}  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index c160dad03037..991def878881 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -122,9 +122,8 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)  void iwl_down(struct iwl_priv *priv);  void iwl_cancel_deferred_work(struct iwl_priv *priv);  void iwlagn_prepare_restart(struct iwl_priv *priv); -int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, -				 struct iwl_rx_cmd_buffer *rxb, -				 struct iwl_device_cmd *cmd); +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi, +		     struct iwl_rx_cmd_buffer *rxb);  bool iwl_check_for_ct_kill(struct iwl_priv *priv); @@ -216,11 +215,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,  		       struct ieee80211_sta *sta, u16 tid);  int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,  			struct ieee80211_sta *sta, u16 tid); -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, -				   struct iwl_rx_cmd_buffer *rxb, -				   struct iwl_device_cmd *cmd); -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd); +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, +				   struct iwl_rx_cmd_buffer *rxb); +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb);  static inline u32 iwl_tx_status_to_mac80211(u32 status)  { @@ -277,9 +274,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,  /* bt coex */  void iwlagn_send_advance_bt_config(struct iwl_priv *priv); -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *cmd);  void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);  void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);  void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); @@ -332,8 +326,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,  int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,  		    struct iwl_link_quality_cmd *lq, u8 flags, bool init); -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd); +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb);  int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,  		      struct ieee80211_sta *sta); @@ -480,7 +473,7 @@ do {									\  } while (0)  #endif				/* CONFIG_IWLWIFI_DEBUG */ -extern const char *const iwl_dvm_cmd_strings[REPLY_MAX]; +extern const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1];  static inline const char *iwl_dvm_get_cmd_string(u8 cmd)  { diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 0ffb6ff1a255..b15e44f8d1bd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -310,12 +310,8 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,  	pos += scnprintf(buf + pos, buf_size - pos,  			 "NVM version: 0x%x\n", nvm_ver);  	for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { -		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); -		hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, -				   buf_size - pos, 0); -		pos += strlen(buf + pos); -		if (buf_size - pos > 0) -			buf[pos++] = '\n'; +		pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", +				 ofs, ptr + ofs);  	}  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd..0ba3e56d6015 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -669,6 +669,8 @@ struct iwl_priv {  	/* ieee device used by generic ieee processing code */  	struct ieee80211_hw *hw; +	struct napi_struct *napi; +  	struct list_head calib_results;  	struct workqueue_struct *workqueue; @@ -678,9 +680,8 @@ struct iwl_priv {  	enum ieee80211_band band;  	u8 valid_contexts; -	int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, -				       struct iwl_rx_cmd_buffer *rxb, -				       struct iwl_device_cmd *cmd); +	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, +				       struct iwl_rx_cmd_buffer *rxb);  	struct iwl_notif_wait_data notif_wait; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 1d2223df5cb0..ab45819c1fbb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -659,9 +659,8 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,  	return need_update;  } -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *cmd) +static void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, +					 struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data; @@ -669,7 +668,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,  	if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {  		/* bt coex disabled */ -		return 0; +		return;  	}  	IWL_DEBUG_COEX(priv, "BT Coex notification:\n"); @@ -714,7 +713,6 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,  	/* FIXME: based on notification, adjust the prio_boost */  	priv->bt_ci_compliance = coex->bt_ci_compliance; -	return 0;  }  void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 7acaa266b704..453f7c315ab5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -250,12 +250,24 @@ static int __iwl_up(struct iwl_priv *priv)  		}  	} +	ret = iwl_trans_start_hw(priv->trans); +	if (ret) { +		IWL_ERR(priv, "Failed to start HW: %d\n", ret); +		goto error; +	} +  	ret = iwl_run_init_ucode(priv);  	if (ret) {  		IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);  		goto error;  	} +	ret = iwl_trans_start_hw(priv->trans); +	if (ret) { +		IWL_ERR(priv, "Failed to start HW: %d\n", ret); +		goto error; +	} +  	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);  	if (ret) {  		IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); @@ -432,7 +444,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)  		u32 error_id;  	} err_info;  	struct iwl_notification_wait status_wait; -	static const u8 status_cmd[] = { +	static const u16 status_cmd[] = {  		REPLY_WOWLAN_GET_STATUS,  	};  	struct iwlagn_wowlan_status status_data = {}; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 234e30f498b2..e7616f0ee6e8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2029,17 +2029,6 @@ static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)  	return false;  } -static void iwl_napi_add(struct iwl_op_mode *op_mode, -			 struct napi_struct *napi, -			 struct net_device *napi_dev, -			 int (*poll)(struct napi_struct *, int), -			 int weight) -{ -	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - -	ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight); -} -  static const struct iwl_op_mode_ops iwl_dvm_ops = {  	.start = iwl_op_mode_dvm_start,  	.stop = iwl_op_mode_dvm_stop, @@ -2052,7 +2041,6 @@ static const struct iwl_op_mode_ops iwl_dvm_ops = {  	.cmd_queue_full = iwl_cmd_queue_full,  	.nic_config = iwl_nic_config,  	.wimax_active = iwl_wimax_active, -	.napi_add = iwl_napi_add,  };  /***************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 3bd7c86e90d9..cef921c1a623 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -1416,11 +1416,11 @@ static int rs_switch_to_siso(struct iwl_priv *priv,  /*   * Try to switch to new modulation mode from legacy   */ -static int rs_move_legacy_other(struct iwl_priv *priv, -				struct iwl_lq_sta *lq_sta, -				struct ieee80211_conf *conf, -				struct ieee80211_sta *sta, -				int index) +static void rs_move_legacy_other(struct iwl_priv *priv, +				 struct iwl_lq_sta *lq_sta, +				 struct ieee80211_conf *conf, +				 struct ieee80211_sta *sta, +				 int index)  {  	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);  	struct iwl_scale_tbl_info *search_tbl = @@ -1575,7 +1575,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,  	}  	search_tbl->lq_type = LQ_NONE; -	return 0; +	return;  out:  	lq_sta->search_better_tbl = 1; @@ -1584,17 +1584,15 @@ out:  		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;  	if (update_search_tbl_counter)  		search_tbl->action = tbl->action; -	return 0; -  }  /*   * Try to switch to new modulation mode from SISO   */ -static int rs_move_siso_to_other(struct iwl_priv *priv, -				 struct iwl_lq_sta *lq_sta, -				 struct ieee80211_conf *conf, -				 struct ieee80211_sta *sta, int index) +static void rs_move_siso_to_other(struct iwl_priv *priv, +				  struct iwl_lq_sta *lq_sta, +				  struct ieee80211_conf *conf, +				  struct ieee80211_sta *sta, int index)  {  	u8 is_green = lq_sta->is_green;  	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1747,7 +1745,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,  			break;  	}  	search_tbl->lq_type = LQ_NONE; -	return 0; +	return;   out:  	lq_sta->search_better_tbl = 1; @@ -1756,17 +1754,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,  		tbl->action = IWL_SISO_SWITCH_ANTENNA1;  	if (update_search_tbl_counter)  		search_tbl->action = tbl->action; - -	return 0;  }  /*   * Try to switch to new modulation mode from MIMO2   */ -static int rs_move_mimo2_to_other(struct iwl_priv *priv, -				 struct iwl_lq_sta *lq_sta, -				 struct ieee80211_conf *conf, -				 struct ieee80211_sta *sta, int index) +static void rs_move_mimo2_to_other(struct iwl_priv *priv, +				   struct iwl_lq_sta *lq_sta, +				   struct ieee80211_conf *conf, +				   struct ieee80211_sta *sta, int index)  {  	s8 is_green = lq_sta->is_green;  	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1917,7 +1913,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,  			break;  	}  	search_tbl->lq_type = LQ_NONE; -	return 0; +	return;   out:  	lq_sta->search_better_tbl = 1;  	tbl->action++; @@ -1926,17 +1922,15 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,  	if (update_search_tbl_counter)  		search_tbl->action = tbl->action; -	return 0; -  }  /*   * Try to switch to new modulation mode from MIMO3   */ -static int rs_move_mimo3_to_other(struct iwl_priv *priv, -				 struct iwl_lq_sta *lq_sta, -				 struct ieee80211_conf *conf, -				 struct ieee80211_sta *sta, int index) +static void rs_move_mimo3_to_other(struct iwl_priv *priv, +				   struct iwl_lq_sta *lq_sta, +				   struct ieee80211_conf *conf, +				   struct ieee80211_sta *sta, int index)  {  	s8 is_green = lq_sta->is_green;  	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -2093,7 +2087,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,  			break;  	}  	search_tbl->lq_type = LQ_NONE; -	return 0; +	return;   out:  	lq_sta->search_better_tbl = 1;  	tbl->action++; @@ -2101,9 +2095,6 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,  		tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;  	if (update_search_tbl_counter)  		search_tbl->action = tbl->action; - -	return 0; -  }  /* diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610..4a45b0b594c7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -39,7 +39,7 @@  #define IWL_CMD_ENTRY(x) [x] = #x -const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { +const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1] = {  	IWL_CMD_ENTRY(REPLY_ALIVE),  	IWL_CMD_ENTRY(REPLY_ERROR),  	IWL_CMD_ENTRY(REPLY_ECHO), @@ -123,9 +123,8 @@ const char *const iwl_dvm_cmd_strings[REPLY_MAX] = {   *   ******************************************************************************/ -static int iwlagn_rx_reply_error(struct iwl_priv *priv, -			       struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_error(struct iwl_priv *priv, +				  struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -136,11 +135,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv,  		err_resp->cmd_id,  		le16_to_cpu(err_resp->bad_cmd_seq_num),  		le32_to_cpu(err_resp->error_info)); -	return 0;  } -static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +static void iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_csa_notification *csa = (void *)pkt->data; @@ -152,7 +149,7 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  	struct iwl_rxon_cmd *rxon = (void *)&ctx->active;  	if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) -		return 0; +		return;  	if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {  		rxon->channel = csa->channel; @@ -165,13 +162,11 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  			le16_to_cpu(csa->channel));  		iwl_chswitch_done(priv, false);  	} -	return 0;  } -static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, -					  struct iwl_rx_cmd_buffer *rxb, -					  struct iwl_device_cmd *cmd) +static void iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, +					     struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_spectrum_notification *report = (void *)pkt->data; @@ -179,17 +174,15 @@ static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,  	if (!report->state) {  		IWL_DEBUG_11H(priv,  			"Spectrum Measure Notification: Start\n"); -		return 0; +		return;  	}  	memcpy(&priv->measure_report, report, sizeof(*report));  	priv->measurement_status |= MEASUREMENT_READY; -	return 0;  } -static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, +				     struct iwl_rx_cmd_buffer *rxb)  {  #ifdef CONFIG_IWLWIFI_DEBUG  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -197,24 +190,20 @@ static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,  	IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",  		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);  #endif -	return 0;  } -static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, +						struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u32 __maybe_unused len = iwl_rx_packet_len(pkt);  	IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "  			"notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);  	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); -	return 0;  } -static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd) +static void iwlagn_rx_beacon_notif(struct iwl_priv *priv, +				   struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwlagn_beacon_notif *beacon = (void *)pkt->data; @@ -232,8 +221,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,  #endif  	priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - -	return 0;  }  /** @@ -448,9 +435,8 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv,  }  #endif -static int iwlagn_rx_statistics(struct iwl_priv *priv, -			      struct iwl_rx_cmd_buffer *rxb, -			      struct iwl_device_cmd *cmd) +static void iwlagn_rx_statistics(struct iwl_priv *priv, +				 struct iwl_rx_cmd_buffer *rxb)  {  	unsigned long stamp = jiffies;  	const int reg_recalib_period = 60; @@ -505,7 +491,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,  			  len, sizeof(struct iwl_bt_notif_statistics),  			  sizeof(struct iwl_notif_statistics));  		spin_unlock(&priv->statistics.lock); -		return 0; +		return;  	}  	change = common->temperature != priv->statistics.common.temperature || @@ -550,13 +536,10 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,  		priv->lib->temperature(priv);  	spin_unlock(&priv->statistics.lock); - -	return 0;  } -static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_statistics(struct iwl_priv *priv, +				       struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_notif_statistics *stats = (void *)pkt->data; @@ -572,15 +555,14 @@ static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,  #endif  		IWL_DEBUG_RX(priv, "Statistics have been cleared\n");  	} -	iwlagn_rx_statistics(priv, rxb, cmd); -	return 0; + +	iwlagn_rx_statistics(priv, rxb);  }  /* Handle notification from uCode that card's power state is changing   * due to software, hardware, or critical temperature RFKILL */ -static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd) +static void iwlagn_rx_card_state_notif(struct iwl_priv *priv, +				       struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -627,12 +609,10 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,  	     test_bit(STATUS_RF_KILL_HW, &priv->status)))  		wiphy_rfkill_set_hw_state(priv->hw->wiphy,  			test_bit(STATUS_RF_KILL_HW, &priv->status)); -	return 0;  } -static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, -				       struct iwl_rx_cmd_buffer *rxb, -				       struct iwl_device_cmd *cmd) +static void iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, +					  struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -649,14 +629,12 @@ static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,  		if (!test_bit(STATUS_SCANNING, &priv->status))  			iwl_init_sensitivity(priv);  	} -	return 0;  }  /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).   * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, +				   struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -664,7 +642,6 @@ static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,  	priv->ampdu_ref++;  	memcpy(&priv->last_phy_res, pkt->data,  	       sizeof(struct iwl_rx_phy_res)); -	return 0;  }  /* @@ -786,7 +763,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,  	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); -	ieee80211_rx(priv->hw, skb); +	ieee80211_rx_napi(priv->hw, skb, priv->napi);  }  static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) @@ -890,9 +867,8 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,  }  /* Called for REPLY_RX_MPDU_CMD */ -static int iwlagn_rx_reply_rx(struct iwl_priv *priv, -			    struct iwl_rx_cmd_buffer *rxb, -			    struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx(struct iwl_priv *priv, +			       struct iwl_rx_cmd_buffer *rxb)  {  	struct ieee80211_hdr *header;  	struct ieee80211_rx_status rx_status = {}; @@ -906,7 +882,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,  	if (!priv->last_phy_res_valid) {  		IWL_ERR(priv, "MPDU frame without cached PHY data\n"); -		return 0; +		return;  	}  	phy_res = &priv->last_phy_res;  	amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; @@ -919,14 +895,14 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,  	if ((unlikely(phy_res->cfg_phy_cnt > 20))) {  		IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",  				phy_res->cfg_phy_cnt); -		return 0; +		return;  	}  	if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||  	    !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {  		IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",  				le32_to_cpu(rx_pkt_status)); -		return 0; +		return;  	}  	/* This will be used in several places later */ @@ -998,12 +974,10 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,  	iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,  				    rxb, &rx_status); -	return 0;  } -static int iwlagn_rx_noa_notification(struct iwl_priv *priv, -				      struct iwl_rx_cmd_buffer *rxb, -				      struct iwl_device_cmd *cmd) +static void iwlagn_rx_noa_notification(struct iwl_priv *priv, +				       struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_wipan_noa_data *new_data, *old_data;  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -1041,8 +1015,6 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv,  	if (old_data)  		kfree_rcu(old_data, rcu_head); - -	return 0;  }  /** @@ -1053,8 +1025,7 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv,   */  void iwl_setup_rx_handlers(struct iwl_priv *priv)  { -	int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd); +	void (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb);  	handlers = priv->rx_handlers; @@ -1102,12 +1073,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)  		iwlagn_bt_rx_handler_setup(priv);  } -int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, -		    struct iwl_device_cmd *cmd) +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi, +		     struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); -	int err = 0;  	/*  	 * Do the notification wait before RX handlers so @@ -1121,12 +1091,11 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,  	 *   rx_handlers table.  See iwl_setup_rx_handlers() */  	if (priv->rx_handlers[pkt->hdr.cmd]) {  		priv->rx_handlers_stats[pkt->hdr.cmd]++; -		err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); +		priv->rx_handlers[pkt->hdr.cmd](priv, rxb);  	} else {  		/* No handling needed */  		IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",  			     iwl_dvm_get_cmd_string(pkt->hdr.cmd),  			     pkt->hdr.cmd);  	} -	return err;  } diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index ed50de6362ed..85ceceb34fcc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1,6 +1,7 @@  /******************************************************************************   *   * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify it   * under the terms of version 2 of the GNU General Public License as @@ -123,7 +124,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,  	__le32 old_filter = send->filter_flags;  	u8 old_dev_type = send->dev_type;  	int ret; -	static const u8 deactivate_cmd[] = { +	static const u16 deactivate_cmd[] = {  		REPLY_WIPAN_DEACTIVATION_COMPLETE  	}; diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 43bef901e8f9..648159495bbc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -247,9 +247,8 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)  }  /* Service response to REPLY_SCAN_CMD (0x80) */ -static int iwl_rx_reply_scan(struct iwl_priv *priv, -			      struct iwl_rx_cmd_buffer *rxb, -			      struct iwl_device_cmd *cmd) +static void iwl_rx_reply_scan(struct iwl_priv *priv, +			      struct iwl_rx_cmd_buffer *rxb)  {  #ifdef CONFIG_IWLWIFI_DEBUG  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -257,13 +256,11 @@ static int iwl_rx_reply_scan(struct iwl_priv *priv,  	IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);  #endif -	return 0;  }  /* Service SCAN_START_NOTIFICATION (0x82) */ -static int iwl_rx_scan_start_notif(struct iwl_priv *priv, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd) +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, +				    struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_scanstart_notification *notif = (void *)pkt->data; @@ -277,14 +274,11 @@ static int iwl_rx_scan_start_notif(struct iwl_priv *priv,  		       le32_to_cpu(notif->tsf_high),  		       le32_to_cpu(notif->tsf_low),  		       notif->status, notif->beacon_timer); - -	return 0;  }  /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static int iwl_rx_scan_results_notif(struct iwl_priv *priv, -				      struct iwl_rx_cmd_buffer *rxb, -				      struct iwl_device_cmd *cmd) +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, +				      struct iwl_rx_cmd_buffer *rxb)  {  #ifdef CONFIG_IWLWIFI_DEBUG  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -303,13 +297,11 @@ static int iwl_rx_scan_results_notif(struct iwl_priv *priv,  		       le32_to_cpu(notif->statistics[0]),  		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);  #endif -	return 0;  }  /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, -				       struct iwl_rx_cmd_buffer *rxb, -				       struct iwl_device_cmd *cmd) +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, +				       struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data; @@ -356,7 +348,6 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,  		queue_work(priv->workqueue,  			   &priv->bt_traffic_change_work);  	} -	return 0;  }  void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 6ec86adbe4a1..0fa67d3b7235 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -60,41 +60,28 @@ static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)  	return 0;  } -static int iwl_process_add_sta_resp(struct iwl_priv *priv, -				    struct iwl_addsta_cmd *addsta, -				    struct iwl_rx_packet *pkt) +static void iwl_process_add_sta_resp(struct iwl_priv *priv, +				     struct iwl_rx_packet *pkt)  {  	struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; -	u8 sta_id = addsta->sta.sta_id; -	int ret = -EIO; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", -			pkt->hdr.flags); -		return ret; -	} - -	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", -		       sta_id); +	IWL_DEBUG_INFO(priv, "Processing response for adding station\n");  	spin_lock_bh(&priv->sta_lock);  	switch (add_sta_resp->status) {  	case ADD_STA_SUCCESS_MSK:  		IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); -		ret = iwl_sta_ucode_activate(priv, sta_id);  		break;  	case ADD_STA_NO_ROOM_IN_TABLE: -		IWL_ERR(priv, "Adding station %d failed, no room in table.\n", -			sta_id); +		IWL_ERR(priv, "Adding station failed, no room in table.\n");  		break;  	case ADD_STA_NO_BLOCK_ACK_RESOURCE: -		IWL_ERR(priv, "Adding station %d failed, no block ack " -			"resource.\n", sta_id); +		IWL_ERR(priv, +			"Adding station failed, no block ack resource.\n");  		break;  	case ADD_STA_MODIFY_NON_EXIST_STA: -		IWL_ERR(priv, "Attempting to modify non-existing station %d\n", -			sta_id); +		IWL_ERR(priv, "Attempting to modify non-existing station\n");  		break;  	default:  		IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", @@ -102,37 +89,14 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,  		break;  	} -	IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", -		       priv->stations[sta_id].sta.mode == -		       STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added", -		       sta_id, priv->stations[sta_id].sta.sta.addr); - -	/* -	 * XXX: The MAC address in the command buffer is often changed from -	 * the original sent to the device. That is, the MAC address -	 * written to the command buffer often is not the same MAC address -	 * read from the command buffer when the command returns. This -	 * issue has not yet been resolved and this debugging is left to -	 * observe the problem. -	 */ -	IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", -		       priv->stations[sta_id].sta.mode == -		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", -		       addsta->sta.addr);  	spin_unlock_bh(&priv->sta_lock); - -	return ret;  } -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	if (!cmd) -		return 0; - -	return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt); +	iwl_process_add_sta_resp(priv, pkt);  }  int iwl_send_add_sta(struct iwl_priv *priv, @@ -146,6 +110,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,  		.len = { sizeof(*sta), },  	};  	u8 sta_id __maybe_unused = sta->sta.sta_id; +	struct iwl_rx_packet *pkt; +	struct iwl_add_sta_resp *add_sta_resp;  	IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",  		       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : ""); @@ -159,16 +125,22 @@ int iwl_send_add_sta(struct iwl_priv *priv,  	if (ret || (flags & CMD_ASYNC))  		return ret; -	/*else the command was successfully sent in SYNC mode, need to free -	 * the reply page */ -	iwl_free_resp(&cmd); +	pkt = cmd.resp_pkt; +	add_sta_resp = (void *)pkt->data; -	if (cmd.handler_status) -		IWL_ERR(priv, "%s - error in the CMD response %d\n", __func__, -			cmd.handler_status); +	/* debug messages are printed in the handler */ +	if (add_sta_resp->status == ADD_STA_SUCCESS_MSK) { +		spin_lock_bh(&priv->sta_lock); +		ret = iwl_sta_ucode_activate(priv, sta_id); +		spin_unlock_bh(&priv->sta_lock); +	} else { +		ret = -EIO; +	} -	return cmd.handler_status; +	iwl_free_resp(&cmd); + +	return ret;  }  bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, @@ -452,6 +424,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,  	struct iwl_rx_packet *pkt;  	int ret;  	struct iwl_rem_sta_cmd rm_sta_cmd; +	struct iwl_rem_sta_resp *rem_sta_resp;  	struct iwl_host_cmd cmd = {  		.id = REPLY_REMOVE_STA, @@ -471,29 +444,23 @@ static int iwl_send_remove_station(struct iwl_priv *priv,  		return ret;  	pkt = cmd.resp_pkt; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", -			  pkt->hdr.flags); -		ret = -EIO; -	} +	rem_sta_resp = (void *)pkt->data; -	if (!ret) { -		struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data; -		switch (rem_sta_resp->status) { -		case REM_STA_SUCCESS_MSK: -			if (!temporary) { -				spin_lock_bh(&priv->sta_lock); -				iwl_sta_ucode_deactivate(priv, sta_id); -				spin_unlock_bh(&priv->sta_lock); -			} -			IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); -			break; -		default: -			ret = -EIO; -			IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); -			break; +	switch (rem_sta_resp->status) { +	case REM_STA_SUCCESS_MSK: +		if (!temporary) { +			spin_lock_bh(&priv->sta_lock); +			iwl_sta_ucode_deactivate(priv, sta_id); +			spin_unlock_bh(&priv->sta_lock);  		} +		IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); +		break; +	default: +		ret = -EIO; +		IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); +		break;  	} +  	iwl_free_resp(&cmd);  	return ret; diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 275df12a6045..bddd19769035 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1128,8 +1128,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv,  	}  } -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1273,8 +1272,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,  		skb = __skb_dequeue(&skbs);  		ieee80211_tx_status(priv->hw, skb);  	} - -	return 0;  }  /** @@ -1283,9 +1280,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,   * Handles block-acknowledge notification from device, which reports success   * of frames sent via aggregation.   */ -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, -				   struct iwl_rx_cmd_buffer *rxb, -				   struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, +				   struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; @@ -1306,7 +1302,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,  	if (scd_flow >= priv->cfg->base_params->num_of_queues) {  		IWL_ERR(priv,  			"BUG_ON scd_flow is bigger than number of queues\n"); -		return 0; +		return;  	}  	sta_id = ba_resp->sta_id; @@ -1319,7 +1315,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,  		if (unlikely(ba_resp->bitmap))  			IWL_ERR(priv, "Received BA when not expected\n");  		spin_unlock_bh(&priv->sta_lock); -		return 0; +		return;  	}  	if (unlikely(scd_flow != agg->txq_id)) { @@ -1333,7 +1329,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,  				    "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",  				    scd_flow, sta_id, tid, agg->txq_id);  		spin_unlock_bh(&priv->sta_lock); -		return 0; +		return;  	}  	__skb_queue_head_init(&reclaimed_skbs); @@ -1413,6 +1409,4 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,  		skb = __skb_dequeue(&reclaimed_skbs);  		ieee80211_tx_status(priv->hw, skb);  	} - -	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 5244e43bfafb..931a8e4269ef 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -3,6 +3,7 @@   * GPL LICENSE SUMMARY   *   * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -327,7 +328,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,  	const struct fw_img *fw;  	int ret;  	enum iwl_ucode_type old_type; -	static const u8 alive_cmd[] = { REPLY_ALIVE }; +	static const u16 alive_cmd[] = { REPLY_ALIVE };  	fw = iwl_get_ucode_image(priv, ucode_type);  	if (WARN_ON(!fw)) @@ -406,7 +407,7 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,  int iwl_run_init_ucode(struct iwl_priv *priv)  {  	struct iwl_notification_wait calib_wait; -	static const u8 calib_complete[] = { +	static const u16 calib_complete[] = {  		CALIBRATION_RES_NOTIFICATION,  		CALIBRATION_COMPLETE_NOTIFICATION  	}; diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index cc35f796d406..6951aba620eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,14 +69,14 @@  #include "iwl-agn-hw.h"  /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX	15 +#define IWL7260_UCODE_API_MAX	17  /* Oldest version we won't warn about */  #define IWL7260_UCODE_API_OK	12  #define IWL3165_UCODE_API_OK	13  /* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN	10 +#define IWL7260_UCODE_API_MIN	12  #define IWL3165_UCODE_API_MIN	13  /* NVM versions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 72040cd0b979..197abe43ddc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,13 +69,13 @@  #include "iwl-agn-hw.h"  /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX	15 +#define IWL8000_UCODE_API_MAX	17  /* Oldest version we won't warn about */  #define IWL8000_UCODE_API_OK	12  /* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN	10 +#define IWL8000_UCODE_API_MIN	12  /* NVM versions */  #define IWL8000_NVM_VERSION		0x0a1d @@ -97,8 +97,9 @@  #define DEFAULT_NVM_FILE_FAMILY_8000B		"nvmData-8000B"  #define DEFAULT_NVM_FILE_FAMILY_8000C		"nvmData-8000C" -/* Max SDIO RX aggregation size of the ADDBA request/response */ -#define MAX_RX_AGG_SIZE_8260_SDIO	28 +/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ +#define MAX_RX_AGG_SIZE_8260_SDIO	21 +#define MAX_TX_AGG_SIZE_8260_SDIO	40  /* Max A-MPDU exponent for HT and VHT */  #define MAX_HT_AMPDU_EXPONENT_8260_SDIO	IEEE80211_HT_MAX_AMPDU_32K @@ -154,6 +155,7 @@ static const struct iwl_tt_params iwl8000_tt_params = {  	.led_mode = IWL_LED_RF_STATE,					\  	.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000,		\  	.d0i3 = true,							\ +	.features = NETIF_F_RXCSUM,					\  	.non_shared_ant = ANT_A,					\  	.dccm_offset = IWL8260_DCCM_OFFSET,				\  	.dccm_len = IWL8260_DCCM_LEN,					\ @@ -203,6 +205,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION,  	.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, +	.max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO,  	.disable_dummy_notification = true,  	.max_ht_ampdu_exponent  = MAX_HT_AMPDU_EXPONENT_8260_SDIO,  	.max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, @@ -216,6 +219,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {  	.nvm_ver = IWL8000_NVM_VERSION,  	.nvm_calib_ver = IWL8000_TX_POWER_VERSION,  	.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, +	.max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO,  	.bt_shared_single_ant = true,  	.disable_dummy_notification = true,  	.max_ht_ampdu_exponent  = MAX_HT_AMPDU_EXPONENT_8260_SDIO, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 08c14afeb148..939fa229c038 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff {   *	mode set   * @d0i3: device uses d0i3 instead of d3   * @nvm_hw_section_num: the ID of the HW NVM section + * @features: hw features, any combination of feature_whitelist   * @pwr_tx_backoffs: translation table between power limits and backoffs   * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response   * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response @@ -348,6 +349,7 @@ struct iwl_cfg {  	bool no_power_up_nic_in_init;  	const char *default_nvm_file_B_step;  	const char *default_nvm_file_C_step; +	netdev_features_t features;  	unsigned int max_rx_agg_size;  	bool disable_dummy_notification;  	unsigned int max_tx_agg_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index faa17f2e352a..543abeaffcf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -200,6 +200,7 @@  #define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */  #define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */  #define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */ +#define CSR_INT_BIT_PAGING       (1 << 24) /* SDIO PAGING */  #define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */  #define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */  #define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses */ @@ -210,6 +211,7 @@  				 CSR_INT_BIT_HW_ERR  | \  				 CSR_INT_BIT_FH_TX   | \  				 CSR_INT_BIT_SW_ERR  | \ +				 CSR_INT_BIT_PAGING  | \  				 CSR_INT_BIT_RF_KILL | \  				 CSR_INT_BIT_SW_RX   | \  				 CSR_INT_BIT_WAKEUP  | \ @@ -422,6 +424,7 @@ enum {  /* DRAM INT TABLE */  #define CSR_DRAM_INT_TBL_ENABLE		(1 << 31) +#define CSR_DRAM_INIT_TBL_WRITE_POINTER	(1 << 28)  #define CSR_DRAM_INIT_TBL_WRAP_CHECK	(1 << 27)  /* diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h index 04e6649340b8..71a78cede9b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h @@ -35,8 +35,8 @@  TRACE_EVENT(iwlwifi_dev_tx_data,  	TP_PROTO(const struct device *dev,  		 struct sk_buff *skb, -		 void *data, size_t data_len), -	TP_ARGS(dev, skb, data, data_len), +		 u8 hdr_len, size_t data_len), +	TP_ARGS(dev, skb, hdr_len, data_len),  	TP_STRUCT__entry(  		DEV_ENTRY @@ -45,7 +45,8 @@ TRACE_EVENT(iwlwifi_dev_tx_data,  	TP_fast_assign(  		DEV_ASSIGN;  		if (iwl_trace_data(skb)) -			memcpy(__get_dynamic_array(data), data, data_len); +			skb_copy_bits(skb, hdr_len, +				      __get_dynamic_array(data), data_len);  	),  	TP_printk("[%s] TX frame data", __get_str(dev))  ); diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h index 948ce0802fa7..eb4b99a1c8cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h @@ -36,7 +36,7 @@  TRACE_EVENT(iwlwifi_dev_hcmd,  	TP_PROTO(const struct device *dev,  		 struct iwl_host_cmd *cmd, u16 total_size, -		 struct iwl_cmd_header *hdr), +		 struct iwl_cmd_header_wide *hdr),  	TP_ARGS(dev, cmd, total_size, hdr),  	TP_STRUCT__entry(  		DEV_ENTRY @@ -44,11 +44,14 @@ TRACE_EVENT(iwlwifi_dev_hcmd,  		__field(u32, flags)  	),  	TP_fast_assign( -		int i, offset = sizeof(*hdr); +		int i, offset = sizeof(struct iwl_cmd_header); + +		if (hdr->group_id) +			offset = sizeof(struct iwl_cmd_header_wide);  		DEV_ASSIGN;  		__entry->flags = cmd->flags; -		memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); +		memcpy(__get_dynamic_array(hcmd), hdr, offset);  		for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  			if (!cmd->len[i]) @@ -58,8 +61,9 @@ TRACE_EVENT(iwlwifi_dev_hcmd,  			offset += cmd->len[i];  		}  	), -	TP_printk("[%s] hcmd %#.2x (%ssync)", -		  __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[0], +	TP_printk("[%s] hcmd %#.2x.%#.2x (%ssync)", +		  __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[1], +		  ((u8 *)__get_dynamic_array(hcmd))[0],  		  __entry->flags & CMD_ASYNC ? "a" : "")  ); diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6685259927f8..a86aa5bcee7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -372,6 +372,30 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)  	return 0;  } +static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, +				const u32 len) +{ +	struct iwl_fw_gscan_capabilities *fw_capa = (void *)data; +	struct iwl_gscan_capabilities *capa = &fw->gscan_capa; + +	if (len < sizeof(*fw_capa)) +		return -EINVAL; + +	capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size); +	capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets); +	capa->max_ap_cache_per_scan = +		le32_to_cpu(fw_capa->max_ap_cache_per_scan); +	capa->max_rssi_sample_size = le32_to_cpu(fw_capa->max_rssi_sample_size); +	capa->max_scan_reporting_threshold = +		le32_to_cpu(fw_capa->max_scan_reporting_threshold); +	capa->max_hotlist_aps = le32_to_cpu(fw_capa->max_hotlist_aps); +	capa->max_significant_change_aps = +		le32_to_cpu(fw_capa->max_significant_change_aps); +	capa->max_bssid_history_entries = +		le32_to_cpu(fw_capa->max_bssid_history_entries); +	return 0; +} +  /*   * Gets uCode section from tlv.   */ @@ -573,13 +597,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,  	size_t len = ucode_raw->size;  	const u8 *data;  	u32 tlv_len; +	u32 usniffer_img;  	enum iwl_ucode_tlv_type tlv_type;  	const u8 *tlv_data;  	char buildstr[25]; -	u32 build; +	u32 build, paging_mem_size;  	int num_of_cpus;  	bool usniffer_images = false;  	bool usniffer_req = false; +	bool gscan_capa = false;  	if (len < sizeof(*ucode)) {  		IWL_ERR(drv, "uCode has invalid length: %zd\n", len); @@ -955,12 +981,46 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,  					    IWL_UCODE_REGULAR_USNIFFER,  					    tlv_len);  			break; +		case IWL_UCODE_TLV_PAGING: +			if (tlv_len != sizeof(u32)) +				goto invalid_tlv_len; +			paging_mem_size = le32_to_cpup((__le32 *)tlv_data); + +			IWL_DEBUG_FW(drv, +				     "Paging: paging enabled (size = %u bytes)\n", +				     paging_mem_size); + +			if (paging_mem_size > MAX_PAGING_IMAGE_SIZE) { +				IWL_ERR(drv, +					"Paging: driver supports up to %lu bytes for paging image\n", +					MAX_PAGING_IMAGE_SIZE); +				return -EINVAL; +			} + +			if (paging_mem_size & (FW_PAGING_SIZE - 1)) { +				IWL_ERR(drv, +					"Paging: image isn't multiple %lu\n", +					FW_PAGING_SIZE); +				return -EINVAL; +			} + +			drv->fw.img[IWL_UCODE_REGULAR].paging_mem_size = +				paging_mem_size; +			usniffer_img = IWL_UCODE_REGULAR_USNIFFER; +			drv->fw.img[usniffer_img].paging_mem_size = +				paging_mem_size; +			break;  		case IWL_UCODE_TLV_SDIO_ADMA_ADDR:  			if (tlv_len != sizeof(u32))  				goto invalid_tlv_len;  			drv->fw.sdio_adma_addr =  				le32_to_cpup((__le32 *)tlv_data);  			break; +		case IWL_UCODE_TLV_FW_GSCAN_CAPA: +			if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len)) +				goto invalid_tlv_len; +			gscan_capa = true; +			break;  		default:  			IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);  			break; @@ -979,6 +1039,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,  		return -EINVAL;  	} +	/* +	 * If ucode advertises that it supports GSCAN but GSCAN +	 * capabilities TLV is not present, warn and continue without GSCAN. +	 */ +	if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && +	    WARN(!gscan_capa, +		 "GSCAN is supported but capabilities TLV is unavailable\n")) +		__clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT, +			    capa->_capa); +  	return 0;   invalid_tlv_len: diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 21302b6f2bfd..acc3d186c5c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -713,12 +713,12 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data,  	struct ieee80211_channel *chan = &data->channels[0];  	int n = 0, idx = 0; -	while (chan->band != band && idx < n_channels) +	while (idx < n_channels && chan->band != band)  		chan = &data->channels[++idx];  	sband->channels = &data->channels[idx]; -	while (chan->band == band && idx < n_channels) { +	while (idx < n_channels && chan->band == band) {  		chan = &data->channels[++idx];  		n++;  	} diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index e57dbd0ef2e1..af5b3201492c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -84,6 +84,8 @@   * @IWL_FW_ERROR_DUMP_MEM: chunk of memory   * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump.   *	Structured as &struct iwl_fw_error_dump_trigger_desc. + * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as + *	&struct iwl_fw_error_dump_rb   */  enum iwl_fw_error_dump_type {  	/* 0 is deprecated */ @@ -97,6 +99,7 @@ enum iwl_fw_error_dump_type {  	IWL_FW_ERROR_DUMP_FH_REGS = 8,  	IWL_FW_ERROR_DUMP_MEM = 9,  	IWL_FW_ERROR_DUMP_ERROR_INFO = 10, +	IWL_FW_ERROR_DUMP_RB = 11,  	IWL_FW_ERROR_DUMP_MAX,  }; @@ -223,6 +226,20 @@ struct iwl_fw_error_dump_mem {  };  /** + * struct iwl_fw_error_dump_rb - content of an Receive Buffer + * @index: the index of the Receive Buffer in the Rx queue + * @rxq: the RB's Rx queue + * @reserved: + * @data: the content of the Receive Buffer + */ +struct iwl_fw_error_dump_rb { +	__le32 index; +	__le32 rxq; +	__le32 reserved; +	u8 data[]; +}; + +/**   * iwl_fw_error_next_data - advance fw error dump data pointer   * @data: previous data block   * Returns: next data block diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index a9b5ae4ebec0..84653e3d02ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -132,12 +132,14 @@ enum iwl_ucode_tlv_type {  	IWL_UCODE_TLV_API_CHANGES_SET	= 29,  	IWL_UCODE_TLV_ENABLED_CAPABILITIES	= 30,  	IWL_UCODE_TLV_N_SCAN_CHANNELS		= 31, +	IWL_UCODE_TLV_PAGING		= 32,  	IWL_UCODE_TLV_SEC_RT_USNIFFER	= 34,  	IWL_UCODE_TLV_SDIO_ADMA_ADDR	= 35,  	IWL_UCODE_TLV_FW_VERSION	= 36,  	IWL_UCODE_TLV_FW_DBG_DEST	= 38,  	IWL_UCODE_TLV_FW_DBG_CONF	= 39,  	IWL_UCODE_TLV_FW_DBG_TRIGGER	= 40, +	IWL_UCODE_TLV_FW_GSCAN_CAPA	= 50,  };  struct iwl_ucode_tlv { @@ -247,9 +249,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;   * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.   * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR   * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. - * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, - *	regardless of the band or the number of the probes. FW will calculate - *	the actual dwell time. + * @IWL_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header   * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler   *	through the dedicated host command.   * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. @@ -259,6 +259,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;   * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format   * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority   *	instead of 3. + * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size + *	(command version 3) that supports per-chain limits   */  enum iwl_ucode_tlv_api {  	IWL_UCODE_TLV_API_BT_COEX_SPLIT         = (__force iwl_ucode_tlv_api_t)3, @@ -266,7 +268,7 @@ enum iwl_ucode_tlv_api {  	IWL_UCODE_TLV_API_WIFI_MCC_UPDATE	= (__force iwl_ucode_tlv_api_t)9,  	IWL_UCODE_TLV_API_HDC_PHASE_0		= (__force iwl_ucode_tlv_api_t)10,  	IWL_UCODE_TLV_API_TX_POWER_DEV		= (__force iwl_ucode_tlv_api_t)11, -	IWL_UCODE_TLV_API_BASIC_DWELL		= (__force iwl_ucode_tlv_api_t)13, +	IWL_UCODE_TLV_API_WIDE_CMD_HDR		= (__force iwl_ucode_tlv_api_t)14,  	IWL_UCODE_TLV_API_SCD_CFG		= (__force iwl_ucode_tlv_api_t)15,  	IWL_UCODE_TLV_API_SINGLE_SCAN_EBS	= (__force iwl_ucode_tlv_api_t)16,  	IWL_UCODE_TLV_API_ASYNC_DTM		= (__force iwl_ucode_tlv_api_t)17, @@ -274,6 +276,7 @@ enum iwl_ucode_tlv_api {  	IWL_UCODE_TLV_API_STATS_V10		= (__force iwl_ucode_tlv_api_t)19,  	IWL_UCODE_TLV_API_NEW_VERSION		= (__force iwl_ucode_tlv_api_t)20,  	IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY	= (__force iwl_ucode_tlv_api_t)24, +	IWL_UCODE_TLV_API_TX_POWER_CHAIN	= (__force iwl_ucode_tlv_api_t)27,  };  typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; @@ -284,6 +287,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;   * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory   * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan.   * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer + * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM)   * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality   * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current   *	tx power value into TPC Report action frame and Link Measurement Report @@ -298,6 +302,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;   * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching   * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command   * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command + * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload   * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics   * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running   * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different @@ -305,12 +310,14 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;   *	IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR   *	is supported.   * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC + * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan   */  enum iwl_ucode_tlv_capa {  	IWL_UCODE_TLV_CAPA_D0I3_SUPPORT			= (__force iwl_ucode_tlv_capa_t)0,  	IWL_UCODE_TLV_CAPA_LAR_SUPPORT			= (__force iwl_ucode_tlv_capa_t)1,  	IWL_UCODE_TLV_CAPA_UMAC_SCAN			= (__force iwl_ucode_tlv_capa_t)2,  	IWL_UCODE_TLV_CAPA_BEAMFORMER			= (__force iwl_ucode_tlv_capa_t)3, +	IWL_UCODE_TLV_CAPA_TOF_SUPPORT                  = (__force iwl_ucode_tlv_capa_t)5,  	IWL_UCODE_TLV_CAPA_TDLS_SUPPORT			= (__force iwl_ucode_tlv_capa_t)6,  	IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT	= (__force iwl_ucode_tlv_capa_t)8,  	IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT	= (__force iwl_ucode_tlv_capa_t)9, @@ -320,10 +327,12 @@ enum iwl_ucode_tlv_capa {  	IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH		= (__force iwl_ucode_tlv_capa_t)13,  	IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT		= (__force iwl_ucode_tlv_capa_t)18,  	IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT		= (__force iwl_ucode_tlv_capa_t)19, +	IWL_UCODE_TLV_CAPA_CSUM_SUPPORT			= (__force iwl_ucode_tlv_capa_t)21,  	IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS		= (__force iwl_ucode_tlv_capa_t)22,  	IWL_UCODE_TLV_CAPA_BT_COEX_PLCR			= (__force iwl_ucode_tlv_capa_t)28,  	IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC		= (__force iwl_ucode_tlv_capa_t)29,  	IWL_UCODE_TLV_CAPA_BT_COEX_RRC			= (__force iwl_ucode_tlv_capa_t)30, +	IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT		= (__force iwl_ucode_tlv_capa_t)31,  };  /* The default calibrate table size if not specified by firmware file */ @@ -341,8 +350,9 @@ enum iwl_ucode_tlv_capa {   * For 16.0 uCode and above, there is no differentiation between sections,   * just an offset to the HW address.   */ -#define IWL_UCODE_SECTION_MAX 12 +#define IWL_UCODE_SECTION_MAX 16  #define CPU1_CPU2_SEPARATOR_SECTION	0xFFFFCCCC +#define PAGING_SEPARATOR_SECTION	0xAAAABBBB  /* uCode version contains 4 values: Major/Minor/API/Serial */  #define IWL_UCODE_MAJOR(ver)	(((ver) & 0xFF000000) >> 24) @@ -412,6 +422,12 @@ enum iwl_fw_dbg_reg_operator {  	PRPH_ASSIGN,  	PRPH_SETBIT,  	PRPH_CLEARBIT, + +	INDIRECT_ASSIGN, +	INDIRECT_SETBIT, +	INDIRECT_CLEARBIT, + +	PRPH_BLOCKBIT,  };  /** @@ -485,10 +501,13 @@ struct iwl_fw_dbg_conf_hcmd {   *   * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism   * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data + * @IWL_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to + *	collect only monitor data   */  enum iwl_fw_dbg_trigger_mode {  	IWL_FW_DBG_TRIGGER_START = BIT(0),  	IWL_FW_DBG_TRIGGER_STOP = BIT(1), +	IWL_FW_DBG_TRIGGER_MONITOR_ONLY = BIT(2),  };  /** @@ -718,4 +737,28 @@ struct iwl_fw_dbg_conf_tlv {  	struct iwl_fw_dbg_conf_hcmd hcmd;  } __packed; +/** + * struct iwl_fw_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + *	change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + *	hold. + */ +struct iwl_fw_gscan_capabilities { +	__le32 max_scan_cache_size; +	__le32 max_scan_buckets; +	__le32 max_ap_cache_per_scan; +	__le32 max_rssi_sample_size; +	__le32 max_scan_reporting_threshold; +	__le32 max_hotlist_aps; +	__le32 max_significant_change_aps; +	__le32 max_bssid_history_entries; +} __packed; +  #endif  /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 3e3c9d8b3c37..45e732150d28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -133,6 +133,7 @@ struct fw_desc {  struct fw_img {  	struct fw_desc sec[IWL_UCODE_SECTION_MAX];  	bool is_dual_cpus; +	u32 paging_mem_size;  };  struct iwl_sf_region { @@ -140,6 +141,48 @@ struct iwl_sf_region {  	u32 size;  }; +/* + * Block paging calculations + */ +#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ +#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */ +#define PAGE_PER_GROUP_2_EXP_SIZE 3 +/* 8 pages per group */ +#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE) +/* don't change, support only 32KB size */ +#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE) +/* 32K == 2^15 */ +#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE) + +/* + * Image paging calculations + */ +#define BLOCK_PER_IMAGE_2_EXP_SIZE 5 +/* 2^5 == 32 blocks per image */ +#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE) +/* maximum image size 1024KB */ +#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) + +/* Virtual address signature */ +#define PAGING_ADDR_SIG 0xAA000000 + +#define PAGING_CMD_IS_SECURED BIT(9) +#define PAGING_CMD_IS_ENABLED BIT(8) +#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS	0 +#define PAGING_TLV_SECURE_MASK 1 + +/** + * struct iwl_fw_paging + * @fw_paging_phys: page phy pointer + * @fw_paging_block: pointer to the allocated block + * @fw_paging_size: page size + */ +struct iwl_fw_paging { +	dma_addr_t fw_paging_phys; +	struct page *fw_paging_block; +	u32 fw_paging_size; +}; +  /**   * struct iwl_fw_cscheme_list - a cipher scheme list   * @size: a number of entries @@ -151,6 +194,30 @@ struct iwl_fw_cscheme_list {  } __packed;  /** + * struct iwl_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + *	change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + *	hold. + */ +struct iwl_gscan_capabilities { +	u32 max_scan_cache_size; +	u32 max_scan_buckets; +	u32 max_ap_cache_per_scan; +	u32 max_rssi_sample_size; +	u32 max_scan_reporting_threshold; +	u32 max_hotlist_aps; +	u32 max_significant_change_aps; +	u32 max_bssid_history_entries; +}; + +/**   * struct iwl_fw - variables associated with the firmware   *   * @ucode_ver: ucode version from the ucode file @@ -208,6 +275,7 @@ struct iwl_fw {  	struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];  	size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];  	u8 dbg_dest_reg_num; +	struct iwl_gscan_capabilities gscan_capa;  };  static inline const char *get_fw_dbg_mode_string(int mode) diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index b5bc959b1dfe..6caf2affbbb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -6,6 +6,7 @@   * GPL LICENSE SUMMARY   *   * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -98,7 +99,8 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,  				continue;  			for (i = 0; i < w->n_cmds; i++) { -				if (w->cmds[i] == pkt->hdr.cmd) { +				if (w->cmds[i] == +				    WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) {  					found = true;  					break;  				} @@ -136,7 +138,7 @@ IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);  void  iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,  			   struct iwl_notification_wait *wait_entry, -			   const u8 *cmds, int n_cmds, +			   const u16 *cmds, int n_cmds,  			   bool (*fn)(struct iwl_notif_wait_data *notif_wait,  				      struct iwl_rx_packet *pkt, void *data),  			   void *fn_data) @@ -147,7 +149,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,  	wait_entry->fn = fn;  	wait_entry->fn_data = fn_data;  	wait_entry->n_cmds = n_cmds; -	memcpy(wait_entry->cmds, cmds, n_cmds); +	memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16));  	wait_entry->triggered = false;  	wait_entry->aborted = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 95af97a6c2cf..dbe8234521de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -6,6 +6,7 @@   * GPL LICENSE SUMMARY   *   * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -105,7 +106,7 @@ struct iwl_notification_wait {  		   struct iwl_rx_packet *pkt, void *data);  	void *fn_data; -	u8 cmds[MAX_NOTIF_CMDS]; +	u16 cmds[MAX_NOTIF_CMDS];  	u8 n_cmds;  	bool triggered, aborted;  }; @@ -121,7 +122,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data);  void __acquires(wait_entry)  iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data,  			   struct iwl_notification_wait *wait_entry, -			   const u8 *cmds, int n_cmds, +			   const u16 *cmds, int n_cmds,  			   bool (*fn)(struct iwl_notif_wait_data *notif_data,  				      struct iwl_rx_packet *pkt, void *data),  			   void *fn_data); diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 80fefe7d7b8c..3b8e85e51002 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -540,13 +540,11 @@ static void iwl_set_hw_address_family_8000(struct device *dev,  		hw_addr = (const u8 *)(mac_override +  				 MAC_ADDRESS_OVERRIDE_FAMILY_8000); -		/* The byte order is little endian 16 bit, meaning 214365 */ -		data->hw_addr[0] = hw_addr[1]; -		data->hw_addr[1] = hw_addr[0]; -		data->hw_addr[2] = hw_addr[3]; -		data->hw_addr[3] = hw_addr[2]; -		data->hw_addr[4] = hw_addr[5]; -		data->hw_addr[5] = hw_addr[4]; +		/* +		 * Store the MAC address from MAO section. +		 * No byte swapping is required in MAO section +		 */ +		memcpy(data->hw_addr, hw_addr, ETH_ALEN);  		/*  		 * Force the use of the OTP MAC address in case of reserved MAC diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index ce1cdd7604e8..b47fe9d6b97a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -116,10 +116,6 @@ struct iwl_cfg;   *	May sleep   * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the   *	HCMD this Rx responds to. Can't sleep. - * @napi_add: NAPI initialization. The transport is fully responsible for NAPI, - *	but the higher layers need to know about it (in particular mac80211 to - *	to able to call the right NAPI RX functions); this function is needed - *	to eventually call netif_napi_add() with higher layer involvement.   * @queue_full: notifies that a HW queue is full.   *	Must be atomic and called with BH disabled.   * @queue_not_full: notifies that a HW queue is not full any more. @@ -148,13 +144,8 @@ struct iwl_op_mode_ops {  				     const struct iwl_fw *fw,  				     struct dentry *dbgfs_dir);  	void (*stop)(struct iwl_op_mode *op_mode); -	int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, -		  struct iwl_device_cmd *cmd); -	void (*napi_add)(struct iwl_op_mode *op_mode, -			 struct napi_struct *napi, -			 struct net_device *napi_dev, -			 int (*poll)(struct napi_struct *, int), -			 int weight); +	void (*rx)(struct iwl_op_mode *op_mode, struct napi_struct *napi, +		   struct iwl_rx_cmd_buffer *rxb);  	void (*queue_full)(struct iwl_op_mode *op_mode, int queue);  	void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);  	bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); @@ -188,11 +179,11 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)  	op_mode->ops->stop(op_mode);  } -static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *cmd) +static inline void iwl_op_mode_rx(struct iwl_op_mode *op_mode, +				  struct napi_struct *napi, +				  struct iwl_rx_cmd_buffer *rxb)  { -	return op_mode->ops->rx(op_mode, rxb, cmd); +	return op_mode->ops->rx(op_mode, napi, rxb);  }  static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, @@ -260,15 +251,4 @@ static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode)  	return op_mode->ops->exit_d0i3(op_mode);  } -static inline void iwl_op_mode_napi_add(struct iwl_op_mode *op_mode, -					struct napi_struct *napi, -					struct net_device *napi_dev, -					int (*poll)(struct napi_struct *, int), -					int weight) -{ -	if (!op_mode->ops->napi_add) -		return; -	op_mode->ops->napi_add(op_mode, napi, napi_dev, poll, weight); -} -  #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 5af1c776d2d4..3ab777f79e4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -253,6 +253,7 @@  #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)  #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)  #define SCD_GP_CTRL_ENABLE_31_QUEUES		BIT(0) +#define SCD_GP_CTRL_AUTO_ACTIVE_MODE		BIT(18)  /* Context Data */  #define SCD_CONTEXT_MEM_LOWER_BOUND	(SCD_MEM_LOWER_BOUND + 0x600) @@ -291,6 +292,9 @@  /*********************** END TX SCHEDULER *************************************/ +/* tcp checksum offload */ +#define RX_EN_CSUM		(0x00a00d88) +  /* Oscillator clock */  #define OSC_CLK				(0xa04068)  #define OSC_CLK_FORCE_CONTROL		(0x8) @@ -379,6 +383,8 @@ enum aux_misc_master1_en {  #define AUX_MISC_MASTER1_SMPHR_STATUS	0xA20800  #define RSA_ENABLE			0xA24B08  #define PREG_AUX_BUS_WPROT_0		0xA04CC0 +#define SB_CPU_1_STATUS			0xA01E30 +#define SB_CPU_2_STATUS			0xA01E34  /* FW chicken bits */  #define LMPM_CHICK			0xA01FF8 @@ -386,4 +392,10 @@ enum {  	LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0),  }; +/* FW chicken bits */ +#define LMPM_PAGE_PASS_NOTIF			0xA03824 +enum { +	LMPM_PAGE_PASS_NOTIF_POS = BIT(20), +}; +  #endif				/* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 87a230a7f4b6..c829c505e141 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -122,6 +122,40 @@  #define INDEX_TO_SEQ(i)	((i) & 0xff)  #define SEQ_RX_FRAME	cpu_to_le16(0x8000) +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ +	return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ +	return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ +	return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ +	return opcode + (groupid << 8) + (version << 16); +} + +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) ((grp << 8) | opcode) + +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP	1 +  /**   * struct iwl_cmd_header   * @@ -130,7 +164,7 @@   */  struct iwl_cmd_header {  	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */ -	u8 flags;	/* 0:5 reserved, 6 abort, 7 internal */ +	u8 group_id;  	/*  	 * The driver sets up the sequence number to values of its choosing.  	 * uCode does not use this value, but passes it back to the driver @@ -154,9 +188,22 @@ struct iwl_cmd_header {  	__le16 sequence;  } __packed; -/* iwl_cmd_header flags value */ -#define IWL_CMD_FAILED_MSK 0x40 - +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { +	u8 cmd; +	u8 group_id; +	__le16 sequence; +	__le16 length; +	u8 reserved; +	u8 version; +} __packed;  #define FH_RSCSR_FRAME_SIZE_MSK		0x00003FFF	/* bits 0-13 */  #define FH_RSCSR_FRAME_INVALID		0x55550000 @@ -201,6 +248,8 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)   * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle.   * @CMD_WAKE_UP_TRANS: The command response should wake up the trans   *	(i.e. mark it as non-idle). + * @CMD_TB_BITMAP_POS: Position of the first bit for the TB bitmap. We need to + *	check that we leave enough room for the TBs bitmap which needs 20 bits.   */  enum CMD_MODE {  	CMD_ASYNC		= BIT(0), @@ -210,6 +259,8 @@ enum CMD_MODE {  	CMD_SEND_IN_IDLE	= BIT(4),  	CMD_MAKE_TRANS_IDLE	= BIT(5),  	CMD_WAKE_UP_TRANS	= BIT(6), + +	CMD_TB_BITMAP_POS	= 11,  };  #define DEF_CMD_PAYLOAD_SIZE 320 @@ -222,8 +273,18 @@ enum CMD_MODE {   * aren't fully copied and use other TFD space.   */  struct iwl_device_cmd { -	struct iwl_cmd_header hdr;	/* uCode API */ -	u8 payload[DEF_CMD_PAYLOAD_SIZE]; +	union { +		struct { +			struct iwl_cmd_header hdr;	/* uCode API */ +			u8 payload[DEF_CMD_PAYLOAD_SIZE]; +		}; +		struct { +			struct iwl_cmd_header_wide hdr_wide; +			u8 payload_wide[DEF_CMD_PAYLOAD_SIZE - +					sizeof(struct iwl_cmd_header_wide) + +					sizeof(struct iwl_cmd_header)]; +		}; +	};  } __packed;  #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) @@ -261,24 +322,22 @@ enum iwl_hcmd_dataflag {   * @resp_pkt: response packet, if %CMD_WANT_SKB was set   * @_rx_page_order: (internally used to free response packet)   * @_rx_page_addr: (internally used to free response packet) - * @handler_status: return value of the handler of the command - *	(put in setup_rx_handlers) - valid for SYNC mode only   * @flags: can be CMD_*   * @len: array of the lengths of the chunks in data   * @dataflags: IWL_HCMD_DFL_* - * @id: id of the host command + * @id: command id of the host command, for wide commands encoding the + *	version and group as well   */  struct iwl_host_cmd {  	const void *data[IWL_MAX_CMD_TBS_PER_TFD];  	struct iwl_rx_packet *resp_pkt;  	unsigned long _rx_page_addr;  	u32 _rx_page_order; -	int handler_status;  	u32 flags; +	u32 id;  	u16 len[IWL_MAX_CMD_TBS_PER_TFD];  	u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD]; -	u8 id;  };  static inline void iwl_free_resp(struct iwl_host_cmd *cmd) @@ -379,6 +438,7 @@ enum iwl_trans_status {   * @bc_table_dword: set to true if the BC table expects the byte count to be   *	in DWORD (as opposed to bytes)   * @scd_set_active: should the transport configure the SCD for HCMD queue + * @wide_cmd_header: firmware supports wide host command header   * @command_names: array of command names, must be 256 entries   *	(one for each command); for debugging only   * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until @@ -396,6 +456,7 @@ struct iwl_trans_config {  	bool rx_buf_size_8k;  	bool bc_table_dword;  	bool scd_set_active; +	bool wide_cmd_header;  	const char *const *command_names;  	u32 sdio_adma_addr; @@ -544,10 +605,12 @@ struct iwl_trans_ops {  			      u32 value);  	void (*ref)(struct iwl_trans *trans);  	void (*unref)(struct iwl_trans *trans); -	void (*suspend)(struct iwl_trans *trans); +	int  (*suspend)(struct iwl_trans *trans);  	void (*resume)(struct iwl_trans *trans); -	struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); +	struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, +						 struct iwl_fw_dbg_trigger_tlv +						 *trigger);  };  /** @@ -584,6 +647,8 @@ enum iwl_d0i3_mode {   * @cfg - pointer to the configuration   * @status: a bit-mask of transport status flags   * @dev - pointer to struct device * that represents the device + * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. + *	0 indicates that frag SKBs (NETIF_F_SG) aren't supported.   * @hw_id: a u32 with the ID of the device / sub-device.   *	Set during transport allocation.   * @hw_id_str: a string with info about HW ID. Set during transport allocation. @@ -603,6 +668,12 @@ enum iwl_d0i3_mode {   * @dbg_conf_tlv: array of pointers to configuration TLVs for debug   * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug   * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + * @paging_req_addr: The location were the FW will upload / download the pages + *	from. The address is set by the opmode + * @paging_db: Pointer to the opmode paging data base, the pointer is set by + *	the opmode. + * @paging_download_buf: Buffer used for copying all of the pages before + *	downloading them to the FW. The buffer is allocated in the opmode   */  struct iwl_trans {  	const struct iwl_trans_ops *ops; @@ -612,6 +683,7 @@ struct iwl_trans {  	unsigned long status;  	struct device *dev; +	u32 max_skb_frags;  	u32 hw_rev;  	u32 hw_id;  	char hw_id_str[52]; @@ -639,6 +711,14 @@ struct iwl_trans {  	struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;  	u8 dbg_dest_reg_num; +	/* +	 * Paging parameters - All of the parameters should be set by the +	 * opmode when paging is enabled +	 */ +	u32 paging_req_addr; +	struct iwl_fw_paging *paging_db; +	void *paging_download_buf; +  	enum iwl_d0i3_mode d0i3_mode;  	bool wowlan_d0i3; @@ -730,7 +810,8 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)  static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)  {  	might_sleep(); -	trans->ops->d3_suspend(trans, test); +	if (trans->ops->d3_suspend) +		trans->ops->d3_suspend(trans, test);  }  static inline int iwl_trans_d3_resume(struct iwl_trans *trans, @@ -738,6 +819,9 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans,  				      bool test)  {  	might_sleep(); +	if (!trans->ops->d3_resume) +		return 0; +  	return trans->ops->d3_resume(trans, status, test);  } @@ -753,10 +837,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)  		trans->ops->unref(trans);  } -static inline void iwl_trans_suspend(struct iwl_trans *trans) +static inline int iwl_trans_suspend(struct iwl_trans *trans)  { -	if (trans->ops->suspend) -		trans->ops->suspend(trans); +	if (!trans->ops->suspend) +		return 0; + +	return trans->ops->suspend(trans);  }  static inline void iwl_trans_resume(struct iwl_trans *trans) @@ -766,11 +852,12 @@ static inline void iwl_trans_resume(struct iwl_trans *trans)  }  static inline struct iwl_trans_dump_data * -iwl_trans_dump_data(struct iwl_trans *trans) +iwl_trans_dump_data(struct iwl_trans *trans, +		    struct iwl_fw_dbg_trigger_tlv *trigger)  {  	if (!trans->ops->dump_data)  		return NULL; -	return trans->ops->dump_data(trans); +	return trans->ops->dump_data(trans, trigger);  }  static inline int iwl_trans_send_cmd(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 2d7c3ea3c4f8..8c2c3d13b092 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -6,6 +6,7 @@ iwlmvm-y += power.o coex.o coex_legacy.o  iwlmvm-y += tt.o offloading.o tdls.o  iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o  iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o +iwlmvm-y += tof.o  iwlmvm-$(CONFIG_PM_SLEEP) += d3.o  ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index b4737e296c92..e290ac67d975 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -725,15 +725,17 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)  	}  } -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, -			     struct iwl_rx_cmd_buffer *rxb, -			     struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, +			      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; -	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) -		return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); +	if (!fw_has_api(&mvm->fw->ucode_capa, +			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { +		iwl_mvm_rx_bt_coex_notif_old(mvm, rxb); +		return; +	}  	IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");  	IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); @@ -748,12 +750,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,  	memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));  	iwl_mvm_bt_coex_notif_handle(mvm); - -	/* -	 * This is an async handler for a notification, returning anything other -	 * than 0 doesn't make sense even if HCMD failed. -	 */ -	return 0;  }  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -947,9 +943,8 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)  	iwl_mvm_bt_coex_notif_handle(mvm);  } -int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, +				   struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u32 ant_isolation = le32_to_cpup((void *)pkt->data); @@ -957,20 +952,23 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,  	u8 __maybe_unused lower_bound, upper_bound;  	u8 lut; -	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) -		return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); +	if (!fw_has_api(&mvm->fw->ucode_capa, +			IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { +		iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb); +		return; +	}  	if (!iwl_mvm_bt_is_plcr_supported(mvm)) -		return 0; +		return;  	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; +		return;  	if (ant_isolation ==  mvm->last_ant_isol) -		return 0; +		return;  	for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++)  		if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -989,7 +987,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,  	mvm->last_ant_isol = ant_isolation;  	if (mvm->last_corun_lut == lut) -		return 0; +		return;  	mvm->last_corun_lut = lut; @@ -1000,6 +998,8 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,  	memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20,  	       sizeof(cmd.corun_lut40)); -	return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, -				    sizeof(cmd), &cmd); +	if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, +				 sizeof(cmd), &cmd)) +		IWL_ERR(mvm, +			"failed to send BT_COEX_UPDATE_CORUN_LUT command\n");  } diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 6ac6de2af977..61c07b05fcaa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -1058,9 +1058,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)  		IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");  } -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, -				 struct iwl_rx_cmd_buffer *rxb, -				 struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, +				  struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; @@ -1083,12 +1082,6 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,  	memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old));  	iwl_mvm_bt_coex_notif_handle(mvm); - -	/* -	 * This is an async handler for a notification, returning anything other -	 * than 0 doesn't make sense even if HCMD failed. -	 */ -	return 0;  }  static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, @@ -1250,14 +1243,12 @@ void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm)  	iwl_mvm_bt_coex_notif_handle(mvm);  } -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, -				      struct iwl_rx_cmd_buffer *rxb, -				      struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, +				       struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u32 ant_isolation = le32_to_cpup((void *)pkt->data);  	u8 __maybe_unused lower_bound, upper_bound; -	int ret;  	u8 lut;  	struct iwl_bt_coex_cmd_old *bt_cmd; @@ -1268,16 +1259,16 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,  	};  	if (!iwl_mvm_bt_is_plcr_supported(mvm)) -		return 0; +		return;  	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; +		return;  	if (ant_isolation ==  mvm->last_ant_isol) -		return 0; +		return;  	for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++)  		if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -1296,13 +1287,13 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,  	mvm->last_ant_isol = ant_isolation;  	if (mvm->last_corun_lut == lut) -		return 0; +		return;  	mvm->last_corun_lut = lut;  	bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);  	if (!bt_cmd) -		return 0; +		return;  	cmd.data[0] = bt_cmd;  	bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); @@ -1317,8 +1308,8 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,  	memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20,  	       sizeof(bt_cmd->bt4_corun_lut40)); -	ret = iwl_mvm_send_cmd(mvm, &cmd); +	if (iwl_mvm_send_cmd(mvm, &cmd)) +		IWL_ERR(mvm, "failed to send BT_CONFIG command\n");  	kfree(bt_cmd); -	return ret;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index beba375489f1..b8ee3121fbd2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -102,6 +102,7 @@  #define IWL_MVM_QUOTA_THRESHOLD			4  #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0  #define IWL_MVM_RS_DISABLE_P2P_MIMO		0 +#define IWL_MVM_TOF_IS_RESPONDER		0  #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE    1  #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE      2  #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW   1 diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 4165d104e4c3..04264e417c1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1145,7 +1145,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,  static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm)  {  	struct iwl_notification_wait wait_d3; -	static const u8 d3_notif[] = { D3_CONFIG_CMD }; +	static const u16 d3_notif[] = { D3_CONFIG_CMD };  	int ret;  	iwl_init_notification_wait(&mvm->notif_wait, &wait_d3, @@ -1168,13 +1168,17 @@ remove_notif:  int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  {  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	int ret; + +	ret = iwl_trans_suspend(mvm->trans); +	if (ret) +		return ret; -	iwl_trans_suspend(mvm->trans);  	mvm->trans->wowlan_d0i3 = wowlan->any;  	if (mvm->trans->wowlan_d0i3) {  		/* 'any' trigger means d0i3 usage */  		if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { -			int ret = iwl_mvm_enter_d0i3_sync(mvm); +			ret = iwl_mvm_enter_d0i3_sync(mvm);  			if (ret)  				return ret; @@ -1183,6 +1187,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  		mutex_lock(&mvm->d0i3_suspend_mutex);  		__set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);  		mutex_unlock(&mvm->d0i3_suspend_mutex); + +		iwl_trans_d3_suspend(mvm->trans, false); +  		return 0;  	} @@ -1935,28 +1942,59 @@ out:  	return 1;  } -int iwl_mvm_resume(struct ieee80211_hw *hw) +static int iwl_mvm_resume_d3(struct iwl_mvm *mvm)  { -	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); +	iwl_trans_resume(mvm->trans); + +	return __iwl_mvm_resume(mvm, false); +} + +static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) +{ +	bool exit_now; +	enum iwl_d3_status d3_status; + +	iwl_trans_d3_resume(mvm->trans, &d3_status, false); + +	/* +	 * make sure to clear D0I3_DEFER_WAKEUP before +	 * calling iwl_trans_resume(), which might wait +	 * for d0i3 exit completion. +	 */ +	mutex_lock(&mvm->d0i3_suspend_mutex); +	__clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); +	exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, +					&mvm->d0i3_suspend_flags); +	mutex_unlock(&mvm->d0i3_suspend_mutex); +	if (exit_now) { +		IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); +		_iwl_mvm_exit_d0i3(mvm); +	}  	iwl_trans_resume(mvm->trans); -	if (mvm->hw->wiphy->wowlan_config->any) { -		/* 'any' trigger means d0i3 usage */ -		if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { -			int ret = iwl_mvm_exit_d0i3(hw->priv); +	if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { +		int ret = iwl_mvm_exit_d0i3(mvm->hw->priv); -			if (ret) -				return ret; -			/* -			 * d0i3 exit will be deferred until reconfig_complete. -			 * make sure there we are out of d0i3. -			 */ -		} -		return 0; +		if (ret) +			return ret; +		/* +		 * d0i3 exit will be deferred until reconfig_complete. +		 * make sure there we are out of d0i3. +		 */  	} +	return 0; +} -	return __iwl_mvm_resume(mvm, false); +int iwl_mvm_resume(struct ieee80211_hw *hw) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + +	/* 'any' trigger means d0i3 was used */ +	if (hw->wiphy->wowlan_config->any) +		return iwl_mvm_resume_d0i3(mvm); +	else +		return iwl_mvm_resume_d3(mvm);  }  void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 5c8a65de0e77..383a3162046c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -63,6 +63,7 @@   *   *****************************************************************************/  #include "mvm.h" +#include "fw-api-tof.h"  #include "debugfs.h"  static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, @@ -497,6 +498,731 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,  	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);  } +static inline char *iwl_dbgfs_is_match(char *name, char *buf) +{ +	int len = strlen(name); + +	return !strncmp(name, buf, len) ? buf + len : NULL; +} + +static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif, +					  char *buf, +					  size_t count, loff_t *ppos) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	int value, ret = -EINVAL; +	char *data; + +	mutex_lock(&mvm->mutex); + +	data = iwl_dbgfs_is_match("tof_disabled=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.tof_cfg.tof_disabled = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("one_sided_disabled=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.tof_cfg.one_sided_disabled = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("is_debug_mode=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.tof_cfg.is_debug_mode = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("is_buf=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.tof_cfg.is_buf_required = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("send_tof_cfg=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0 && value) { +			ret = iwl_mvm_tof_config_cmd(mvm); +			goto out; +		} +	} + +out: +	mutex_unlock(&mvm->mutex); + +	return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_enable_read(struct file *file, +					 char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[256]; +	int pos = 0; +	const size_t bufsz = sizeof(buf); +	struct iwl_tof_config_cmd *cmd; + +	cmd = &mvm->tof_data.tof_cfg; + +	mutex_lock(&mvm->mutex); + +	pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n", +			 cmd->tof_disabled); +	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n", +			 cmd->one_sided_disabled); +	pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n", +			 cmd->is_debug_mode); +	pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n", +			 cmd->is_buf_required); + +	mutex_unlock(&mvm->mutex); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif, +						    char *buf, +						    size_t count, loff_t *ppos) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	int value, ret = 0; +	char *data; + +	mutex_lock(&mvm->mutex); + +	data = iwl_dbgfs_is_match("burst_period=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (!ret) +			mvm->tof_data.responder_cfg.burst_period = +							cpu_to_le16(value); +		goto out; +	} + +	data = iwl_dbgfs_is_match("min_delta_ftm=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.min_delta_ftm = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("burst_duration=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.burst_duration = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("num_of_burst_exp=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.num_of_burst_exp = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("abort_responder=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.abort_responder = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("get_ch_est=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.get_ch_est = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("recv_sta_req_params=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.recv_sta_req_params = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("channel_num=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.channel_num = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("bandwidth=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.bandwidth = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("rate=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.rate = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("bssid=", buf); +	if (data) { +		u8 *mac = mvm->tof_data.responder_cfg.bssid; + +		if (!mac_pton(data, mac)) { +			ret = -EINVAL; +			goto out; +		} +	} + +	data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.tsf_timer_offset_msecs = +							cpu_to_le16(value); +		goto out; +	} + +	data = iwl_dbgfs_is_match("toa_offset=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.toa_offset = +							cpu_to_le16(value); +		goto out; +	} + +	data = iwl_dbgfs_is_match("ctrl_ch_position=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.ctrl_ch_position = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("ftm_per_burst=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.ftm_per_burst = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("asap_mode=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.responder_cfg.asap_mode = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("send_responder_cfg=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0 && value) { +			ret = iwl_mvm_tof_responder_cmd(mvm, vif); +			goto out; +		} +	} + +out: +	mutex_unlock(&mvm->mutex); + +	return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file, +						   char __user *user_buf, +						   size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[256]; +	int pos = 0; +	const size_t bufsz = sizeof(buf); +	struct iwl_tof_responder_config_cmd *cmd; + +	cmd = &mvm->tof_data.responder_cfg; + +	mutex_lock(&mvm->mutex); + +	pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", +			 le16_to_cpu(cmd->burst_period)); +	pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", +			 cmd->burst_duration); +	pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", +			 cmd->bandwidth); +	pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", +			 cmd->channel_num); +	pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", +			 cmd->ctrl_ch_position); +	pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", +			 cmd->bssid); +	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", +			 cmd->min_delta_ftm); +	pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", +			 cmd->num_of_burst_exp); +	pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); +	pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", +			 cmd->abort_responder); +	pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", +			 cmd->get_ch_est); +	pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", +			 cmd->recv_sta_req_params); +	pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", +			 cmd->ftm_per_burst); +	pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", +			 cmd->ftm_resp_ts_avail); +	pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", +			 cmd->asap_mode); +	pos += scnprintf(buf + pos, bufsz - pos, +			 "tsf_timer_offset_msecs = %d\n", +			 le16_to_cpu(cmd->tsf_timer_offset_msecs)); +	pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", +			 le16_to_cpu(cmd->toa_offset)); + +	mutex_unlock(&mvm->mutex); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, +						 char *buf, size_t count, +						 loff_t *ppos) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	int value, ret = 0; +	char *data; + +	mutex_lock(&mvm->mutex); + +	data = iwl_dbgfs_is_match("request_id=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.request_id = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("initiator=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.initiator = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.one_sided_los_disable = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("req_timeout=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.req_timeout = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("report_policy=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.report_policy = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("macaddr_random=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.macaddr_random = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("num_of_ap=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req.num_of_ap = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("macaddr_template=", buf); +	if (data) { +		u8 mac[ETH_ALEN]; + +		if (!mac_pton(data, mac)) { +			ret = -EINVAL; +			goto out; +		} +		memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); +	} + +	data = iwl_dbgfs_is_match("macaddr_mask=", buf); +	if (data) { +		u8 mac[ETH_ALEN]; + +		if (!mac_pton(data, mac)) { +			ret = -EINVAL; +			goto out; +		} +		memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); +	} + +	data = iwl_dbgfs_is_match("ap=", buf); +	if (data) { +		struct iwl_tof_range_req_ap_entry ap; +		int size = sizeof(struct iwl_tof_range_req_ap_entry); +		u16 burst_period; +		u8 *mac = ap.bssid; +		unsigned int i; + +		if (sscanf(data, "%u %hhd %hhx %hhx" +			   "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" +			   "%hhx %hhx %hx" +			   "%hhx %hhx %x" +			   "%hhx %hhx %hhx %hhx", +			   &i, &ap.channel_num, &ap.bandwidth, +			   &ap.ctrl_ch_position, +			   mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, +			   &ap.measure_type, &ap.num_of_bursts, +			   &burst_period, +			   &ap.samples_per_burst, &ap.retries_per_sample, +			   &ap.tsf_delta, &ap.location_req, &ap.asap_mode, +			   &ap.enable_dyn_ack, &ap.rssi) != 20) { +			ret = -EINVAL; +			goto out; +		} +		if (i >= IWL_MVM_TOF_MAX_APS) { +			IWL_ERR(mvm, "Invalid AP index %d\n", i); +			ret = -EINVAL; +			goto out; +		} + +		ap.burst_period = cpu_to_le16(burst_period); + +		memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); +		goto out; +	} + +	data = iwl_dbgfs_is_match("send_range_request=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0 && value) { +			ret = iwl_mvm_tof_range_request_cmd(mvm, vif); +			goto out; +		} +	} + +out: +	mutex_unlock(&mvm->mutex); +	return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file, +						char __user *user_buf, +						size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[512]; +	int pos = 0; +	const size_t bufsz = sizeof(buf); +	struct iwl_tof_range_req_cmd *cmd; +	int i; + +	cmd = &mvm->tof_data.range_req; + +	mutex_lock(&mvm->mutex); + +	pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", +			 cmd->request_id); +	pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", +			 cmd->initiator); +	pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", +			 cmd->one_sided_los_disable); +	pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", +			 cmd->req_timeout); +	pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", +			 cmd->report_policy); +	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", +			 cmd->macaddr_random); +	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", +			 cmd->macaddr_template); +	pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", +			 cmd->macaddr_mask); +	pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", +			 cmd->num_of_ap); +	for (i = 0; i < cmd->num_of_ap; i++) { +		struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; + +		pos += scnprintf(buf + pos, bufsz - pos, +				"ap %.2d: channel_num=%hhx bw=%hhx" +				" control=%hhx bssid=%pM type=%hhx" +				" num_of_bursts=%hhx burst_period=%hx ftm=%hhx" +				" retries=%hhx tsf_delta=%x location_req=%hhx " +				" asap=%hhx enable=%hhx rssi=%hhx\n", +				i, ap->channel_num, ap->bandwidth, +				ap->ctrl_ch_position, ap->bssid, +				ap->measure_type, ap->num_of_bursts, +				ap->burst_period, ap->samples_per_burst, +				ap->retries_per_sample, ap->tsf_delta, +				ap->location_req, ap->asap_mode, +				ap->enable_dyn_ack, ap->rssi); +	} + +	mutex_unlock(&mvm->mutex); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif, +						 char *buf, +						 size_t count, loff_t *ppos) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	int value, ret = 0; +	char *data; + +	mutex_lock(&mvm->mutex); + +	data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req_ext.tsf_timer_offset_msec = +							cpu_to_le16(value); +		goto out; +	} + +	data = iwl_dbgfs_is_match("min_delta_ftm=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req_ext.min_delta_ftm = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req_ext.ftm_format_and_bw20M = +									value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req_ext.ftm_format_and_bw40M = +									value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.range_req_ext.ftm_format_and_bw80M = +									value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("send_range_req_ext=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0 && value) { +			ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); +			goto out; +		} +	} + +out: +	mutex_unlock(&mvm->mutex); +	return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file, +						char __user *user_buf, +						size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[256]; +	int pos = 0; +	const size_t bufsz = sizeof(buf); +	struct iwl_tof_range_req_ext_cmd *cmd; + +	cmd = &mvm->tof_data.range_req_ext; + +	mutex_lock(&mvm->mutex); + +	pos += scnprintf(buf + pos, bufsz - pos, +			 "tsf_timer_offset_msec = %hx\n", +			 cmd->tsf_timer_offset_msec); +	pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhx\n", +			 cmd->min_delta_ftm); +	pos += scnprintf(buf + pos, bufsz - pos, +			 "ftm_format_and_bw20M = %hhx\n", +			 cmd->ftm_format_and_bw20M); +	pos += scnprintf(buf + pos, bufsz - pos, +			 "ftm_format_and_bw40M = %hhx\n", +			 cmd->ftm_format_and_bw40M); +	pos += scnprintf(buf + pos, bufsz - pos, +			 "ftm_format_and_bw80M = %hhx\n", +			 cmd->ftm_format_and_bw80M); + +	mutex_unlock(&mvm->mutex); +	return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif, +					       char *buf, +					       size_t count, loff_t *ppos) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	int value, ret = 0; +	int abort_id; +	char *data; + +	mutex_lock(&mvm->mutex); + +	data = iwl_dbgfs_is_match("abort_id=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0) +			mvm->tof_data.last_abort_id = value; +		goto out; +	} + +	data = iwl_dbgfs_is_match("send_range_abort=", buf); +	if (data) { +		ret = kstrtou32(data, 10, &value); +		if (ret == 0 && value) { +			abort_id = mvm->tof_data.last_abort_id; +			ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); +			goto out; +		} +	} + +out: +	mutex_unlock(&mvm->mutex); +	return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file, +					      char __user *user_buf, +					      size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char buf[32]; +	int pos = 0; +	const size_t bufsz = sizeof(buf); +	int last_abort_id; + +	mutex_lock(&mvm->mutex); +	last_abort_id = mvm->tof_data.last_abort_id; +	mutex_unlock(&mvm->mutex); + +	pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", +			 last_abort_id); +	return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file, +						 char __user *user_buf, +						 size_t count, loff_t *ppos) +{ +	struct ieee80211_vif *vif = file->private_data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm *mvm = mvmvif->mvm; +	char *buf; +	int pos = 0; +	const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; +	struct iwl_tof_range_rsp_ntfy *cmd; +	int i, ret; + +	buf = kzalloc(bufsz, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	mutex_lock(&mvm->mutex); +	cmd = &mvm->tof_data.range_resp; + +	pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", +			 cmd->request_id); +	pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", +			 cmd->request_status); +	pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", +			 cmd->last_in_batch); +	pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", +			 cmd->num_of_aps); +	for (i = 0; i < cmd->num_of_aps; i++) { +		struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; + +		pos += scnprintf(buf + pos, bufsz - pos, +				"ap %.2d: bssid=%pM status=%hhx bw=%hhx" +				" rtt=%x rtt_var=%x rtt_spread=%x" +				" rssi=%hhx  rssi_spread=%hhx" +				" range=%x range_var=%x" +				" time_stamp=%x\n", +				i, ap->bssid, ap->measure_status, +				ap->measure_bw, +				ap->rtt, ap->rtt_variance, ap->rtt_spread, +				ap->rssi, ap->rssi_spread, ap->range, +				ap->range_variance, ap->timestamp); +	} +	mutex_unlock(&mvm->mutex); + +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +	kfree(buf); +	return ret; +} +  static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,  					   size_t count, loff_t *ppos)  { @@ -628,6 +1354,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);  MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); +MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);  void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  { @@ -671,6 +1403,25 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,  					 S_IRUSR | S_IWUSR); +	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && +	    !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { +		if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) +			MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, +						 mvmvif->dbgfs_dir, +						 S_IRUSR | S_IWUSR); + +		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, +					 S_IRUSR | S_IWUSR); +		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, +					 S_IRUSR | S_IWUSR); +		MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, +					 S_IRUSR | S_IWUSR); +		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, +					 S_IRUSR | S_IWUSR); +		MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, +					 S_IRUSR); +	} +  	/*  	 * Create symlink for convenience pointing to interface specific  	 * debugfs entries for the driver. For example, under diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ffb4b5cef275..7d69a556bcc8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -949,9 +949,10 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,  					   char *buf, size_t count,  					   loff_t *ppos)  { -	int ret, conf_id; +	unsigned int conf_id; +	int ret; -	ret = kstrtoint(buf, 0, &conf_id); +	ret = kstrtouint(buf, 0, &conf_id);  	if (ret)  		return ret; @@ -974,7 +975,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,  	if (ret)  		return ret; -	iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, 0); +	iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, NULL);  	iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); @@ -1200,12 +1201,7 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,  	if (ptr) {  		for (ofs = 0; ofs < len; ofs += 16) {  			pos += scnprintf(buf + pos, bufsz - pos, -					 "0x%.4x ", ofs); -			hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, -					   bufsz - pos, false); -			pos += strlen(buf + pos); -			if (bufsz - pos > 0) -				buf[pos++] = '\n'; +					 "0x%.4x %16ph\n", ofs, ptr + ofs);  		}  	} else {  		pos += scnprintf(buf + pos, bufsz - pos, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index d7658d16e965..20521bebb0b1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -339,8 +339,13 @@ enum iwl_wowlan_wakeup_reason {  	IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE			= BIT(8),  	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS			= BIT(9),  	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE		= BIT(10), -	/* BIT(11) reserved */ +	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL		= BIT(11),  	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET		= BIT(12), +	IWL_WOWLAN_WAKEUP_BY_IOAC_MAGIC_PACKET			= BIT(13), +	IWL_WOWLAN_WAKEUP_BY_D3_WAKEUP_HOST_TIMER		= BIT(14), +	IWL_WOWLAN_WAKEUP_BY_RXFRAME_FILTERED_IN		= BIT(15), +	IWL_WOWLAN_WAKEUP_BY_BEACON_FILTERED_IN			= BIT(16), +  }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */  struct iwl_wowlan_gtk_status { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index b1baa33cc19b..7005fa4be74a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -7,6 +7,7 @@   *   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@   *   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -310,17 +312,22 @@ struct iwl_reduce_tx_power_cmd {  	__le16 pwr_restriction;  } __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ +enum iwl_dev_tx_power_cmd_mode { +	IWL_TX_POWER_MODE_SET_MAC = 0, +	IWL_TX_POWER_MODE_SET_DEVICE = 1, +	IWL_TX_POWER_MODE_SET_CHAINS = 2, +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */; +  /** - * struct iwl_dev_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @set_mode: 0 - MAC tx power, 1 - device tx power + * struct iwl_dev_tx_power_cmd_v2 - TX power reduction command + * @set_mode: see &enum iwl_dev_tx_power_cmd_mode   * @mac_context_id: id of the mac ctx for which we are reducing TX power.   * @pwr_restriction: TX power restriction in 1/8 dBms.   * @dev_24: device TX power restriction in 1/8 dBms   * @dev_52_low: device TX power restriction upper band - low   * @dev_52_high: device TX power restriction upper band - high   */ -struct iwl_dev_tx_power_cmd { +struct iwl_dev_tx_power_cmd_v2 {  	__le32 set_mode;  	__le32 mac_context_id;  	__le16 pwr_restriction; @@ -329,6 +336,20 @@ struct iwl_dev_tx_power_cmd {  	__le16 dev_52_high;  } __packed; /* TX_REDUCED_POWER_API_S_VER_2 */ +#define IWL_NUM_CHAIN_LIMITS	2 +#define IWL_NUM_SUB_BANDS	5 + +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * @v2: version 2 of the command, embedded here for easier software handling + * @per_chain_restriction: per chain restrictions + */ +struct iwl_dev_tx_power_cmd { +	/* v3 is just an extension of v2 - keep this here */ +	struct iwl_dev_tx_power_cmd_v2 v2; +	__le16 per_chain_restriction[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS]; +} __packed; /* TX_REDUCED_POWER_API_S_VER_3 */ +  #define IWL_DEV_MAX_TX_POWER 0x7FFF  /** @@ -413,7 +434,7 @@ struct iwl_beacon_filter_cmd {  #define IWL_BF_TEMP_FAST_FILTER_MIN 0  #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 -#define IWL_BF_TEMP_SLOW_FILTER_D0I3 5 +#define IWL_BF_TEMP_SLOW_FILTER_D0I3 20  #define IWL_BF_TEMP_SLOW_FILTER_MAX 255  #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 5e4cbdb44c60..660cc1c93e19 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -87,41 +87,6 @@ struct iwl_ssid_ie {  	u8 ssid[IEEE80211_MAX_SSID_LEN];  } __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ -/* How many statistics are gathered for each channel */ -#define SCAN_RESULTS_STATISTICS 1 - -/** - * enum iwl_scan_complete_status - status codes for scan complete notifications - * @SCAN_COMP_STATUS_OK:  scan completed successfully - * @SCAN_COMP_STATUS_ABORT: scan was aborted by user - * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed - * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready - * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed - * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed - * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command - * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort - * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax - * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful - *	(not an error!) - * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repetition the driver - *	asked for - * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events -*/ -enum iwl_scan_complete_status { -	SCAN_COMP_STATUS_OK = 0x1, -	SCAN_COMP_STATUS_ABORT = 0x2, -	SCAN_COMP_STATUS_ERR_SLEEP = 0x3, -	SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, -	SCAN_COMP_STATUS_ERR_PROBE = 0x5, -	SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, -	SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, -	SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, -	SCAN_COMP_STATUS_ERR_COEX = 0x9, -	SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, -	SCAN_COMP_STATUS_ITERATION_END = 0x0B, -	SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, -}; -  /* scan offload */  #define IWL_SCAN_MAX_BLACKLIST_LEN	64  #define IWL_SCAN_SHORT_BLACKLIST_LEN	16 @@ -144,71 +109,6 @@ enum scan_framework_client {  };  /** - * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 - * @scan_flags:		see enum iwl_scan_flags - * @channel_count:	channels in channel list - * @quiet_time:		dwell time, in milliseconds, on quiet channel - * @quiet_plcp_th:	quiet channel num of packets threshold - * @good_CRC_th:	passive to active promotion threshold - * @rx_chain:		RXON rx chain. - * @max_out_time:	max TUs to be out of associated channel - * @suspend_time:	pause scan this TUs when returning to service channel - * @flags:		RXON flags - * @filter_flags:	RXONfilter - * @tx_cmd:		tx command for active scan; for 2GHz and for 5GHz. - * @direct_scan:	list of SSIDs for directed active scan - * @scan_type:		see enum iwl_scan_type. - * @rep_count:		repetition count for each scheduled scan iteration. - */ -struct iwl_scan_offload_cmd { -	__le16 len; -	u8 scan_flags; -	u8 channel_count; -	__le16 quiet_time; -	__le16 quiet_plcp_th; -	__le16 good_CRC_th; -	__le16 rx_chain; -	__le32 max_out_time; -	__le32 suspend_time; -	/* RX_ON_FLAGS_API_S_VER_1 */ -	__le32 flags; -	__le32 filter_flags; -	struct iwl_tx_cmd tx_cmd[2]; -	/* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ -	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; -	__le32 scan_type; -	__le32 rep_count; -} __packed; - -enum iwl_scan_offload_channel_flags { -	IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE		= BIT(0), -	IWL_SCAN_OFFLOAD_CHANNEL_NARROW		= BIT(22), -	IWL_SCAN_OFFLOAD_CHANNEL_FULL		= BIT(24), -	IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL	= BIT(25), -}; - -/* 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 iterations on one channel. - * u8 active_dwell. - * u8 passive_dwell. - */ -#define IWL_SCAN_CHAN_SIZE 14 - -/** - * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S - * @scan_cmd:		scan command fixed part - * @data:		scan channel configuration and probe request frames - */ -struct iwl_scan_offload_cfg { -	struct iwl_scan_offload_cmd scan_cmd; -	u8 data[0]; -} __packed; - -/**   * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S   * @ssid:		MAC address to filter out   * @reported_rssi:	AP rssi reported to the host @@ -298,35 +198,6 @@ enum iwl_scan_ebs_status {  };  /** - * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 - * @last_schedule_line:		last schedule line executed (fast or regular) - * @last_schedule_iteration:	last scan iteration executed before scan abort - * @status:			enum iwl_scan_offload_compleate_status - * @ebs_status: last EBS status, see IWL_SCAN_EBS_* - */ -struct iwl_scan_offload_complete { -	u8 last_schedule_line; -	u8 last_schedule_iteration; -	u8 status; -	u8 ebs_status; -} __packed; - -/** - * iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1 - * @ssid_bitmap:	SSIDs indexes found in this iteration - * @client_bitmap:	clients that are active and wait for this notification - */ -struct iwl_sched_scan_results { -	__le16 ssid_bitmap; -	u8 client_bitmap; -	u8 reserved; -}; - -/* Unified LMAC scan API */ - -#define IWL_MVM_BASIC_PASSIVE_DWELL 110 - -/**   * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S   * @tx_flags: combination of TX_CMD_FLG_*   * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is @@ -550,18 +421,6 @@ struct iwl_periodic_scan_complete {  /* UMAC Scan API */ -/** - * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands - * @size:	size of the command (not including header) - * @reserved0:	for future use and alignment - * @ver:	API version number - */ -struct iwl_mvm_umac_cmd_hdr { -	__le16 size; -	u8 reserved0; -	u8 ver; -} __packed; -  /* The maximum of either of these cannot exceed 8, because we use an   * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h).   */ @@ -621,7 +480,6 @@ enum iwl_channel_flags {  /**   * struct iwl_scan_config - * @hdr: umac command header   * @flags:			enum scan_config_flags   * @tx_chains:			valid_tx antenna - ANT_* definitions   * @rx_chains:			valid_rx antenna - ANT_* definitions @@ -639,7 +497,6 @@ enum iwl_channel_flags {   * @channel_array:		default supported channels   */  struct iwl_scan_config { -	struct iwl_mvm_umac_cmd_hdr hdr;  	__le32 flags;  	__le32 tx_chains;  	__le32 rx_chains; @@ -660,7 +517,8 @@ struct iwl_scan_config {   * iwl_umac_scan_flags   *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request   *	can be preempted by other scan requests with higher priority. - *	The low priority scan is aborted. + *	The low priority scan will be resumed when the higher proirity scan is + *	completed.   *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver   *	when scan starts.   */ @@ -734,7 +592,6 @@ struct iwl_scan_req_umac_tail {  /**   * struct iwl_scan_req_umac - * @hdr: umac command header   * @flags: &enum iwl_umac_scan_flags   * @uid: scan id, &enum iwl_umac_scan_uid_offsets   * @ooc_priority: out of channel priority - &enum iwl_scan_priority @@ -753,7 +610,6 @@ struct iwl_scan_req_umac_tail {   *	&struct iwl_scan_req_umac_tail   */  struct iwl_scan_req_umac { -	struct iwl_mvm_umac_cmd_hdr hdr;  	__le32 flags;  	__le32 uid;  	__le32 ooc_priority; @@ -775,12 +631,10 @@ struct iwl_scan_req_umac {  /**   * struct iwl_umac_scan_abort - * @hdr: umac command header   * @uid: scan id, &enum iwl_umac_scan_uid_offsets   * @flags: reserved   */  struct iwl_umac_scan_abort { -	struct iwl_mvm_umac_cmd_hdr hdr;  	__le32 uid;  	__le32 flags;  } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 21dd5b771660..493a8bdfbc9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -366,8 +366,8 @@ struct iwl_mvm_rm_sta_cmd {   * ( MGMT_MCAST_KEY = 0x1f )   * @ctrl_flags: %iwl_sta_key_flag   * @IGTK: - * @K1: IGTK master key - * @K2: IGTK sub key + * @K1: unused + * @K2: unused   * @sta_id: station ID that support IGTK   * @key_id:   * @receive_seq_cnt: initial RSC/PN needed for replay check diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h new file mode 100644 index 000000000000..eed6271d01a3 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license.  When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <[email protected]> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *  * Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + *  * Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + *  * Neither the name Intel Corporation nor the names of its + *    contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __fw_api_tof_h__ +#define __fw_api_tof_h__ + +#include "fw-api.h" + +/* ToF sub-group command IDs */ +enum iwl_mvm_tof_sub_grp_ids { +	TOF_RANGE_REQ_CMD = 0x1, +	TOF_CONFIG_CMD = 0x2, +	TOF_RANGE_ABORT_CMD = 0x3, +	TOF_RANGE_REQ_EXT_CMD = 0x4, +	TOF_RESPONDER_CONFIG_CMD = 0x5, +	TOF_NW_INITIATED_RES_SEND_CMD = 0x6, +	TOF_NEIGHBOR_REPORT_REQ_CMD = 0x7, +	TOF_NEIGHBOR_REPORT_RSP_NOTIF = 0xFC, +	TOF_NW_INITIATED_REQ_RCVD_NOTIF = 0xFD, +	TOF_RANGE_RESPONSE_NOTIF = 0xFE, +	TOF_MCSI_DEBUG_NOTIF = 0xFB, +}; + +/** + * struct iwl_tof_config_cmd - ToF configuration + * @tof_disabled: 0 enabled, 1 - disabled + * @one_sided_disabled: 0 enabled, 1 - disabled + * @is_debug_mode: 1 debug mode, 0 - otherwise + * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise + */ +struct iwl_tof_config_cmd { +	__le32 sub_grp_cmd_id; +	u8 tof_disabled; +	u8 one_sided_disabled; +	u8 is_debug_mode; +	u8 is_buf_required; +} __packed; + +/** + * struct iwl_tof_responder_config_cmd - ToF AP mode (for debug) + * @burst_period: future use: (currently hard coded in the LMAC) + *		  The interval between two sequential bursts. + * @min_delta_ftm: future use: (currently hard coded in the LMAC) + *		   The minimum delay between two sequential FTM Responses + *		   in the same burst. + * @burst_duration: future use: (currently hard coded in the LMAC) + *		   The total time for all FTMs handshake in the same burst. + *		   Affect the time events duration in the LMAC. + * @num_of_burst_exp: future use: (currently hard coded in the LMAC) + *		   The number of bursts for the current ToF request. Affect + *		   the number of events allocations in the current iteration. + * @get_ch_est: for xVT only, NA for driver + * @abort_responder: when set to '1' - Responder will terminate its activity + *		     (all other fields in the command are ignored) + * @recv_sta_req_params: 1 - Responder will ignore the other Responder's + *			 params and use the recomended Initiator params. + *			 0 - otherwise + * @channel_num: current AP Channel + * @bandwidth: current AP Bandwidth: 0  20MHz, 1  40MHz, 2  80MHz + * @rate: current AP rate + * @ctrl_ch_position: coding of the control channel position relative to + *	     the center frequency. + *	     40MHz  0 below center, 1 above center + *	     80MHz  bits [0..1]: 0  the near 20MHz to the center, + *				 1  the far  20MHz to the center + *		    bit[2]  as above 40MHz + * @ftm_per_burst: FTMs per Burst + * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, + *		  '1' - we measure over the Initial FTM Response + * @asap_mode: ASAP / Non ASAP mode for the current WLS station + * @sta_id: index of the AP STA when in AP mode + * @tsf_timer_offset_msecs: The dictated time offset (mSec) from the AP's TSF + * @toa_offset: Artificial addition [0.1nsec] for the ToA - to be used for debug + *		purposes, simulating station movement by adding various values + *		to this field + * @bssid: Current AP BSSID + */ +struct iwl_tof_responder_config_cmd { +	__le32 sub_grp_cmd_id; +	__le16 burst_period; +	u8 min_delta_ftm; +	u8 burst_duration; +	u8 num_of_burst_exp; +	u8 get_ch_est; +	u8 abort_responder; +	u8 recv_sta_req_params; +	u8 channel_num; +	u8 bandwidth; +	u8 rate; +	u8 ctrl_ch_position; +	u8 ftm_per_burst; +	u8 ftm_resp_ts_avail; +	u8 asap_mode; +	u8 sta_id; +	__le16 tsf_timer_offset_msecs; +	__le16 toa_offset; +	u8 bssid[ETH_ALEN]; +} __packed; + +/** + * struct iwl_tof_range_request_ext_cmd - extended range req for WLS + * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @min_delta_ftm: Minimal time between two consecutive measurements, + *		   in units of 100us. 0 means no preference by station + * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended + *			value be sent to the AP + * @ftm_format_and_bw40M: FTM Channel Spacing/Format for 40MHz: recommended + *			value to be sent to the AP + * @ftm_format_and_bw80M: FTM Channel Spacing/Format for 80MHz: recommended + *			value to be sent to the AP + */ +struct iwl_tof_range_req_ext_cmd { +	__le32 sub_grp_cmd_id; +	__le16 tsf_timer_offset_msec; +	__le16 reserved; +	u8 min_delta_ftm; +	u8 ftm_format_and_bw20M; +	u8 ftm_format_and_bw40M; +	u8 ftm_format_and_bw80M; +} __packed; + +#define IWL_MVM_TOF_MAX_APS 21 + +/** + * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * @channel_num: Current AP Channel + * @bandwidth: Current AP Bandwidth: 0  20MHz, 1  40MHz, 2  80MHz + * @tsf_delta_direction: TSF relatively to the subject AP + * @ctrl_ch_position: Coding of the control channel position relative to the + *	     center frequency. + *	     40MHz  0 below center, 1 above center + *	     80MHz  bits [0..1]: 0  the near 20MHz to the center, + *				 1  the far  20MHz to the center + *		    bit[2]  as above 40MHz + * @bssid: AP's bss id + * @measure_type: Measurement type: 0 - two sided, 1 - One sided + * @num_of_bursts: Recommended value to be sent to the AP.  2s Exponent of the + *		   number of measurement iterations (min 2^0 = 1, max 2^14) + * @burst_period: Recommended value to be sent to the AP. Measurement + *		  periodicity In units of 100ms. ignored if num_of_bursts = 0 + * @samples_per_burst: 2-sided: the number of FTMs pairs in single Burst (1-31) + *		       1-sided: how many rts/cts pairs should be used per burst. + * @retries_per_sample: Max number of retries that the LMAC should send + *			in case of no replies by the AP. + * @tsf_delta: TSF Delta in units of microseconds. + *	       The difference between the AP TSF and the device local clock. + * @location_req: Location Request Bit[0] LCI should be sent in the FTMR + *			      Bit[1] Civic should be sent in the FTMR + * @asap_mode: 0 - non asap mode, 1 - asap mode (not relevant for one sided) + * @enable_dyn_ack: Enable Dynamic ACK BW. + *	    0  Initiator interact with regular AP + *	    1  Initiator interact with Responder machine: need to send the + *	    Initiator Acks with HT 40MHz / 80MHz, since the Responder should + *	    use it for its ch est measurement (this flag will be set when we + *	    configure the opposite machine to be Responder). + * @rssi: Last received value + *	  leagal values: -128-0 (0x7f). above 0x0 indicating an invalid value. + */ +struct iwl_tof_range_req_ap_entry { +	u8 channel_num; +	u8 bandwidth; +	u8 tsf_delta_direction; +	u8 ctrl_ch_position; +	u8 bssid[ETH_ALEN]; +	u8 measure_type; +	u8 num_of_bursts; +	__le16 burst_period; +	u8 samples_per_burst; +	u8 retries_per_sample; +	__le32 tsf_delta; +	u8 location_req; +	u8 asap_mode; +	u8 enable_dyn_ack; +	s8 rssi; +} __packed; + +/** + * enum iwl_tof_response_mode + * @IWL_MVM_TOF_RESPOSE_ASAP: report each AP measurement separately as soon as + *			      possible (not supported for this release) + * @IWL_MVM_TOF_RESPOSE_TIMEOUT: report all AP measurements as a batch upon + *				 timeout expiration + * @IWL_MVM_TOF_RESPOSE_COMPLETE: report all AP measurements as a batch at the + *				  earlier of: measurements completion / timeout + *				  expiration. + */ +enum iwl_tof_response_mode { +	IWL_MVM_TOF_RESPOSE_ASAP = 1, +	IWL_MVM_TOF_RESPOSE_TIMEOUT, +	IWL_MVM_TOF_RESPOSE_COMPLETE, +}; + +/** + * struct iwl_tof_range_req_cmd - start measurement cmd + * @request_id: A Token incremented per request. The same Token will be + *		sent back in the range response + * @initiator: 0- NW initiated,  1 - Client Initiated + * @one_sided_los_disable: '0'- run ML-Algo for both ToF/OneSided, + *			   '1' - run ML-Algo for ToF only + * @req_timeout: Requested timeout of the response in units of 100ms. + *	     This is equivalent to the session time configured to the + *	     LMAC in Initiator Request + * @report_policy: Supported partially for this release: For current release - + *		   the range report will be uploaded as a batch when ready or + *		   when the session is done (successfully / partially). + *		   one of iwl_tof_response_mode. + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @macaddr_random: '0' Use default source MAC address (i.e. p2_p), + *	            '1' Use MAC Address randomization according to the below + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + *		  Bits set to 1 shall be randomized by the UMAC + */ +struct iwl_tof_range_req_cmd { +	__le32 sub_grp_cmd_id; +	u8 request_id; +	u8 initiator; +	u8 one_sided_los_disable; +	u8 req_timeout; +	u8 report_policy; +	u8 los_det_disable; +	u8 num_of_ap; +	u8 macaddr_random; +	u8 macaddr_template[ETH_ALEN]; +	u8 macaddr_mask[ETH_ALEN]; +	struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +/** + * struct iwl_tof_gen_resp_cmd - generic ToF response + */ +struct iwl_tof_gen_resp_cmd { +	__le32 sub_grp_cmd_id; +	u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) + * @measure_status: current APs measurement status + * @measure_bw: Current AP Bandwidth: 0  20MHz, 1  40MHz, 2  80MHz + * @rtt: The Round Trip Time that took for the last measurement for + *	 current AP [nSec] + * @rtt_variance: The Variance of the RTT values measured for current AP + * @rtt_spread: The Difference between the maximum and the minimum RTT + *	       values measured for current AP in the current session [nsec] + * @rssi: RSSI as uploaded in the Channel Estimation notification + * @rssi_spread: The Difference between the maximum and the minimum RSSI values + *	        measured for current AP in the current session + * @range: Measured range [cm] + * @range_variance: Measured range variance [cm] + * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was + *	       uploaded by the LMAC + */ +struct iwl_tof_range_rsp_ap_entry_ntfy { +	u8 bssid[ETH_ALEN]; +	u8 measure_status; +	u8 measure_bw; +	__le32 rtt; +	__le32 rtt_variance; +	__le32 rtt_spread; +	s8 rssi; +	u8 rssi_spread; +	__le16 reserved; +	__le32 range; +	__le32 range_variance; +	__le32 timestamp; +} __packed; + +/** + * struct iwl_tof_range_rsp_ntfy - + * @request_id: A Token ID of the corresponding Range request + * @request_status: status of current measurement session + * @last_in_batch: reprot policy (when not all responses are uploaded at once) + * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + */ +struct iwl_tof_range_rsp_ntfy { +	u8 request_id; +	u8 request_status; +	u8 last_in_batch; +	u8 num_of_aps; +	struct iwl_tof_range_rsp_ap_entry_ntfy ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +#define IWL_MVM_TOF_MCSI_BUF_SIZE  (245) +/** + * struct iwl_tof_mcsi_notif - used for debug + * @token: token ID for the current session + * @role: '0' - initiator, '1' - responder + * @initiator_bssid: initiator machine + * @responder_bssid: responder machine + * @mcsi_buffer: debug data + */ +struct iwl_tof_mcsi_notif { +	u8 token; +	u8 role; +	__le16 reserved; +	u8 initiator_bssid[ETH_ALEN]; +	u8 responder_bssid[ETH_ALEN]; +	u8 mcsi_buffer[IWL_MVM_TOF_MCSI_BUF_SIZE * 4]; +} __packed; + +/** + * struct iwl_tof_neighbor_report_notif + * @bssid: BSSID of the AP which sent the report + * @request_token: same token as the corresponding request + * @status: + * @report_ie_len: the length of the response frame starting from the Element ID + * @data: the IEs + */ +struct iwl_tof_neighbor_report { +	u8 bssid[ETH_ALEN]; +	u8 request_token; +	u8 status; +	__le16 report_ie_len; +	u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_abort_cmd + * @request_id: corresponds to a range request + */ +struct iwl_tof_range_abort_cmd { +	__le32 sub_grp_cmd_id; +	u8 request_id; +	u8 reserved[3]; +} __packed; + +#endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 81c4ea3c6958..853698ab8b05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -124,6 +124,18 @@ enum iwl_tx_flags {  	TX_CMD_FLG_HCCA_CHUNK		= BIT(31)  }; /* TX_FLAGS_BITS_API_S_VER_1 */ +/** + * enum iwl_tx_pm_timeouts - pm timeout values in TX command + * @PM_FRAME_NONE: no need to suspend sleep mode + * @PM_FRAME_MGMT: fw suspend sleep mode for 100TU + * @PM_FRAME_ASSOC: fw suspend sleep mode for 10sec + */ +enum iwl_tx_pm_timeouts { +	PM_FRAME_NONE		= 0, +	PM_FRAME_MGMT		= 2, +	PM_FRAME_ASSOC		= 3, +}; +  /*   * TX command security control   */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 16e9ef49397f..4af7513adda2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -75,6 +75,7 @@  #include "fw-api-coex.h"  #include "fw-api-scan.h"  #include "fw-api-stats.h" +#include "fw-api-tof.h"  /* Tx queue numbers */  enum { @@ -119,6 +120,9 @@ enum {  	ADD_STA = 0x18,  	REMOVE_STA = 0x19, +	/* paging get item */ +	FW_GET_ITEM_CMD = 0x1a, +  	/* TX */  	TX_CMD = 0x1c,  	TXPATH_FLUSH = 0x1e, @@ -148,6 +152,9 @@ enum {  	LQ_CMD = 0x4e, +	/* paging block to FW cpu2 */ +	FW_PAGING_BLOCK_CMD = 0x4f, +  	/* Scan offload */  	SCAN_OFFLOAD_REQUEST_CMD = 0x51,  	SCAN_OFFLOAD_ABORT_CMD = 0x52, @@ -163,6 +170,10 @@ enum {  	CALIB_RES_NOTIF_PHY_DB = 0x6b,  	/* PHY_DB_CMD = 0x6c, */ +	/* ToF - 802.11mc FTM */ +	TOF_CMD = 0x10, +	TOF_NOTIFICATION = 0x11, +  	/* Power - legacy power table command */  	POWER_TABLE_CMD = 0x77,  	PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, @@ -365,6 +376,50 @@ struct iwl_nvm_access_cmd {  	u8 data[];  } __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ +#define NUM_OF_FW_PAGING_BLOCKS	33 /* 32 for data and 1 block for CSS */ + +/* + * struct iwl_fw_paging_cmd - paging layout + * + * (FW_PAGING_BLOCK_CMD = 0x4f) + * + * Send to FW the paging layout in the driver. + * + * @flags: various flags for the command + * @block_size: the block size in powers of 2 + * @block_num: number of blocks specified in the command. + * @device_phy_addr: virtual addresses from device side +*/ +struct iwl_fw_paging_cmd { +	__le32 flags; +	__le32 block_size; +	__le32 block_num; +	__le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ + +/* + * Fw items ID's + * + * @IWL_FW_ITEM_ID_PAGING: Address of the pages that the FW will upload + *	download + */ +enum iwl_fw_item_id { +	IWL_FW_ITEM_ID_PAGING = 3, +}; + +/* + * struct iwl_fw_get_item_cmd - get an item from the fw + */ +struct iwl_fw_get_item_cmd { +	__le32 item_id; +} __packed; /* FW_GET_ITEM_CMD_API_S_VER_1 */ + +struct iwl_fw_get_item_resp { +	__le32 item_id; +	__le32 item_byte_cnt; +	__le32 item_val; +} __packed; /* FW_GET_ITEM_RSP_S_VER_1 */ +  /**   * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD   * @offset: offset in bytes into the section @@ -1080,10 +1135,33 @@ struct iwl_rx_phy_info {  	__le16 frame_time;  } __packed; +/* + * TCP offload Rx assist info + * + * bits 0:3 - reserved + * bits 4:7 - MIC CRC length + * bits 8:12 - MAC header length + * bit 13 - Padding indication + * bit 14 - A-AMSDU indication + * bit 15 - Offload enabled + */ +enum iwl_csum_rx_assist_info { +	CSUM_RXA_RESERVED_MASK	= 0x000f, +	CSUM_RXA_MICSIZE_MASK	= 0x00f0, +	CSUM_RXA_HEADERLEN_MASK	= 0x1f00, +	CSUM_RXA_PADD		= BIT(13), +	CSUM_RXA_AMSDU		= BIT(14), +	CSUM_RXA_ENA		= BIT(15) +}; + +/** + * struct iwl_rx_mpdu_res_start - phy info + * @assist: see CSUM_RX_ASSIST_ above + */  struct iwl_rx_mpdu_res_start {  	__le16 byte_count; -	__le16 reserved; -} __packed; +	__le16 assist; +} __packed; /* _RX_MPDU_RES_START_API_S_VER_2 */  /**   * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags @@ -1136,6 +1214,8 @@ enum iwl_rx_phy_flags {   * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP:   * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT:   * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame + * @RX_MPDU_RES_STATUS_CSUM_DONE: checksum was done by the hw + * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors   * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK:   * @RX_MPDU_RES_STATUS_STA_ID_MSK:   * @RX_MPDU_RES_STATUS_RRF_KILL: @@ -1165,6 +1245,8 @@ enum iwl_mvm_rx_status {  	RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP		= BIT(13),  	RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT		= BIT(14),  	RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME		= BIT(15), +	RX_MPDU_RES_STATUS_CSUM_DONE			= BIT(16), +	RX_MPDU_RES_STATUS_CSUM_OK			= BIT(17),  	RX_MPDU_RES_STATUS_HASH_INDEX_MSK		= (0x3F0000),  	RX_MPDU_RES_STATUS_STA_ID_MSK			= (0x1f000000),  	RX_MPDU_RES_STATUS_RRF_KILL			= BIT(29), diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index eb10c5ee4a14..4a0ce83315bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -106,6 +106,306 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)  				    sizeof(tx_ant_cmd), &tx_ant_cmd);  } +static void iwl_free_fw_paging(struct iwl_mvm *mvm) +{ +	int i; + +	if (!mvm->fw_paging_db[0].fw_paging_block) +		return; + +	for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { +		if (!mvm->fw_paging_db[i].fw_paging_block) { +			IWL_DEBUG_FW(mvm, +				     "Paging: block %d already freed, continue to next page\n", +				     i); + +			continue; +		} + +		__free_pages(mvm->fw_paging_db[i].fw_paging_block, +			     get_order(mvm->fw_paging_db[i].fw_paging_size)); +	} +	kfree(mvm->trans->paging_download_buf); +	memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); +} + +static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) +{ +	int sec_idx, idx; +	u32 offset = 0; + +	/* +	 * find where is the paging image start point: +	 * if CPU2 exist and it's in paging format, then the image looks like: +	 * CPU1 sections (2 or more) +	 * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 +	 * CPU2 sections (not paged) +	 * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 +	 * non paged to CPU2 paging sec +	 * CPU2 paging CSS +	 * CPU2 paging image (including instruction and data) +	 */ +	for (sec_idx = 0; sec_idx < IWL_UCODE_SECTION_MAX; sec_idx++) { +		if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) { +			sec_idx++; +			break; +		} +	} + +	if (sec_idx >= IWL_UCODE_SECTION_MAX) { +		IWL_ERR(mvm, "driver didn't find paging image\n"); +		iwl_free_fw_paging(mvm); +		return -EINVAL; +	} + +	/* copy the CSS block to the dram */ +	IWL_DEBUG_FW(mvm, "Paging: load paging CSS to FW, sec = %d\n", +		     sec_idx); + +	memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block), +	       image->sec[sec_idx].data, +	       mvm->fw_paging_db[0].fw_paging_size); + +	IWL_DEBUG_FW(mvm, +		     "Paging: copied %d CSS bytes to first block\n", +		     mvm->fw_paging_db[0].fw_paging_size); + +	sec_idx++; + +	/* +	 * copy the paging blocks to the dram +	 * loop index start from 1 since that CSS block already copied to dram +	 * and CSS index is 0. +	 * loop stop at num_of_paging_blk since that last block is not full. +	 */ +	for (idx = 1; idx < mvm->num_of_paging_blk; idx++) { +		memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), +		       image->sec[sec_idx].data + offset, +		       mvm->fw_paging_db[idx].fw_paging_size); + +		IWL_DEBUG_FW(mvm, +			     "Paging: copied %d paging bytes to block %d\n", +			     mvm->fw_paging_db[idx].fw_paging_size, +			     idx); + +		offset += mvm->fw_paging_db[idx].fw_paging_size; +	} + +	/* copy the last paging block */ +	if (mvm->num_of_pages_in_last_blk > 0) { +		memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), +		       image->sec[sec_idx].data + offset, +		       FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk); + +		IWL_DEBUG_FW(mvm, +			     "Paging: copied %d pages in the last block %d\n", +			     mvm->num_of_pages_in_last_blk, idx); +	} + +	return 0; +} + +static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, +				   const struct fw_img *image) +{ +	struct page *block; +	dma_addr_t phys = 0; +	int blk_idx = 0; +	int order, num_of_pages; +	int dma_enabled; + +	if (mvm->fw_paging_db[0].fw_paging_block) +		return 0; + +	dma_enabled = is_device_dma_capable(mvm->trans->dev); + +	/* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */ +	BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE); + +	num_of_pages = image->paging_mem_size / FW_PAGING_SIZE; +	mvm->num_of_paging_blk = ((num_of_pages - 1) / +				    NUM_OF_PAGE_PER_GROUP) + 1; + +	mvm->num_of_pages_in_last_blk = +		num_of_pages - +		NUM_OF_PAGE_PER_GROUP * (mvm->num_of_paging_blk - 1); + +	IWL_DEBUG_FW(mvm, +		     "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", +		     mvm->num_of_paging_blk, +		     mvm->num_of_pages_in_last_blk); + +	/* allocate block of 4Kbytes for paging CSS */ +	order = get_order(FW_PAGING_SIZE); +	block = alloc_pages(GFP_KERNEL, order); +	if (!block) { +		/* free all the previous pages since we failed */ +		iwl_free_fw_paging(mvm); +		return -ENOMEM; +	} + +	mvm->fw_paging_db[blk_idx].fw_paging_block = block; +	mvm->fw_paging_db[blk_idx].fw_paging_size = FW_PAGING_SIZE; + +	if (dma_enabled) { +		phys = dma_map_page(mvm->trans->dev, block, 0, +				    PAGE_SIZE << order, DMA_BIDIRECTIONAL); +		if (dma_mapping_error(mvm->trans->dev, phys)) { +			/* +			 * free the previous pages and the current one since +			 * we failed to map_page. +			 */ +			iwl_free_fw_paging(mvm); +			return -ENOMEM; +		} +		mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; +	} else { +		mvm->fw_paging_db[blk_idx].fw_paging_phys = PAGING_ADDR_SIG | +			blk_idx << BLOCK_2_EXP_SIZE; +	} + +	IWL_DEBUG_FW(mvm, +		     "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n", +		     order); + +	/* +	 * allocate blocks in dram. +	 * since that CSS allocated in fw_paging_db[0] loop start from index 1 +	 */ +	for (blk_idx = 1; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { +		/* allocate block of PAGING_BLOCK_SIZE (32K) */ +		order = get_order(PAGING_BLOCK_SIZE); +		block = alloc_pages(GFP_KERNEL, order); +		if (!block) { +			/* free all the previous pages since we failed */ +			iwl_free_fw_paging(mvm); +			return -ENOMEM; +		} + +		mvm->fw_paging_db[blk_idx].fw_paging_block = block; +		mvm->fw_paging_db[blk_idx].fw_paging_size = PAGING_BLOCK_SIZE; + +		if (dma_enabled) { +			phys = dma_map_page(mvm->trans->dev, block, 0, +					    PAGE_SIZE << order, +					    DMA_BIDIRECTIONAL); +			if (dma_mapping_error(mvm->trans->dev, phys)) { +				/* +				 * free the previous pages and the current one +				 * since we failed to map_page. +				 */ +				iwl_free_fw_paging(mvm); +				return -ENOMEM; +			} +			mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; +		} else { +			mvm->fw_paging_db[blk_idx].fw_paging_phys = +				PAGING_ADDR_SIG | +				blk_idx << BLOCK_2_EXP_SIZE; +		} + +		IWL_DEBUG_FW(mvm, +			     "Paging: allocated 32K bytes (order %d) for firmware paging.\n", +			     order); +	} + +	return 0; +} + +static int iwl_save_fw_paging(struct iwl_mvm *mvm, +			      const struct fw_img *fw) +{ +	int ret; + +	ret = iwl_alloc_fw_paging_mem(mvm, fw); +	if (ret) +		return ret; + +	return iwl_fill_paging_mem(mvm, fw); +} + +/* send paging cmd to FW in case CPU2 has paging image */ +static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) +{ +	int blk_idx; +	__le32 dev_phy_addr; +	struct iwl_fw_paging_cmd fw_paging_cmd = { +		.flags = +			cpu_to_le32(PAGING_CMD_IS_SECURED | +				    PAGING_CMD_IS_ENABLED | +				    (mvm->num_of_pages_in_last_blk << +				    PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), +		.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), +		.block_num = cpu_to_le32(mvm->num_of_paging_blk), +	}; + +	/* loop for for all paging blocks + CSS block */ +	for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { +		dev_phy_addr = +			cpu_to_le32(mvm->fw_paging_db[blk_idx].fw_paging_phys >> +				    PAGE_2_EXP_SIZE); +		fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr; +	} + +	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, +						    IWL_ALWAYS_LONG_GROUP, 0), +				    0, sizeof(fw_paging_cmd), &fw_paging_cmd); +} + +/* + * Send paging item cmd to FW in case CPU2 has paging image + */ +static int iwl_trans_get_paging_item(struct iwl_mvm *mvm) +{ +	int ret; +	struct iwl_fw_get_item_cmd fw_get_item_cmd = { +		.item_id = cpu_to_le32(IWL_FW_ITEM_ID_PAGING), +	}; + +	struct iwl_fw_get_item_resp *item_resp; +	struct iwl_host_cmd cmd = { +		.id = iwl_cmd_id(FW_GET_ITEM_CMD, IWL_ALWAYS_LONG_GROUP, 0), +		.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, +		.data = { &fw_get_item_cmd, }, +	}; + +	cmd.len[0] = sizeof(struct iwl_fw_get_item_cmd); + +	ret = iwl_mvm_send_cmd(mvm, &cmd); +	if (ret) { +		IWL_ERR(mvm, +			"Paging: Failed to send FW_GET_ITEM_CMD cmd (err = %d)\n", +			ret); +		return ret; +	} + +	item_resp = (void *)((struct iwl_rx_packet *)cmd.resp_pkt)->data; +	if (item_resp->item_id != cpu_to_le32(IWL_FW_ITEM_ID_PAGING)) { +		IWL_ERR(mvm, +			"Paging: got wrong item in FW_GET_ITEM_CMD resp (item_id = %u)\n", +			le32_to_cpu(item_resp->item_id)); +		ret = -EIO; +		goto exit; +	} + +	mvm->trans->paging_download_buf = kzalloc(MAX_PAGING_IMAGE_SIZE, +						  GFP_KERNEL); +	if (!mvm->trans->paging_download_buf) { +		ret = -ENOMEM; +		goto exit; +	} +	mvm->trans->paging_req_addr = le32_to_cpu(item_resp->item_val); +	mvm->trans->paging_db = mvm->fw_paging_db; +	IWL_DEBUG_FW(mvm, +		     "Paging: got paging request address (paging_req_addr 0x%08x)\n", +		     mvm->trans->paging_req_addr); + +exit: +	iwl_free_resp(&cmd); + +	return ret; +} +  static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  			 struct iwl_rx_packet *pkt, void *data)  { @@ -213,7 +513,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	const struct fw_img *fw;  	int ret, i;  	enum iwl_ucode_type old_type = mvm->cur_ucode; -	static const u8 alive_cmd[] = { MVM_ALIVE }; +	static const u16 alive_cmd[] = { MVM_ALIVE };  	struct iwl_sf_region st_fwrd_space;  	if (ucode_type == IWL_UCODE_REGULAR && @@ -244,6 +544,11 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait,  				    MVM_UCODE_ALIVE_TIMEOUT);  	if (ret) { +		if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) +			IWL_ERR(mvm, +				"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", +				iwl_read_prph(mvm->trans, SB_CPU_1_STATUS), +				iwl_read_prph(mvm->trans, SB_CPU_2_STATUS));  		mvm->cur_ucode = old_type;  		return ret;  	} @@ -269,6 +574,40 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr);  	/* +	 * configure and operate fw paging mechanism. +	 * driver configures the paging flow only once, CPU2 paging image +	 * included in the IWL_UCODE_INIT image. +	 */ +	if (fw->paging_mem_size) { +		/* +		 * When dma is not enabled, the driver needs to copy / write +		 * the downloaded / uploaded page to / from the smem. +		 * This gets the location of the place were the pages are +		 * stored. +		 */ +		if (!is_device_dma_capable(mvm->trans->dev)) { +			ret = iwl_trans_get_paging_item(mvm); +			if (ret) { +				IWL_ERR(mvm, "failed to get FW paging item\n"); +				return ret; +			} +		} + +		ret = iwl_save_fw_paging(mvm, fw); +		if (ret) { +			IWL_ERR(mvm, "failed to save the FW paging image\n"); +			return ret; +		} + +		ret = iwl_send_paging_cmd(mvm, fw); +		if (ret) { +			IWL_ERR(mvm, "failed to send the paging cmd\n"); +			iwl_free_fw_paging(mvm); +			return ret; +		} +	} + +	/*  	 * Note: all the queues are enabled as part of the interface  	 * initialization, but in firmware restart scenarios they  	 * could be stopped, so wake them up. In firmware restart, @@ -314,7 +653,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)  int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)  {  	struct iwl_notification_wait calib_wait; -	static const u8 init_complete[] = { +	static const u16 init_complete[] = {  		INIT_COMPLETE_NOTIF,  		CALIB_RES_NOTIF_PHY_DB  	}; @@ -444,12 +783,6 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm)  		return;  	pkt = cmd.resp_pkt; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n", -			pkt->hdr.flags); -		goto exit; -	} -  	mem_cfg = (void *)pkt->data;  	mvm->shared_mem_cfg.shared_mem_addr = @@ -473,14 +806,18 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm)  		le32_to_cpu(mem_cfg->page_buff_size);  	IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); -exit:  	iwl_free_resp(&cmd);  }  int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,  				struct iwl_mvm_dump_desc *desc, -				unsigned int delay) +				struct iwl_fw_dbg_trigger_tlv *trigger)  { +	unsigned int delay = 0; + +	if (trigger) +		delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); +  	if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))  		return -EBUSY; @@ -491,6 +828,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,  		 le32_to_cpu(desc->trig_desc.type));  	mvm->fw_dump_desc = desc; +	mvm->fw_dump_trig = trigger;  	queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); @@ -498,7 +836,8 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,  }  int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, -			   const char *str, size_t len, unsigned int delay) +			   const char *str, size_t len, +			   struct iwl_fw_dbg_trigger_tlv *trigger)  {  	struct iwl_mvm_dump_desc *desc; @@ -510,14 +849,13 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,  	desc->trig_desc.type = cpu_to_le32(trig);  	memcpy(desc->trig_desc.data, str, len); -	return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay); +	return iwl_mvm_fw_dbg_collect_desc(mvm, desc, trigger);  }  int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,  				struct iwl_fw_dbg_trigger_tlv *trigger,  				const char *fmt, ...)  { -	unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));  	u16 occurrences = le16_to_cpu(trigger->occurrences);  	int ret, len = 0;  	char buf[64]; @@ -541,8 +879,9 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,  		len = strlen(buf) + 1;  	} -	ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, -				     len, delay); +	ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, len, +				     trigger); +  	if (ret)  		return ret; @@ -676,8 +1015,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  		goto error;  	} -	if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) -		iwl_mvm_get_shared_mem_conf(mvm); +	iwl_mvm_get_shared_mem_conf(mvm);  	ret = iwl_mvm_sf_update(mvm, NULL, false);  	if (ret) @@ -760,6 +1098,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  			goto error;  	} +	if (iwl_mvm_is_csum_supported(mvm) && +	    mvm->cfg->features & NETIF_F_RXCSUM) +		iwl_trans_write_prph(mvm->trans, RX_EN_CSUM, 0x3); +  	/* allow FW/transport low power modes if not during restart */  	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))  		iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -815,9 +1157,8 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)  	return ret;  } -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd) +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -828,13 +1169,10 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,  			  (flags & SW_CARD_DISABLED) ? "Kill" : "On",  			  (flags & CT_KILL_CARD_DISABLED) ?  			  "Reached" : "Not reached"); - -	return 0;  } -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, -			    struct iwl_rx_cmd_buffer *rxb, -			    struct iwl_device_cmd *cmd) +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, +			     struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; @@ -845,5 +1183,4 @@ int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,  		       le32_to_cpu(mfuart_notif->external_ver),  		       le32_to_cpu(mfuart_notif->status),  		       le32_to_cpu(mfuart_notif->duration)); -	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 1812dd018af2..3424315dd876 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1312,9 +1312,8 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,  	}  } -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, -			    struct iwl_rx_cmd_buffer *rxb, -			    struct iwl_device_cmd *cmd) +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, +			     struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; @@ -1365,8 +1364,6 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  			RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);  		}  	} - -	return 0;  }  static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, @@ -1415,9 +1412,8 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,  		iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL);  } -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd) +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, +				     struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_missed_beacons_notif *mb = (void *)pkt->data; @@ -1434,5 +1430,4 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,  						   IEEE80211_IFACE_ITER_NORMAL,  						   iwl_mvm_beacon_loss_iterator,  						   mb); -	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index dfdab38e2d4a..aa8c2b7f23c7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -641,6 +641,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  			IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) {  		IWL_DEBUG_TDLS(mvm, "TDLS supported\n");  		hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; +		ieee80211_hw_set(hw, TDLS_WIDER_BW);  	}  	if (fw_has_capa(&mvm->fw->ucode_capa, @@ -649,6 +650,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;  	} +	hw->netdev_features |= mvm->cfg->features; +	if (!iwl_mvm_is_csum_supported(mvm)) +		hw->netdev_features &= ~NETIF_F_RXCSUM; +  	ret = ieee80211_register_hw(mvm->hw);  	if (ret)  		iwl_mvm_leds_exit(mvm); @@ -1120,9 +1125,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  	u32 file_len, fifo_data_len = 0;  	u32 smem_len = mvm->cfg->smem_len;  	u32 sram2_len = mvm->cfg->dccm2_len; +	bool monitor_dump_only = false;  	lockdep_assert_held(&mvm->mutex); +	if (mvm->fw_dump_trig && +	    mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) +		monitor_dump_only = true; +  	fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);  	if (!fw_error_dump)  		return; @@ -1174,6 +1184,20 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  		   fifo_data_len +  		   sizeof(*dump_info); +	/* Make room for the SMEM, if it exists */ +	if (smem_len) +		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; + +	/* Make room for the secondary SRAM, if it exists */ +	if (sram2_len) +		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; + +	/* If we only want a monitor dump, reset the file length */ +	if (monitor_dump_only) { +		file_len = sizeof(*dump_file) + sizeof(*dump_data) + +			   sizeof(*dump_info); +	} +  	/*  	 * In 8000 HW family B-step include the ICCM (which resides separately)  	 */ @@ -1186,14 +1210,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  		file_len += sizeof(*dump_data) + sizeof(*dump_trig) +  			    mvm->fw_dump_desc->len; -	/* Make room for the SMEM, if it exists */ -	if (smem_len) -		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; - -	/* Make room for the secondary SRAM, if it exists */ -	if (sram2_len) -		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; -  	dump_file = vzalloc(file_len);  	if (!dump_file) {  		kfree(fw_error_dump); @@ -1239,6 +1255,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  		dump_data = iwl_fw_error_next_data(dump_data);  	} +	/* In case we only want monitor dump, skip to dump trasport data */ +	if (monitor_dump_only) +		goto dump_trans_data; +  	dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);  	dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));  	dump_mem = (void *)dump_data->data; @@ -1282,7 +1302,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  					 dump_mem->data, IWL8260_ICCM_LEN);  	} -	fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); +dump_trans_data: +	fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, +						       mvm->fw_dump_trig);  	fw_error_dump->op_mode_len = file_len;  	if (fw_error_dump->trans_ptr)  		file_len += fw_error_dump->trans_ptr->len; @@ -1291,6 +1313,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  	dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,  		      GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); +	mvm->fw_dump_trig = NULL;  	clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);  } @@ -1433,22 +1456,9 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)  static void iwl_mvm_resume_complete(struct iwl_mvm *mvm)  { -	bool exit_now; -  	if (!iwl_mvm_is_d0i3_supported(mvm))  		return; -	mutex_lock(&mvm->d0i3_suspend_mutex); -	__clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); -	exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, -					&mvm->d0i3_suspend_flags); -	mutex_unlock(&mvm->d0i3_suspend_mutex); - -	if (exit_now) { -		IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); -		_iwl_mvm_exit_d0i3(mvm); -	} -  	if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND)  		if (!wait_event_timeout(mvm->d0i3_exit_waitq,  					!test_bit(IWL_MVM_STATUS_IN_D0I3, @@ -1585,20 +1595,23 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  				s16 tx_power)  {  	struct iwl_dev_tx_power_cmd cmd = { -		.set_mode = 0, -		.mac_context_id = +		.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), +		.v2.mac_context_id =  			cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), -		.pwr_restriction = cpu_to_le16(8 * tx_power), +		.v2.pwr_restriction = cpu_to_le16(8 * tx_power),  	}; +	int len = sizeof(cmd);  	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_DEV))  		return iwl_mvm_set_tx_power_old(mvm, vif, tx_power);  	if (tx_power == IWL_DEFAULT_MAX_TX_POWER) -		cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); +		cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); -	return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, -				    sizeof(cmd), &cmd); +	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN)) +		len = sizeof(cmd.v2); + +	return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);  }  static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1664,6 +1677,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  		goto out_unlock;  	} +	mvmvif->features |= hw->netdev_features; +  	ret = iwl_mvm_mac_ctxt_add(mvm, vif);  	if (ret)  		goto out_release; @@ -2880,10 +2895,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  	switch (key->cipher) {  	case WLAN_CIPHER_SUITE_TKIP:  		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; -		/* fall-through */ -	case WLAN_CIPHER_SUITE_CCMP:  		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;  		break; +	case WLAN_CIPHER_SUITE_CCMP: +		key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; +		break;  	case WLAN_CIPHER_SUITE_AES_CMAC:  		WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));  		break; @@ -3025,7 +3041,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,  	int res, time_reg = DEVICE_SYSTEM_TIME_REG;  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; -	static const u8 time_event_response[] = { HOT_SPOT_CMD }; +	static const u16 time_event_response[] = { HOT_SPOT_CMD };  	struct iwl_notification_wait wait_time_event;  	struct iwl_hs20_roc_req aux_roc_req = {  		.action = cpu_to_le32(FW_CTXT_ACTION_ADD), diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825..b95a07ec9e36 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,6 +80,7 @@  #include "sta.h"  #include "fw-api.h"  #include "constants.h" +#include "tof.h"  #define IWL_INVALID_MAC80211_QUEUE	0xff  #define IWL_MVM_MAX_ADDRESSES		5 @@ -122,8 +123,7 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops;   *	be up'ed after the INIT fw asserted. This is useful to be able to use   *	proprietary tools over testmode to debug the INIT fw.   * @tfd_q_hang_detect: enabled the detection of hung transmit queues - * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power - *	Save)-2(default), LP(Low Power)-3 + * @power_scheme: one of enum iwl_power_scheme   */  struct iwl_mvm_mod_params {  	bool init_dbg; @@ -357,6 +357,7 @@ struct iwl_mvm_vif_bf_data {   *	# of received beacons accumulated over FW restart, and the current   *	average signal of beacons retrieved from the firmware   * @csa_failed: CSA failed to schedule time event, report an error later + * @features: hw features active for this vif   */  struct iwl_mvm_vif {  	struct iwl_mvm *mvm; @@ -437,6 +438,9 @@ struct iwl_mvm_vif {  	/* Indicates that CSA countdown may be started */  	bool csa_countdown;  	bool csa_failed; + +	/* TCP Checksum Offload */ +	netdev_features_t features;  };  static inline struct iwl_mvm_vif * @@ -606,6 +610,11 @@ struct iwl_mvm {  	/* NVM sections */  	struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; +	/* Paging section */ +	struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS]; +	u16 num_of_paging_blk; +	u16 num_of_pages_in_last_blk; +  	/* EEPROM MAC addresses */  	struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; @@ -686,6 +695,7 @@ struct iwl_mvm {  	 * can hold 16 keys at most. Reflect this fact.  	 */  	unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; +	u8 fw_key_deleted[STA_KEY_MAX_NUM];  	/* references taken by the driver and spinlock protecting them */  	spinlock_t refs_lock; @@ -698,6 +708,7 @@ struct iwl_mvm {  	u8 fw_dbg_conf;  	struct delayed_work fw_dump_wk;  	struct iwl_mvm_dump_desc *fw_dump_desc; +	struct iwl_fw_dbg_trigger_tlv *fw_dump_trig;  #ifdef CONFIG_IWLWIFI_LEDS  	struct led_classdev led; @@ -822,6 +833,7 @@ struct iwl_mvm {  	struct iwl_mvm_shared_mem_cfg shared_mem_cfg;  	u32 ciphers[6]; +	struct iwl_mvm_tof_data tof_data;  };  /* Extract MVM priv from op_mode and _hw */ @@ -941,6 +953,12 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)  		IWL_MVM_BT_COEX_RRC;  } +static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm) +{ +	return fw_has_capa(&mvm->fw->ucode_capa, +			   IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); +} +  extern const u8 iwl_mvm_ac_to_tx_fifo[];  struct iwl_rate_info { @@ -974,12 +992,12 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);  /* Tx / Host Commands */  int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,  				  struct iwl_host_cmd *cmd); -int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,  				      u32 flags, u16 len, const void *data);  int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,  					 struct iwl_host_cmd *cmd,  					 u32 *status); -int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id,  					     u16 len, const void *data,  					     u32 *status);  int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, @@ -988,10 +1006,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);  void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  			struct iwl_tx_cmd *tx_cmd,  			struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, -			       struct ieee80211_tx_info *info, -			       struct iwl_tx_cmd *tx_cmd, -			       struct sk_buff *skb_frag);  void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,  			    struct ieee80211_tx_info *info,  			    struct ieee80211_sta *sta, __le16 fc); @@ -1003,6 +1017,17 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }  int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);  void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); +static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, +					   struct iwl_tx_cmd *tx_cmd) +{ +	struct ieee80211_key_conf *keyconf = info->control.hw_key; + +	tx_cmd->sec_ctl = TX_CMD_SEC_CCM; +	memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); +	if (info->flags & IEEE80211_TX_CTL_AMPDU) +		tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); +} +  static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)  {  	flush_work(&mvm->async_handlers_wk); @@ -1011,9 +1036,8 @@ static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm)  /* Statistics */  void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,  				  struct iwl_rx_packet *pkt); -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, -			  struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd); +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, +			   struct iwl_rx_cmd_buffer *rxb);  int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear);  void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); @@ -1059,27 +1083,20 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,   * FW notifications / CMD responses handlers   * Convention: iwl_mvm_rx_<NAME OF THE CMD>   */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd); -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		       struct iwl_device_cmd *cmd); -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		      struct iwl_device_cmd *cmd); -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			struct iwl_device_cmd *cmd); -int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, -				  struct iwl_rx_cmd_buffer *rxb, -				  struct iwl_device_cmd *cmd); -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd); -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd); -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			    struct iwl_device_cmd *cmd); -int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd); +void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, +			struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, +				   struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, +			     struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, +				     struct iwl_rx_cmd_buffer *rxb);  /* MVM PHY */  int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, @@ -1106,12 +1123,10 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);  u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);  int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,  				    struct ieee80211_vif *vif); -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, -			    struct iwl_rx_cmd_buffer *rxb, -			    struct iwl_device_cmd *cmd); -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, -				    struct iwl_rx_cmd_buffer *rxb, -				    struct iwl_device_cmd *cmd); +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, +			     struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, +				     struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,  				    struct ieee80211_vif *vif);  unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, @@ -1135,29 +1150,24 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);  void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);  /* Scheduled scan */ -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, -					struct iwl_rx_cmd_buffer *rxb, -					struct iwl_device_cmd *cmd); -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd); +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, +					 struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb);  int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  			     struct ieee80211_vif *vif,  			     struct cfg80211_sched_scan_request *req,  			     struct ieee80211_scan_ies *ies,  			     int type); -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd); +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb);  /* UMAC scan */  int iwl_mvm_config_scan(struct iwl_mvm *mvm); -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, -					struct iwl_rx_cmd_buffer *rxb, -					struct iwl_device_cmd *cmd); -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd); +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, +					 struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb);  /* MVM debugfs */  #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1196,9 +1206,8 @@ int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  				 char *buf, int bufsz);  void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd); +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb);  #ifdef CONFIG_IWLWIFI_LEDS  int iwl_mvm_leds_init(struct iwl_mvm *mvm); @@ -1254,9 +1263,8 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);  /* BT Coex */  int iwl_send_bt_init_conf(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, -			     struct iwl_rx_cmd_buffer *rxb, -			     struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, +			      struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			   enum ieee80211_rssi_event_data);  void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); @@ -1274,9 +1282,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,  bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm);  void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm);  int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, -				 struct iwl_rx_cmd_buffer *rxb, -				 struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, +				  struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  			       enum ieee80211_rssi_event_data);  u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, @@ -1285,9 +1292,8 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,  					 struct ieee80211_sta *sta);  bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,  					enum ieee80211_band band); -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, -				      struct iwl_rx_cmd_buffer *rxb, -				      struct iwl_device_cmd *cmd); +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, +				       struct iwl_rx_cmd_buffer *rxb);  /* beacon filtering */  #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1376,9 +1382,8 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,  /* Thermal management and CT-kill */  void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);  void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, -		       struct iwl_rx_cmd_buffer *rxb, -		       struct iwl_device_cmd *cmd); +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, +			struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_tt_handler(struct iwl_mvm *mvm);  void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);  void iwl_mvm_tt_exit(struct iwl_mvm *mvm); @@ -1390,9 +1395,8 @@ struct iwl_mcc_update_resp *  iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,  		   enum iwl_mcc_source src_id);  int iwl_mvm_init_mcc(struct iwl_mvm *mvm); -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, -			       struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd); +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, +				struct iwl_rx_cmd_buffer *rxb);  struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,  						  const char *alpha2,  						  enum iwl_mcc_source src_id, @@ -1431,8 +1435,7 @@ void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,  void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,  					struct ieee80211_vif *vif,  					struct ieee80211_sta *sta); -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd); +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);  void iwl_mvm_tdls_ch_switch_work(struct work_struct *work);  struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); @@ -1442,10 +1445,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);  int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);  int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, -			   const char *str, size_t len, unsigned int delay); +			   const char *str, size_t len, +			   struct iwl_fw_dbg_trigger_tlv *trigger);  int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,  				struct iwl_mvm_dump_desc *desc, -				unsigned int delay); +				struct iwl_fw_dbg_trigger_tlv *trigger);  void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);  int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,  				struct iwl_fw_dbg_trigger_tlv *trigger, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2a6be350704a..328187da7541 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -139,12 +139,6 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,  		return ret;  	pkt = cmd.resp_pkt; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n", -			pkt->hdr.flags); -		ret = -EIO; -		goto exit; -	}  	/* Extract NVM response */  	nvm_resp = (void *)pkt->data; @@ -652,12 +646,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,  		return ERR_PTR(ret);  	pkt = cmd.resp_pkt; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n", -			pkt->hdr.flags); -		ret = -EIO; -		goto exit; -	}  	/* Extract MCC response */  	mcc_resp = (void *)pkt->data; @@ -839,9 +827,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)  	return retval;  } -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, -			       struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, +				struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mcc_chub_notif *notif = (void *)pkt->data; @@ -852,7 +839,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,  	lockdep_assert_held(&mvm->mutex);  	if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) -		return 0; +		return;  	mcc[0] = notif->mcc >> 8;  	mcc[1] = notif->mcc & 0xff; @@ -864,10 +851,8 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,  		      mcc, src);  	regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL);  	if (IS_ERR_OR_NULL(regd)) -		return 0; +		return;  	regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);  	kfree(regd); - -	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffd..a37de3f410a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -201,14 +201,15 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  }  struct iwl_rx_handlers { -	u8 cmd_id; +	u16 cmd_id;  	bool async; -	int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		  struct iwl_device_cmd *cmd); +	void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);  };  #define RX_HANDLER(_cmd_id, _fn, _async)	\  	{ .cmd_id = _cmd_id , .fn = _fn , .async = _async } +#define RX_HANDLER_GRP(_grp, _cmd, _fn, _async)	\ +	{ .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .async = _async }  /*   * Handlers for fw notifications @@ -221,7 +222,6 @@ struct iwl_rx_handlers {   * called from a worker with mvm->mutex held.   */  static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { -	RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false),  	RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),  	RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),  	RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), @@ -261,12 +261,14 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {  	RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,  		   true),  	RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), +	RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true),  };  #undef RX_HANDLER +#undef RX_HANDLER_GRP  #define CMD(x) [x] = #x -static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { +static const char *const iwl_mvm_cmd_strings[REPLY_MAX + 1] = {  	CMD(MVM_ALIVE),  	CMD(REPLY_ERROR),  	CMD(INIT_COMPLETE_NOTIF), @@ -286,8 +288,10 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {  	CMD(PHY_CONFIGURATION_CMD),  	CMD(CALIB_RES_NOTIF_PHY_DB),  	CMD(SET_CALIB_DEFAULT_CMD), +	CMD(FW_PAGING_BLOCK_CMD),  	CMD(ADD_STA_KEY),  	CMD(ADD_STA), +	CMD(FW_GET_ITEM_CMD),  	CMD(REMOVE_STA),  	CMD(LQ_CMD),  	CMD(SCAN_OFFLOAD_CONFIG_CMD), @@ -470,6 +474,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	trans_cfg.no_reclaim_cmds = no_reclaim_cmds;  	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);  	trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; +	trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa, +					       IWL_UCODE_TLV_API_WIDE_CMD_HDR);  	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)  		trans_cfg.bc_table_dword = true; @@ -576,6 +582,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	/* rpm starts with a taken ref. only set the appropriate bit here. */  	mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; +	iwl_mvm_tof_init(mvm); +  	return op_mode;   out_unregister: @@ -623,14 +631,15 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)  	for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)  		kfree(mvm->nvm_sections[i].data); +	iwl_mvm_tof_clean(mvm); +  	ieee80211_free_hw(mvm->hw);  }  struct iwl_async_handler_entry {  	struct list_head list;  	struct iwl_rx_cmd_buffer rxb; -	int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		  struct iwl_device_cmd *cmd); +	void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);  };  void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) @@ -667,9 +676,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)  	spin_unlock_bh(&mvm->async_handlers_lock);  	list_for_each_entry_safe(entry, tmp, &local_list, list) { -		if (entry->fn(mvm, &entry->rxb, NULL)) -			IWL_WARN(mvm, -				 "returned value from ASYNC handlers are ignored\n"); +		entry->fn(mvm, &entry->rxb);  		iwl_free_rxb(&entry->rxb);  		list_del(&entry->list);  		kfree(entry); @@ -698,24 +705,30 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,  		if (!cmds_trig->cmds[i].cmd_id)  			break; -		if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd) +		if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd || +		    cmds_trig->cmds[i].group_id != pkt->hdr.group_id)  			continue;  		iwl_mvm_fw_dbg_collect_trig(mvm, trig, -					    "CMD 0x%02x received", -					    pkt->hdr.cmd); +					    "CMD 0x%02x.%02x received", +					    pkt->hdr.group_id, pkt->hdr.cmd);  		break;  	}  } -static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, -			       struct iwl_rx_cmd_buffer *rxb, -			       struct iwl_device_cmd *cmd) +static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, +				struct napi_struct *napi, +				struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);  	u8 i; +	if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { +		iwl_mvm_rx_rx_mpdu(mvm, napi, rxb); +		return; +	} +  	iwl_mvm_rx_check_trigger(mvm, pkt);  	/* @@ -729,16 +742,18 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,  		const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i];  		struct iwl_async_handler_entry *entry; -		if (rx_h->cmd_id != pkt->hdr.cmd) +		if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd))  			continue; -		if (!rx_h->async) -			return rx_h->fn(mvm, rxb, cmd); +		if (!rx_h->async) { +			rx_h->fn(mvm, rxb); +			return; +		}  		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);  		/* we can't do much... */  		if (!entry) -			return 0; +			return;  		entry->rxb._page = rxb_steal_page(rxb);  		entry->rxb._offset = rxb->_offset; @@ -750,8 +765,6 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,  		schedule_work(&mvm->async_handlers_wk);  		break;  	} - -	return 0;  }  static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) @@ -903,7 +916,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)  	 * can't recover this since we're already half suspended.  	 */  	if (!mvm->restart_fw && fw_error) { -		iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, 0); +		iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, +					    NULL);  	} else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,  				    &mvm->status)) {  		struct iwl_mvm_reprobe *reprobe; @@ -1100,9 +1114,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)  	IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); -	/* make sure we have no running tx while configuring the qos */  	set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); -	synchronize_net();  	/*  	 * iwl_mvm_ref_sync takes a reference before checking the flag. @@ -1130,6 +1142,9 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)  		mvm->d0i3_offloading = false;  	} +	/* make sure we have no running tx while configuring the seqno */ +	synchronize_net(); +  	iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data);  	ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags,  				   sizeof(wowlan_config_cmd), @@ -1156,15 +1171,25 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac,  	iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags);  } -static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, -					 struct ieee80211_vif *vif) +struct iwl_mvm_wakeup_reason_iter_data { +	struct iwl_mvm *mvm; +	u32 wakeup_reasons; +}; + +static void iwl_mvm_d0i3_wakeup_reason_iter(void *_data, u8 *mac, +					    struct ieee80211_vif *vif)  { -	struct iwl_mvm *mvm = data; +	struct iwl_mvm_wakeup_reason_iter_data *data = _data;  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && -	    mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) -		iwl_mvm_connection_loss(mvm, vif, "D0i3"); +	    data->mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) { +		if (data->wakeup_reasons & +		    IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH) +			iwl_mvm_connection_loss(data->mvm, vif, "D0i3"); +		else +			ieee80211_beacon_loss(vif); +	}  }  void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) @@ -1232,7 +1257,7 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)  	};  	struct iwl_wowlan_status *status;  	int ret; -	u32 disconnection_reasons, wakeup_reasons; +	u32 handled_reasons, wakeup_reasons;  	__le16 *qos_seq = NULL;  	mutex_lock(&mvm->mutex); @@ -1249,13 +1274,18 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)  	IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); -	disconnection_reasons = -		IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | -		IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; -	if (wakeup_reasons & disconnection_reasons) +	handled_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | +				IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; +	if (wakeup_reasons & handled_reasons) { +		struct iwl_mvm_wakeup_reason_iter_data data = { +			.mvm = mvm, +			.wakeup_reasons = wakeup_reasons, +		}; +  		ieee80211_iterate_active_interfaces(  			mvm->hw, IEEE80211_IFACE_ITER_NORMAL, -			iwl_mvm_d0i3_disconnect_iter, mvm); +			iwl_mvm_d0i3_wakeup_reason_iter, &data); +	}  out:  	iwl_mvm_d0i3_enable_tx(mvm, qos_seq); @@ -1308,17 +1338,6 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)  	return _iwl_mvm_exit_d0i3(mvm);  } -static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, -			     struct napi_struct *napi, -			     struct net_device *napi_dev, -			     int (*poll)(struct napi_struct *, int), -			     int weight) -{ -	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - -	ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight); -} -  static const struct iwl_op_mode_ops iwl_mvm_ops = {  	.start = iwl_op_mode_mvm_start,  	.stop = iwl_op_mode_mvm_stop, @@ -1332,5 +1351,4 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = {  	.nic_config = iwl_mvm_nic_config,  	.enter_d0i3 = iwl_mvm_enter_d0i3,  	.exit_d0i3 = iwl_mvm_exit_d0i3, -	.napi_add = iwl_mvm_napi_add,  }; diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d2c6ba9d326b..4645877882a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -112,11 +112,12 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,  static  void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm,  					  struct ieee80211_vif *vif, -					  struct iwl_beacon_filter_cmd *cmd) +					  struct iwl_beacon_filter_cmd *cmd, +					  bool d0i3)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -	if (vif->bss_conf.cqm_rssi_thold) { +	if (vif->bss_conf.cqm_rssi_thold && !d0i3) {  		cmd->bf_energy_delta =  			cpu_to_le32(vif->bss_conf.cqm_rssi_hyst);  		/* fw uses an absolute value for this */ @@ -287,27 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,  	return true;  } -static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) -{ -	int numerator; -	int dtim_interval = dtimper * bi; - -	if (WARN_ON(!dtim_interval)) -		return 0; - -	if (dtimper == 1) { -		if (bi > 100) -			numerator = 408; -		else -			numerator = 510; -	} else if (dtimper < 10) { -		numerator = 612; -	} else { -		return 0; -	} -	return max(1, (numerator / dtim_interval)); -} -  static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)  {  	struct ieee80211_chanctx_conf *chanctx_conf; @@ -357,8 +337,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,  	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); -	if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || -	    !mvmvif->pm_enabled) +	if (!vif->bss_conf.ps || !mvmvif->pm_enabled || +	    (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p))  		return;  	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -377,11 +357,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,  	if (!radar_detect && (dtimper < 10) &&  	    (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP ||  	     mvm->cur_ucode == IWL_UCODE_WOWLAN)) { -		cmd->skip_dtim_periods = -			iwl_mvm_power_get_skip_over_dtim(dtimper, bi); -		if (cmd->skip_dtim_periods) -			cmd->flags |= -				cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); +		cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); +		cmd->skip_dtim_periods = 3;  	}  	if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { @@ -509,9 +486,8 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,  		       ETH_ALEN);  } -int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd) +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data; @@ -520,8 +496,6 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,  	ieee80211_iterate_active_interfaces_atomic(  		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,  		iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id); - -	return 0;  }  struct iwl_power_vifs { @@ -810,7 +784,7 @@ static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,  	    vif->type != NL80211_IFTYPE_STATION || vif->p2p)  		return 0; -	iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); +	iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd, d0i3);  	if (!d0i3)  		iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);  	ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index daff1d0a8e4a..5ae9c8aa868f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -177,7 +177,8 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  	mvmsta = iwl_mvm_sta_from_mac80211(sta);  	mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); -	if (iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p) +	if (IWL_MVM_RS_DISABLE_P2P_MIMO && +	    iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p)  		return false;  	if (mvm->nvm_data->sku_cap_mimo_disabled) @@ -2403,7 +2404,7 @@ struct rs_init_rate_info {  	u8 rate_idx;  }; -static const struct rs_init_rate_info rs_init_rates_24ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_24ghz_legacy[] = {  	{ -60, IWL_RATE_54M_INDEX },  	{ -64, IWL_RATE_48M_INDEX },  	{ -68, IWL_RATE_36M_INDEX }, @@ -2416,7 +2417,7 @@ static const struct rs_init_rate_info rs_init_rates_24ghz[] = {  	{ S8_MIN, IWL_RATE_1M_INDEX },  }; -static const struct rs_init_rate_info rs_init_rates_5ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_5ghz_legacy[] = {  	{ -60, IWL_RATE_54M_INDEX },  	{ -64, IWL_RATE_48M_INDEX },  	{ -72, IWL_RATE_36M_INDEX }, @@ -2427,6 +2428,124 @@ static const struct rs_init_rate_info rs_init_rates_5ghz[] = {  	{ S8_MIN, IWL_RATE_6M_INDEX },  }; +static const struct rs_init_rate_info rs_optimal_rates_ht[] = { +	{ -60, IWL_RATE_MCS_7_INDEX }, +	{ -64, IWL_RATE_MCS_6_INDEX }, +	{ -68, IWL_RATE_MCS_5_INDEX }, +	{ -72, IWL_RATE_MCS_4_INDEX }, +	{ -80, IWL_RATE_MCS_3_INDEX }, +	{ -84, IWL_RATE_MCS_2_INDEX }, +	{ -85, IWL_RATE_MCS_1_INDEX }, +	{ S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { +	{ -60, IWL_RATE_MCS_8_INDEX }, +	{ -64, IWL_RATE_MCS_7_INDEX }, +	{ -68, IWL_RATE_MCS_6_INDEX }, +	{ -72, IWL_RATE_MCS_5_INDEX }, +	{ -80, IWL_RATE_MCS_4_INDEX }, +	{ -84, IWL_RATE_MCS_3_INDEX }, +	{ -85, IWL_RATE_MCS_2_INDEX }, +	{ -87, IWL_RATE_MCS_1_INDEX }, +	{ S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { +	{ -60, IWL_RATE_MCS_9_INDEX }, +	{ -64, IWL_RATE_MCS_8_INDEX }, +	{ -68, IWL_RATE_MCS_7_INDEX }, +	{ -72, IWL_RATE_MCS_6_INDEX }, +	{ -80, IWL_RATE_MCS_5_INDEX }, +	{ -84, IWL_RATE_MCS_4_INDEX }, +	{ -85, IWL_RATE_MCS_3_INDEX }, +	{ -87, IWL_RATE_MCS_2_INDEX }, +	{ -88, IWL_RATE_MCS_1_INDEX }, +	{ S8_MIN, IWL_RATE_MCS_0_INDEX }, +}; + +/* Init the optimal rate based on STA caps + * This combined with rssi is used to report the last tx rate + * to userspace when we haven't transmitted enough frames. + */ +static void rs_init_optimal_rate(struct iwl_mvm *mvm, +				 struct ieee80211_sta *sta, +				 struct iwl_lq_sta *lq_sta) +{ +	struct rs_rate *rate = &lq_sta->optimal_rate; + +	if (lq_sta->max_mimo2_rate_idx != IWL_RATE_INVALID) +		rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; +	else if (lq_sta->max_siso_rate_idx != IWL_RATE_INVALID) +		rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; +	else if (lq_sta->band == IEEE80211_BAND_5GHZ) +		rate->type = LQ_LEGACY_A; +	else +		rate->type = LQ_LEGACY_G; + +	rate->bw = rs_bw_from_sta_bw(sta); +	rate->sgi = rs_sgi_allow(mvm, sta, rate, NULL); + +	/* ANT/LDPC/STBC aren't relevant for the rate reported to userspace */ + +	if (is_mimo(rate)) { +		lq_sta->optimal_rate_mask = lq_sta->active_mimo2_rate; +	} else if (is_siso(rate)) { +		lq_sta->optimal_rate_mask = lq_sta->active_siso_rate; +	} else { +		lq_sta->optimal_rate_mask = lq_sta->active_legacy_rate; + +		if (lq_sta->band == IEEE80211_BAND_5GHZ) { +			lq_sta->optimal_rates = rs_optimal_rates_5ghz_legacy; +			lq_sta->optimal_nentries = +				ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); +		} else { +			lq_sta->optimal_rates = rs_optimal_rates_24ghz_legacy; +			lq_sta->optimal_nentries = +				ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); +		} +	} + +	if (is_vht(rate)) { +		if (rate->bw == RATE_MCS_CHAN_WIDTH_20) { +			lq_sta->optimal_rates = rs_optimal_rates_vht_20mhz; +			lq_sta->optimal_nentries = +				ARRAY_SIZE(rs_optimal_rates_vht_20mhz); +		} else { +			lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz; +			lq_sta->optimal_nentries = +				ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); +		} +	} else if (is_ht(rate)) { +		lq_sta->optimal_rates = rs_optimal_rates_ht; +		lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_ht); +	} +} + +/* Compute the optimal rate index based on RSSI */ +static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm, +					   struct iwl_lq_sta *lq_sta) +{ +	struct rs_rate *rate = &lq_sta->optimal_rate; +	int i; + +	rate->index = find_first_bit(&lq_sta->optimal_rate_mask, +				     BITS_PER_LONG); + +	for (i = 0; i < lq_sta->optimal_nentries; i++) { +		int rate_idx = lq_sta->optimal_rates[i].rate_idx; + +		if ((lq_sta->pers.last_rssi >= lq_sta->optimal_rates[i].rssi) && +		    (BIT(rate_idx) & lq_sta->optimal_rate_mask)) { +			rate->index = rate_idx; +			break; +		} +	} + +	rs_dump_rate(mvm, rate, "OPTIMAL RATE"); +	return rate; +} +  /* Choose an initial legacy rate and antenna to use based on the RSSI   * of last Rx   */ @@ -2468,12 +2587,12 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,  	if (band == IEEE80211_BAND_5GHZ) {  		rate->type = LQ_LEGACY_A; -		initial_rates = rs_init_rates_5ghz; -		nentries = ARRAY_SIZE(rs_init_rates_5ghz); +		initial_rates = rs_optimal_rates_5ghz_legacy; +		nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy);  	} else {  		rate->type = LQ_LEGACY_G; -		initial_rates = rs_init_rates_24ghz; -		nentries = ARRAY_SIZE(rs_init_rates_24ghz); +		initial_rates = rs_optimal_rates_24ghz_legacy; +		nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy);  	}  	if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { @@ -2496,10 +2615,21 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,  			 struct iwl_lq_sta *lq_sta,  			 struct ieee80211_rx_status *rx_status)  { +	int i; +  	lq_sta->pers.chains = rx_status->chains;  	lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0];  	lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1];  	lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; +	lq_sta->pers.last_rssi = S8_MIN; + +	for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { +		if (!(lq_sta->pers.chains & BIT(i))) +			continue; + +		if (lq_sta->pers.chain_signal[i] > lq_sta->pers.last_rssi) +			lq_sta->pers.last_rssi = lq_sta->pers.chain_signal[i]; +	}  }  /** @@ -2538,6 +2668,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,  	rate = &tbl->rate;  	rs_get_initial_rate(mvm, lq_sta, band, rate); +	rs_init_optimal_rate(mvm, sta, lq_sta);  	WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);  	if (rate->ant == ANT_A) @@ -2560,6 +2691,8 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,  	struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct iwl_lq_sta *lq_sta = mvm_sta; +	struct rs_rate *optimal_rate; +	u32 last_ucode_rate;  	if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) {  		/* if vif isn't initialized mvm doesn't know about @@ -2583,8 +2716,18 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,  	iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags,  				  info->band, &info->control.rates[0]); -  	info->control.rates[0].count = 1; + +	/* Report the optimal rate based on rssi and STA caps if we haven't +	 * converged yet (too little traffic) or exploring other modulations +	 */ +	if (lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN) { +		optimal_rate = rs_get_optimal_rate(mvm, lq_sta); +		last_ucode_rate = ucode_rate_from_rs_rate(mvm, +							  optimal_rate); +		iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, info->band, +					  &txrc->reported_rate); +	}  }  static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, @@ -2605,6 +2748,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,  #endif  	lq_sta->pers.chains = 0;  	memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); +	lq_sta->pers.last_rssi = S8_MIN;  	return &sta_priv->lq_sta;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 2a3da314305a..81314ad9ebe0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -1,6 +1,7 @@  /******************************************************************************   *   * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Mobile Communications GmbH   *   * This program is free software; you can redistribute it and/or modify it   * under the terms of version 2 of the GNU General Public License as @@ -316,6 +317,14 @@ struct iwl_lq_sta {  	u8 max_siso_rate_idx;  	u8 max_mimo2_rate_idx; +	/* Optimal rate based on RSSI and STA caps. +	 * Used only to reflect link speed to userspace. +	 */ +	struct rs_rate optimal_rate; +	unsigned long optimal_rate_mask; +	const struct rs_init_rate_info *optimal_rates; +	int optimal_nentries; +  	u8 missed_rate_counter;  	struct iwl_lq_cmd lq; @@ -341,6 +350,7 @@ struct iwl_lq_sta {  #endif  		u8 chains;  		s8 chain_signal[IEEE80211_MAX_CHAINS]; +		s8 last_rssi;  		struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];  		struct iwl_mvm *drv;  	} pers; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13a..c37c10a423ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -61,6 +61,7 @@   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   *****************************************************************************/ +#include <linux/skbuff.h>  #include "iwl-trans.h"  #include "mvm.h"  #include "fw-api.h" @@ -71,8 +72,7 @@   * Copies the phy information in mvm->last_phy_info, it will be used when the   * actual data will come from the fw in the next packet.   */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -86,8 +86,6 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		spin_unlock(&mvm->drv_stats_lock);  	}  #endif - -	return 0;  }  /* @@ -96,6 +94,7 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,   * Adds the rxb to a new skb and give it to mac80211   */  static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, +					    struct napi_struct *napi,  					    struct sk_buff *skb,  					    struct ieee80211_hdr *hdr, u16 len,  					    u32 ampdu_status, u8 crypt_len, @@ -129,7 +128,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,  				fraglen, rxb->truesize);  	} -	ieee80211_rx(mvm->hw, skb); +	ieee80211_rx_napi(mvm->hw, skb, napi);  }  /* @@ -237,13 +236,26 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,  	return 0;  } +static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, +			    struct sk_buff *skb, +			    u32 status) +{ +	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + +	if (mvmvif->features & NETIF_F_RXCSUM && +	    status & RX_MPDU_RES_STATUS_CSUM_DONE && +	    status & RX_MPDU_RES_STATUS_CSUM_OK) +		skb->ip_summed = CHECKSUM_UNNECESSARY; +} +  /*   * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler   *   * Handles the actual data of the Rx packet from the fw   */ -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		       struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, +			struct iwl_rx_cmd_buffer *rxb)  {  	struct ieee80211_hdr *hdr;  	struct ieee80211_rx_status *rx_status; @@ -271,7 +283,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	skb = alloc_skb(128, GFP_ATOMIC);  	if (!skb) {  		IWL_ERR(mvm, "alloc_skb failed\n"); -		return 0; +		return;  	}  	rx_status = IEEE80211_SKB_RXCB(skb); @@ -284,14 +296,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",  			       rx_pkt_status);  		kfree_skb(skb); -		return 0; +		return;  	}  	if ((unlikely(phy_info->cfg_phy_cnt > 20))) {  		IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n",  			       phy_info->cfg_phy_cnt);  		kfree_skb(skb); -		return 0; +		return;  	}  	/* @@ -366,6 +378,9 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		}  	} +	if (sta && ieee80211_is_data(hdr->frame_control)) +		iwl_mvm_rx_csum(sta, skb, rx_pkt_status); +  	rcu_read_unlock();  	/* set the preamble flag if appropriate */ @@ -429,9 +444,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	iwl_mvm_update_frame_stats(mvm, rate_n_flags,  				   rx_status->flag & RX_FLAG_AMPDU_DETAILS);  #endif -	iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, +	iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status,  					crypt_len, rxb); -	return 0;  }  static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, @@ -623,10 +637,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,  		iwl_rx_packet_payload_len(pkt));  } -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, -			  struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd) +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb)); -	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5de144968723..56559d4d34ad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -72,10 +72,60 @@  #define IWL_DENSE_EBS_SCAN_RATIO 5  #define IWL_SPARSE_EBS_SCAN_RATIO 1 -struct iwl_mvm_scan_params { -	u32 max_out_time; +enum iwl_mvm_scan_type { +	IWL_SCAN_TYPE_UNASSOC, +	IWL_SCAN_TYPE_WILD, +	IWL_SCAN_TYPE_MILD, +	IWL_SCAN_TYPE_FRAGMENTED, +}; + +enum iwl_mvm_traffic_load { +	IWL_MVM_TRAFFIC_LOW, +	IWL_MVM_TRAFFIC_MEDIUM, +	IWL_MVM_TRAFFIC_HIGH, +}; + +struct iwl_mvm_scan_timing_params { +	u32 dwell_active; +	u32 dwell_passive; +	u32 dwell_fragmented;  	u32 suspend_time; -	bool passive_fragmented; +	u32 max_out_time; +}; + +static struct iwl_mvm_scan_timing_params scan_timing[] = { +	[IWL_SCAN_TYPE_UNASSOC] = { +		.dwell_active = 10, +		.dwell_passive = 110, +		.dwell_fragmented = 44, +		.suspend_time = 0, +		.max_out_time = 0, +	}, +	[IWL_SCAN_TYPE_WILD] = { +		.dwell_active = 10, +		.dwell_passive = 110, +		.dwell_fragmented = 44, +		.suspend_time = 30, +		.max_out_time = 120, +	}, +	[IWL_SCAN_TYPE_MILD] = { +		.dwell_active = 10, +		.dwell_passive = 110, +		.dwell_fragmented = 44, +		.suspend_time = 120, +		.max_out_time = 120, +	}, +	[IWL_SCAN_TYPE_FRAGMENTED] = { +		.dwell_active = 10, +		.dwell_passive = 110, +		.dwell_fragmented = 44, +		.suspend_time = 95, +		.max_out_time = 44, +	}, +}; + +struct iwl_mvm_scan_params { +	enum iwl_mvm_scan_type type;  	u32 n_channels;  	u16 delay;  	int n_ssids; @@ -90,15 +140,7 @@ struct iwl_mvm_scan_params {  	int n_match_sets;  	struct iwl_scan_probe_req preq;  	struct cfg80211_match_set *match_sets; -	struct _dwell { -		u16 passive; -		u16 active; -		u16 fragmented; -	} dwell[IEEE80211_NUM_BANDS]; -	struct { -		u8 iterations; -		u8 full_scan_mul; /* not used for UMAC */ -	} schedule[2]; +	u8 iterations[2];  };  static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) @@ -147,34 +189,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,  		return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant);  } -/* - * If req->n_ssids > 0, it means we should do an active scan. - * In case of active scan w/o directed scan, we receive a zero-length SSID - * just to notify that this scan is active and not passive. - * In order to notify the FW of the number of SSIDs we wish to scan (including - * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). If the first SSID is - * already included in the probe template, so we need to set only - * req->n_ssids - 1 bits in addition to the first bit. - */ -static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm, -				    enum ieee80211_band band, int n_ssids) -{ -	if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) -		return 10; -	if (band == IEEE80211_BAND_2GHZ) -		return 20  + 3 * (n_ssids + 1); -	return 10  + 2 * (n_ssids + 1); -} - -static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm, -				     enum ieee80211_band band) -{ -	if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) -			return 110; -	return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; -} -  static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,  					    struct ieee80211_vif *vif)  { @@ -186,90 +200,39 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,  		*global_cnt += 1;  } -static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, -				    struct ieee80211_vif *vif, -				    struct iwl_mvm_scan_params *params) +static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) +{ +	return IWL_MVM_TRAFFIC_LOW; +} + +static enum +iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, +					struct ieee80211_vif *vif, +					struct iwl_mvm_scan_params *params)  {  	int global_cnt = 0; -	enum ieee80211_band band; -	u8 frag_passive_dwell = 0; +	enum iwl_mvm_traffic_load load; +	bool low_latency;  	ieee80211_iterate_active_interfaces_atomic(mvm->hw,  					    IEEE80211_IFACE_ITER_NORMAL,  					    iwl_mvm_scan_condition_iterator,  					    &global_cnt);  	if (!global_cnt) -		goto not_bound; - -	params->suspend_time = 30; -	params->max_out_time = 120; - -	if (iwl_mvm_low_latency(mvm)) { -		if (fw_has_api(&mvm->fw->ucode_capa, -			       IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { - -			params->suspend_time = 105; -			/* -			 * If there is more than one active interface make -			 * passive scan more fragmented. -			 */ -			frag_passive_dwell = 40; -			params->max_out_time = frag_passive_dwell; -		} else { -			params->suspend_time = 120; -			params->max_out_time = 120; -		} -	} +		return IWL_SCAN_TYPE_UNASSOC; -	if (frag_passive_dwell && -	    fw_has_api(&mvm->fw->ucode_capa, -		       IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { -		/* -		 * P2P device scan should not be fragmented to avoid negative -		 * impact on P2P device discovery. Configure max_out_time to be -		 * equal to dwell time on passive channel. Take a longest -		 * possible value, one that corresponds to 2GHz band -		 */ -		if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { -			u32 passive_dwell = -				iwl_mvm_get_passive_dwell(mvm, -							  IEEE80211_BAND_2GHZ); -			params->max_out_time = passive_dwell; -		} else { -			params->passive_fragmented = true; -		} -	} - -	if ((params->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && -	    (params->max_out_time > 200)) -		params->max_out_time = 200; +	load = iwl_mvm_get_traffic_load(mvm); +	low_latency = iwl_mvm_low_latency(mvm); -not_bound: +	if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && +	    vif->type != NL80211_IFTYPE_P2P_DEVICE && +	    fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) +		return IWL_SCAN_TYPE_FRAGMENTED; -	for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { -		if (params->passive_fragmented) -			params->dwell[band].fragmented = frag_passive_dwell; - -		params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm, -									band); -		params->dwell[band].active = -			iwl_mvm_get_active_dwell(mvm, band, params->n_ssids); -	} +	if (load >= IWL_MVM_TRAFFIC_MEDIUM || low_latency) +		return IWL_SCAN_TYPE_MILD; -	IWL_DEBUG_SCAN(mvm, -		       "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n", -		       params->max_out_time, params->suspend_time, -		       params->passive_fragmented); -	IWL_DEBUG_SCAN(mvm, -		       "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n", -		       params->dwell[IEEE80211_BAND_2GHZ].passive, -		       params->dwell[IEEE80211_BAND_2GHZ].active, -		       params->dwell[IEEE80211_BAND_2GHZ].fragmented); -	IWL_DEBUG_SCAN(mvm, -		       "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n", -		       params->dwell[IEEE80211_BAND_5GHZ].passive, -		       params->dwell[IEEE80211_BAND_5GHZ].active, -		       params->dwell[IEEE80211_BAND_5GHZ].fragmented); +	return IWL_SCAN_TYPE_WILD;  }  static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) @@ -327,9 +290,8 @@ static u8 *iwl_mvm_dump_channel_list(struct iwl_scan_results_notif *res,  	return buf;  } -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; @@ -341,17 +303,13 @@ int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,  		       iwl_mvm_dump_channel_list(notif->results,  						 notif->scanned_channels, buf,  						 sizeof(buf))); -	return 0;  } -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd) +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb)  {  	IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");  	ieee80211_sched_scan_results(mvm->hw); - -	return 0;  }  static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) @@ -368,9 +326,8 @@ static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status)  	}  } -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, -					struct iwl_rx_cmd_buffer *rxb, -					struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, +					 struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data; @@ -395,6 +352,11 @@ int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,  		IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n",  			       aborted ? "aborted" : "completed",  			       iwl_mvm_ebs_status_str(scan_notif->ebs_status)); +		IWL_DEBUG_SCAN(mvm, +			       "Last line %d, Last iteration %d, Time after last iteration %d\n", +			       scan_notif->last_schedule_line, +			       scan_notif->last_schedule_iteration, +			       __le32_to_cpu(scan_notif->time_after_last_iter));  		mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED;  	} else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) { @@ -406,9 +368,14 @@ int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,  	} else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) {  		WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR); -		IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s (FW)\n", +		IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n",  			       aborted ? "aborted" : "completed",  			       iwl_mvm_ebs_status_str(scan_notif->ebs_status)); +		IWL_DEBUG_SCAN(mvm, +			       "Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", +			       scan_notif->last_schedule_line, +			       scan_notif->last_schedule_iteration, +			       __le32_to_cpu(scan_notif->time_after_last_iter));  		mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;  		ieee80211_sched_scan_stopped(mvm->hw); @@ -426,8 +393,6 @@ int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,  	mvm->last_ebs_successful =  			scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ||  			scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE; - -	return 0;  }  static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) @@ -751,13 +716,11 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,  				    struct iwl_scan_req_lmac *cmd,  				    struct iwl_mvm_scan_params *params)  { -	cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; -	cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; -	if (params->passive_fragmented) -		cmd->fragmented_dwell = -				params->dwell[IEEE80211_BAND_2GHZ].fragmented; -	cmd->max_out_time = cpu_to_le32(params->max_out_time); -	cmd->suspend_time = cpu_to_le32(params->suspend_time); +	cmd->active_dwell = scan_timing[params->type].dwell_active; +	cmd->passive_dwell = scan_timing[params->type].dwell_passive; +	cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented; +	cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time); +	cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);  	cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);  } @@ -794,7 +757,7 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,  static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)  { -	return params->schedule[0].iterations + params->schedule[1].iterations; +	return params->iterations[0] + params->iterations[1];  }  static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, @@ -808,7 +771,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,  	if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)  		flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; -	if (params->passive_fragmented) +	if (params->type == IWL_SCAN_TYPE_FRAGMENTED)  		flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;  	if (iwl_mvm_rrm_scan_needed(mvm)) @@ -861,11 +824,11 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	ssid_bitmap <<= 1;  	cmd->schedule[0].delay = cpu_to_le16(params->interval); -	cmd->schedule[0].iterations = params->schedule[0].iterations; -	cmd->schedule[0].full_scan_mul = params->schedule[0].full_scan_mul; +	cmd->schedule[0].iterations = params->iterations[0]; +	cmd->schedule[0].full_scan_mul = 1;  	cmd->schedule[1].delay = cpu_to_le16(params->interval); -	cmd->schedule[1].iterations = params->schedule[1].iterations; -	cmd->schedule[1].full_scan_mul = params->schedule[1].iterations; +	cmd->schedule[1].iterations = params->iterations[1]; +	cmd->schedule[1].full_scan_mul = 1;  	if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {  		cmd->channel_opt[0].flags = @@ -937,9 +900,9 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)  	int num_channels =  		mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +  		mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; -	int ret, i, j = 0, cmd_size, data_size; +	int ret, i, j = 0, cmd_size;  	struct iwl_host_cmd cmd = { -		.id = SCAN_CFG_CMD, +		.id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0),  	};  	if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) @@ -951,8 +914,6 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)  	if (!scan_config)  		return -ENOMEM; -	data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); -	scan_config->hdr.size = cpu_to_le16(data_size);  	scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE |  					 SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |  					 SCAN_CONFIG_FLAG_SET_TX_CHAINS | @@ -1013,17 +974,15 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,  				    struct iwl_scan_req_umac *cmd,  				    struct iwl_mvm_scan_params *params)  { -	cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; -	cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; -	if (params->passive_fragmented) -		cmd->fragmented_dwell = -				params->dwell[IEEE80211_BAND_2GHZ].fragmented; -	cmd->max_out_time = cpu_to_le32(params->max_out_time); -	cmd->suspend_time = cpu_to_le32(params->suspend_time); +	cmd->active_dwell = scan_timing[params->type].dwell_active; +	cmd->passive_dwell = scan_timing[params->type].dwell_passive; +	cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented; +	cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time); +	cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);  	cmd->scan_priority =  		iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); -	if (iwl_mvm_scan_total_iterations(params) == 0) +	if (iwl_mvm_scan_total_iterations(params) == 1)  		cmd->ooc_priority =  			iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);  	else @@ -1059,7 +1018,7 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,  	if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)  		flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; -	if (params->passive_fragmented) +	if (params->type == IWL_SCAN_TYPE_FRAGMENTED)  		flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;  	if (iwl_mvm_rrm_scan_needed(mvm)) @@ -1099,8 +1058,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  		return uid;  	memset(cmd, 0, ksize(cmd)); -	cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - -				    sizeof(struct iwl_mvm_umac_cmd_hdr));  	iwl_mvm_scan_umac_dwell(mvm, cmd, params); @@ -1109,6 +1066,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	cmd->uid = cpu_to_le32(uid);  	cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params)); +	if (type == IWL_MVM_SCAN_SCHED) +		cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); +  	if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))  		cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |  				     IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | @@ -1227,17 +1187,15 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	params.n_match_sets = 0;  	params.match_sets = NULL; -	params.schedule[0].iterations = 1; -	params.schedule[0].full_scan_mul = 0; -	params.schedule[1].iterations = 0; -	params.schedule[1].full_scan_mul = 0; +	params.iterations[0] = 1; +	params.iterations[1] = 0; -	iwl_mvm_scan_calc_dwell(mvm, vif, ¶ms); +	params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms);  	iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);  	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { -		hcmd.id = SCAN_REQ_UMAC; +		hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0);  		ret = iwl_mvm_scan_umac(mvm, vif, ¶ms,  					IWL_MVM_SCAN_REGULAR);  	} else { @@ -1310,10 +1268,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  	params.n_match_sets = req->n_match_sets;  	params.match_sets = req->match_sets; -	params.schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS; -	params.schedule[0].full_scan_mul = 1; -	params.schedule[1].iterations = 0xff; -	params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; +	params.iterations[0] = 0; +	params.iterations[1] = 0xff; + +	params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms);  	if (req->interval > U16_MAX) {  		IWL_DEBUG_SCAN(mvm, @@ -1336,8 +1294,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  		params.delay = req->delay;  	} -	iwl_mvm_scan_calc_dwell(mvm, vif, ¶ms); -  	ret = iwl_mvm_config_sched_scan_profiles(mvm, req);  	if (ret)  		return ret; @@ -1345,7 +1301,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  	iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);  	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { -		hcmd.id = SCAN_REQ_UMAC; +		hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0);  		ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_SCHED);  	} else {  		hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; @@ -1371,9 +1327,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  	return ret;  } -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, -					struct iwl_rx_cmd_buffer *rxb, -					struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, +					 struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_umac_scan_complete *notif = (void *)pkt->data; @@ -1381,7 +1336,7 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,  	bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);  	if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status))) -		return 0; +		return;  	/* if the scan is already stopping, we don't need to notify mac80211 */  	if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { @@ -1392,26 +1347,26 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,  	}  	mvm->scan_status &= ~mvm->scan_uid_status[uid]; -  	IWL_DEBUG_SCAN(mvm,  		       "Scan completed, uid %u type %u, status %s, EBS status %s\n",  		       uid, mvm->scan_uid_status[uid],  		       notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?  				"completed" : "aborted",  		       iwl_mvm_ebs_status_str(notif->ebs_status)); +	IWL_DEBUG_SCAN(mvm, +		       "Last line %d, Last iteration %d, Time from last iteration %d\n", +		       notif->last_schedule, notif->last_iter, +		       __le32_to_cpu(notif->time_from_last_iter));  	if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS &&  	    notif->ebs_status != IWL_SCAN_EBS_INACTIVE)  		mvm->last_ebs_successful = false;  	mvm->scan_uid_status[uid] = 0; - -	return 0;  } -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, -					     struct iwl_rx_cmd_buffer *rxb, -					     struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, +					      struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; @@ -1423,15 +1378,11 @@ int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,  		       iwl_mvm_dump_channel_list(notif->results,  						 notif->scanned_channels, buf,  						 sizeof(buf))); -	return 0;  }  static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)  { -	struct iwl_umac_scan_abort cmd = { -		.hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - -					sizeof(struct iwl_mvm_umac_cmd_hdr)), -	}; +	struct iwl_umac_scan_abort cmd = {};  	int uid, ret;  	lockdep_assert_held(&mvm->mutex); @@ -1448,7 +1399,10 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)  	IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); -	ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); +	ret = iwl_mvm_send_cmd_pdu(mvm, +				   iwl_cmd_id(SCAN_ABORT_UMAC, +					      IWL_ALWAYS_LONG_GROUP, 0), +				   0, sizeof(cmd), &cmd);  	if (!ret)  		mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; @@ -1458,7 +1412,7 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)  static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)  {  	struct iwl_notification_wait wait_scan_done; -	static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, +	static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC,  					      SCAN_OFFLOAD_COMPLETE, };  	int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d68dc697a4a0..df216cd0c98f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1148,18 +1148,31 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)  { -	int i; +	int i, max = -1, max_offs = -1;  	lockdep_assert_held(&mvm->mutex); -	i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM); +	/* Pick the unused key offset with the highest 'deleted' +	 * counter. Every time a key is deleted, all the counters +	 * are incremented and the one that was just deleted is +	 * reset to zero. Thus, the highest counter is the one +	 * that was deleted longest ago. Pick that one. +	 */ +	for (i = 0; i < STA_KEY_MAX_NUM; i++) { +		if (test_bit(i, mvm->fw_key_table)) +			continue; +		if (mvm->fw_key_deleted[i] > max) { +			max = mvm->fw_key_deleted[i]; +			max_offs = i; +		} +	} -	if (i == STA_KEY_MAX_NUM) +	if (max_offs < 0)  		return STA_KEY_IDX_INVALID; -	__set_bit(i, mvm->fw_key_table); +	__set_bit(max_offs, mvm->fw_key_table); -	return i; +	return max_offs;  }  static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, @@ -1277,8 +1290,6 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,  		const u8 *pn;  		memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen); -		ieee80211_aes_cmac_calculate_k1_k2(keyconf, -						   igtk_cmd.K1, igtk_cmd.K2);  		ieee80211_get_key_rx_seq(keyconf, 0, &seq);  		pn = seq.aes_cmac.pn;  		igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) | @@ -1401,6 +1412,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,  	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);  	u8 sta_id;  	int ret; +	static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};  	lockdep_assert_held(&mvm->mutex); @@ -1467,7 +1479,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,  end:  	IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",  		      keyconf->cipher, keyconf->keylen, keyconf->keyidx, -		      sta->addr, ret); +		      sta ? sta->addr : zero_addr, ret);  	return ret;  } @@ -1478,7 +1490,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,  {  	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);  	u8 sta_id; -	int ret; +	int ret, i;  	lockdep_assert_held(&mvm->mutex); @@ -1497,6 +1509,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,  		return -ENOENT;  	} +	/* track which key was deleted last */ +	for (i = 0; i < STA_KEY_MAX_NUM; i++) { +		if (mvm->fw_key_deleted[i] < U8_MAX) +			mvm->fw_key_deleted[i]++; +	} +	mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; +  	if (sta_id == IWL_MVM_STATION_COUNT) {  		IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");  		return 0; @@ -1660,9 +1679,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,  		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);  } -int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, -			  struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd) +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, +			   struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; @@ -1670,15 +1688,13 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,  	u32 sta_id = le32_to_cpu(notif->sta_id);  	if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) -		return 0; +		return;  	rcu_read_lock();  	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);  	if (!IS_ERR_OR_NULL(sta))  		ieee80211_sta_eosp(sta);  	rcu_read_unlock(); - -	return 0;  }  void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 748f5dc3f9f4..eedb215eba3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -378,9 +378,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,  			     struct ieee80211_sta *sta, u32 iv32,  			     u16 *phase1key); -int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, -			  struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd); +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, +			   struct iwl_rx_cmd_buffer *rxb);  /* AMPDU */  int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index a87b506c8c72..fe2fa5650443 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -169,18 +169,11 @@ static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		return;  	pkt = cmd.resp_pkt; -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		IWL_ERR(mvm, "Bad return from TDLS_CONFIG_COMMAND (0x%08X)\n", -			pkt->hdr.flags); -		goto exit; -	} -	if (WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp))) -		goto exit; +	WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp));  	/* we don't really care about the response at this point */ -exit:  	iwl_free_resp(&cmd);  } @@ -261,8 +254,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,  		mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT;  } -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data; @@ -277,17 +269,17 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	/* can fail sometimes */  	if (!le32_to_cpu(notif->status)) {  		iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); -		goto out; +		return;  	}  	if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT)) -		goto out; +		return;  	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],  					lockdep_is_held(&mvm->mutex));  	/* the station may not be here, but if it is, it must be a TDLS peer */  	if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls)) -		goto out; +		return;  	mvmsta = iwl_mvm_sta_from_mac80211(sta);  	vif = mvmsta->vif; @@ -301,9 +293,6 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  			 msecs_to_jiffies(delay));  	iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); - -out: -	return 0;  }  static int @@ -471,13 +460,19 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,  	cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2);  	info = IEEE80211_SKB_CB(skb); -	if (info->control.hw_key) -		iwl_mvm_set_tx_cmd_crypto(mvm, info, &cmd.frame.tx_cmd, skb); +	hdr = (void *)skb->data; +	if (info->control.hw_key) { +		if (info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP) { +			rcu_read_unlock(); +			ret = -EINVAL; +			goto out; +		} +		iwl_mvm_set_tx_cmd_ccmp(info, &cmd.frame.tx_cmd); +	}  	iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info,  			   mvmsta->sta_id); -	hdr = (void *)skb->data;  	iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta,  				hdr->frame_control);  	rcu_read_unlock(); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index d24b6a83e68c..dbd7d544575d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -86,7 +86,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,  {  	lockdep_assert_held(&mvm->time_event_lock); -	if (te_data->id == TE_MAX) +	if (!te_data->vif)  		return;  	list_del(&te_data->list); @@ -410,9 +410,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,  /*   * The Rx handler for time event notifications   */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd) +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_time_event_notif *notif = (void *)pkt->data; @@ -433,8 +432,6 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,  	}  unlock:  	spin_unlock_bh(&mvm->time_event_lock); - -	return 0;  }  static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait, @@ -503,7 +500,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,  				       struct iwl_mvm_time_event_data *te_data,  				       struct iwl_time_event_cmd *te_cmd)  { -	static const u8 time_event_response[] = { TIME_EVENT_CMD }; +	static const u16 time_event_response[] = { TIME_EVENT_CMD };  	struct iwl_notification_wait wait_time_event;  	int ret; @@ -566,7 +563,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; -	const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; +	const u16 te_notif_response[] = { TIME_EVENT_NOTIFICATION };  	struct iwl_notification_wait wait_te_notif;  	struct iwl_time_event_cmd time_cmd = {}; @@ -599,8 +596,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,  		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));  	time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC); -	time_cmd.apply_time = -		cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); +	time_cmd.apply_time = cpu_to_le32(0);  	time_cmd.max_frags = TE_V2_FRAG_NONE;  	time_cmd.max_delay = cpu_to_le32(max_delay); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index de4fbc6d57f1..cbdf8e52a5f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -157,9 +157,8 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,  /*   * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION.   */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, -				struct iwl_rx_cmd_buffer *rxb, -				struct iwl_device_cmd *cmd); +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, +				 struct iwl_rx_cmd_buffer *rxb);  /**   * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionality diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c new file mode 100644 index 000000000000..380972f8fb82 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -0,0 +1,304 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license.  When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <[email protected]> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *  * Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + *  * Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + *  * Neither the name Intel Corporation nor the names of its + *    contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "mvm.h" +#include "fw-api-tof.h" + +#define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256 + +void iwl_mvm_tof_init(struct iwl_mvm *mvm) +{ +	struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return; + +	memset(tof_data, 0, sizeof(*tof_data)); + +	tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); + +#ifdef CONFIG_IWLWIFI_DEBUGFS +	if (IWL_MVM_TOF_IS_RESPONDER) { +		tof_data->responder_cfg.sub_grp_cmd_id = +			cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); +		tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; +	} +#endif + +	tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); +	tof_data->range_req.req_timeout = 1; +	tof_data->range_req.initiator = 1; +	tof_data->range_req.report_policy = 3; + +	tof_data->range_req_ext.sub_grp_cmd_id = +		cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); + +	mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +void iwl_mvm_tof_clean(struct iwl_mvm *mvm) +{ +	struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return; + +	memset(tof_data, 0, sizeof(*tof_data)); +	mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +static void iwl_tof_iterator(void *_data, u8 *mac, +			     struct ieee80211_vif *vif) +{ +	bool *enabled = _data; + +	/* non bss vif exists */ +	if (ieee80211_vif_type_p2p(vif) !=  NL80211_IFTYPE_STATION) +		*enabled = false; +} + +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) +{ +	struct iwl_tof_config_cmd *cmd = &mvm->tof_data.tof_cfg; +	bool enabled; + +	lockdep_assert_held(&mvm->mutex); + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return -EINVAL; + +	ieee80211_iterate_active_interfaces_atomic(mvm->hw, +						   IEEE80211_IFACE_ITER_NORMAL, +						   iwl_tof_iterator, &enabled); +	if (!enabled) { +		IWL_DEBUG_INFO(mvm, "ToF is not supported (non bss vif)\n"); +		return -EINVAL; +	} + +	mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, +						    IWL_ALWAYS_LONG_GROUP, 0), +				    0, sizeof(*cmd), cmd); +} + +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) +{ +	struct iwl_tof_range_abort_cmd cmd = { +		.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), +		.request_id = id, +	}; + +	lockdep_assert_held(&mvm->mutex); + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return -EINVAL; + +	if (id != mvm->tof_data.active_range_request) { +		IWL_ERR(mvm, "Invalid range request id %d (active %d)\n", +			id, mvm->tof_data.active_range_request); +		return -EINVAL; +	} + +	/* after abort is sent there's no active request anymore */ +	mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + +	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, +						    IWL_ALWAYS_LONG_GROUP, 0), +				    0, sizeof(cmd), &cmd); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, +			      struct ieee80211_vif *vif) +{ +	struct iwl_tof_responder_config_cmd *cmd = &mvm->tof_data.responder_cfg; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	lockdep_assert_held(&mvm->mutex); + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return -EINVAL; + +	if (vif->p2p || vif->type != NL80211_IFTYPE_AP) { +		IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); +		return -EIO; +	} + +	cmd->sta_id = mvmvif->bcast_sta.sta_id; +	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, +						    IWL_ALWAYS_LONG_GROUP, 0), +				    0, sizeof(*cmd), cmd); +} +#endif + +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, +				  struct ieee80211_vif *vif) +{ +	struct iwl_host_cmd cmd = { +		.id = iwl_cmd_id(TOF_CMD, IWL_ALWAYS_LONG_GROUP, 0), +		.len = { sizeof(mvm->tof_data.range_req), }, +		/* no copy because of the command size */ +		.dataflags = { IWL_HCMD_DFL_NOCOPY, }, +	}; + +	lockdep_assert_held(&mvm->mutex); + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return -EINVAL; + +	if (ieee80211_vif_type_p2p(vif) !=  NL80211_IFTYPE_STATION) { +		IWL_ERR(mvm, "Cannot send range request, not STA mode\n"); +		return -EIO; +	} + +	/* nesting of range requests is not supported in FW */ +	if (mvm->tof_data.active_range_request != +		IWL_MVM_TOF_RANGE_REQ_MAX_ID) { +		IWL_ERR(mvm, "Cannot send range req, already active req %d\n", +			mvm->tof_data.active_range_request); +		return -EIO; +	} + +	mvm->tof_data.active_range_request = mvm->tof_data.range_req.request_id; + +	cmd.data[0] = &mvm->tof_data.range_req; +	return iwl_mvm_send_cmd(mvm, &cmd); +} + +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, +				      struct ieee80211_vif *vif) +{ +	lockdep_assert_held(&mvm->mutex); + +	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) +		return -EINVAL; + +	if (ieee80211_vif_type_p2p(vif) !=  NL80211_IFTYPE_STATION) { +		IWL_ERR(mvm, "Cannot send ext range req, not in STA mode\n"); +		return -EIO; +	} + +	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, +						    IWL_ALWAYS_LONG_GROUP, 0), +				    0, sizeof(mvm->tof_data.range_req_ext), +				    &mvm->tof_data.range_req_ext); +} + +static int iwl_mvm_tof_range_resp(struct iwl_mvm *mvm, void *data) +{ +	struct iwl_tof_range_rsp_ntfy *resp = (void *)data; + +	if (resp->request_id != mvm->tof_data.active_range_request) { +		IWL_ERR(mvm, "Request id mismatch, got %d, active %d\n", +			resp->request_id, mvm->tof_data.active_range_request); +		return -EIO; +	} + +	memcpy(&mvm->tof_data.range_resp, resp, +	       sizeof(struct iwl_tof_range_rsp_ntfy)); +	mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + +	return 0; +} + +static int iwl_mvm_tof_mcsi_notif(struct iwl_mvm *mvm, void *data) +{ +	struct iwl_tof_mcsi_notif *resp = (struct iwl_tof_mcsi_notif *)data; + +	IWL_DEBUG_INFO(mvm, "MCSI notification, token %d\n", resp->token); +	return 0; +} + +static int iwl_mvm_tof_nb_report_notif(struct iwl_mvm *mvm, void *data) +{ +	struct iwl_tof_neighbor_report *report = +		(struct iwl_tof_neighbor_report *)data; + +	IWL_DEBUG_INFO(mvm, "NB report, bssid %pM, token %d, status 0x%x\n", +		       report->bssid, report->request_token, report->status); +	return 0; +} + +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, +			      struct iwl_rx_cmd_buffer *rxb) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	struct iwl_tof_gen_resp_cmd *resp = (void *)pkt->data; + +	lockdep_assert_held(&mvm->mutex); + +	switch (le32_to_cpu(resp->sub_grp_cmd_id)) { +	case TOF_RANGE_RESPONSE_NOTIF: +		iwl_mvm_tof_range_resp(mvm, resp->data); +		break; +	case TOF_MCSI_DEBUG_NOTIF: +		iwl_mvm_tof_mcsi_notif(mvm, resp->data); +		break; +	case TOF_NEIGHBOR_REPORT_RSP_NOTIF: +		iwl_mvm_tof_nb_report_notif(mvm, resp->data); +		break; +	default: +	       IWL_ERR(mvm, "Unknown sub-group command 0x%x\n", +		       resp->sub_grp_cmd_id); +	       break; +	} +} diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.h b/drivers/net/wireless/iwlwifi/mvm/tof.h new file mode 100644 index 000000000000..50ae8adaaa6e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license.  When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <[email protected]> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + *  * Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + *  * Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + *  * Neither the name Intel Corporation nor the names of its + *    contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __tof +#define __tof_h__ + +#include "fw-api-tof.h" + +struct iwl_mvm_tof_data { +	struct iwl_tof_config_cmd tof_cfg; +	struct iwl_tof_range_req_cmd range_req; +	struct iwl_tof_range_req_ext_cmd range_req_ext; +#ifdef CONFIG_IWLWIFI_DEBUGFS +	struct iwl_tof_responder_config_cmd responder_cfg; +#endif +	struct iwl_tof_range_rsp_ntfy range_resp; +	u8 last_abort_id; +	u16 active_range_request; +}; + +void iwl_mvm_tof_init(struct iwl_mvm *mvm); +void iwl_mvm_tof_clean(struct iwl_mvm *mvm); +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm); +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id); +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, +				  struct ieee80211_vif *vif); +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, +			      struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, +				      struct ieee80211_vif *vif); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, +			      struct ieee80211_vif *vif); +#endif +#endif /* __tof_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 80d07db6e7e8..fe7145c2c98a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -33,6 +33,7 @@   *   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -154,24 +155,20 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,  	return true;  } -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, -		       struct iwl_rx_cmd_buffer *rxb, -		       struct iwl_device_cmd *cmd) +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	int temp;  	/* the notification is handled synchronously in ctkill, so skip here */  	if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) -		return 0; +		return;  	temp = iwl_mvm_temp_notif_parse(mvm, pkt);  	if (temp < 0) -		return 0; +		return;  	iwl_mvm_tt_temp_changed(mvm, temp); - -	return 0;  }  static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) @@ -187,7 +184,7 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)  int iwl_mvm_get_temp(struct iwl_mvm *mvm)  {  	struct iwl_notification_wait wait_temp_notif; -	static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; +	static const u16 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION };  	int ret, temp;  	lockdep_assert_held(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 7ba7a118ff5c..6df5aada4f16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -153,18 +153,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (ieee80211_is_mgmt(fc)) {  		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) -			tx_cmd->pm_frame_timeout = cpu_to_le16(3); +			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); +		else if (ieee80211_is_action(fc)) +			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);  		else -			tx_cmd->pm_frame_timeout = cpu_to_le16(2); +			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);  		/* The spec allows Action frames in A-MPDU, we don't support  		 * it  		 */  		WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);  	} else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { -		tx_cmd->pm_frame_timeout = cpu_to_le16(2); +		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);  	} else { -		tx_cmd->pm_frame_timeout = 0; +		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);  	}  	if (ieee80211_is_data(fc) && len > mvm->rts_threshold && @@ -252,7 +254,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,  	if (info->band == IEEE80211_BAND_2GHZ &&  	    !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) -		rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; +		rate_flags = mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS;  	else  		rate_flags =  			BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; @@ -268,19 +270,29 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,  /*   * Sets the fields in the Tx cmd that are crypto related   */ -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, -			       struct ieee80211_tx_info *info, -			       struct iwl_tx_cmd *tx_cmd, -			       struct sk_buff *skb_frag) +static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, +				      struct ieee80211_tx_info *info, +				      struct iwl_tx_cmd *tx_cmd, +				      struct sk_buff *skb_frag, +				      int hdrlen)  {  	struct ieee80211_key_conf *keyconf = info->control.hw_key; +	u8 *crypto_hdr = skb_frag->data + hdrlen; +	u64 pn;  	switch (keyconf->cipher) {  	case WLAN_CIPHER_SUITE_CCMP: -		tx_cmd->sec_ctl = TX_CMD_SEC_CCM; -		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); -		if (info->flags & IEEE80211_TX_CTL_AMPDU) -			tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); +	case WLAN_CIPHER_SUITE_CCMP_256: +		iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); +		pn = atomic64_inc_return(&keyconf->tx_pn); +		crypto_hdr[0] = pn; +		crypto_hdr[2] = 0; +		crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6); +		crypto_hdr[1] = pn >> 8; +		crypto_hdr[4] = pn >> 16; +		crypto_hdr[5] = pn >> 24; +		crypto_hdr[6] = pn >> 32; +		crypto_hdr[7] = pn >> 40;  		break;  	case WLAN_CIPHER_SUITE_TKIP: @@ -308,7 +320,7 @@ void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,   */  static struct iwl_device_cmd *  iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, -		      struct ieee80211_sta *sta, u8 sta_id) +		      int hdrlen, struct ieee80211_sta *sta, u8 sta_id)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -325,7 +337,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,  	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;  	if (info->control.hw_key) -		iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb); +		iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen);  	iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); @@ -346,6 +358,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)  	struct iwl_device_cmd *dev_cmd;  	struct iwl_tx_cmd *tx_cmd;  	u8 sta_id; +	int hdrlen = ieee80211_hdrlen(hdr->frame_control);  	if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU))  		return -1; @@ -366,23 +379,34 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)  		IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;  	/* -	 * If the interface on which frame is sent is the P2P_DEVICE +	 * If the interface on which the frame is sent is the P2P_DEVICE  	 * or an AP/GO interface use the broadcast station associated -	 * with it; otherwise use the AUX station. +	 * with it; otherwise if the interface is a managed interface +	 * use the AP station associated with it for multicast traffic +	 * (this is not possible for unicast packets as a TLDS discovery +	 * response are sent without a station entry); otherwise use the +	 * AUX station.  	 */ -	if (info->control.vif && -	    (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || -	     info->control.vif->type == NL80211_IFTYPE_AP)) { +	sta_id = mvm->aux_sta.sta_id; +	if (info->control.vif) {  		struct iwl_mvm_vif *mvmvif =  			iwl_mvm_vif_from_mac80211(info->control.vif); -		sta_id = mvmvif->bcast_sta.sta_id; -	} else { -		sta_id = mvm->aux_sta.sta_id; + +		if (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || +		    info->control.vif->type == NL80211_IFTYPE_AP) +			sta_id = mvmvif->bcast_sta.sta_id; +		else if (info->control.vif->type == NL80211_IFTYPE_STATION && +			 is_multicast_ether_addr(hdr->addr1)) { +			u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); + +			if (ap_sta_id != IWL_MVM_STATION_COUNT) +				sta_id = ap_sta_id; +		}  	}  	IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); -	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); +	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, NULL, sta_id);  	if (!dev_cmd)  		return -1; @@ -390,7 +414,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)  	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;  	/* Copy MAC header from skb into command buffer */ -	memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); +	memcpy(tx_cmd->hdr, hdr, hdrlen);  	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) {  		iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); @@ -416,9 +440,11 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,  	u8 tid = IWL_MAX_TID_COUNT;  	u8 txq_id = info->hw_queue;  	bool is_data_qos = false, is_ampdu = false; +	int hdrlen;  	mvmsta = iwl_mvm_sta_from_mac80211(sta);  	fc = hdr->frame_control; +	hdrlen = ieee80211_hdrlen(fc);  	if (WARN_ON_ONCE(!mvmsta))  		return -1; @@ -426,7 +452,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))  		return -1; -	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); +	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, sta, mvmsta->sta_id);  	if (!dev_cmd)  		goto drop; @@ -458,7 +484,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,  	}  	/* Copy MAC header from skb into command buffer */ -	memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); +	memcpy(tx_cmd->hdr, hdr, hdrlen);  	WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); @@ -911,8 +937,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,  	rcu_read_unlock();  } -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -		      struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; @@ -921,8 +946,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		iwl_mvm_rx_tx_cmd_single(mvm, pkt);  	else  		iwl_mvm_rx_tx_cmd_agg(mvm, pkt); - -	return 0;  }  static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, @@ -942,8 +965,7 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,  		(void *)(uintptr_t)tid_data->rate_n_flags;  } -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			struct iwl_device_cmd *cmd) +void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; @@ -965,7 +987,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT ||  		      tid >= IWL_MAX_TID_COUNT,  		      "sta_id %d tid %d", sta_id, tid)) -		return 0; +		return;  	rcu_read_lock(); @@ -974,7 +996,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  	/* Reclaiming frames for a station that has been deleted ? */  	if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {  		rcu_read_unlock(); -		return 0; +		return;  	}  	mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -985,7 +1007,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  			"invalid BA notification: Q %d, tid %d, flow %d\n",  			tid_data->txq_id, tid, scd_flow);  		rcu_read_unlock(); -		return 0; +		return;  	}  	spin_lock_bh(&mvmsta->lock); @@ -1072,8 +1094,6 @@ out:  		skb = __skb_dequeue(&reclaimed_skbs);  		ieee80211_tx_status(mvm->hw, skb);  	} - -	return 0;  }  /* diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 03f8e06dded7..a7d434256423 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -108,7 +108,7 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)  	return ret;  } -int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,  			 u32 flags, u16 len, const void *data)  {  	struct iwl_host_cmd cmd = { @@ -166,11 +166,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,  		goto out_free_resp;  	} -	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { -		ret = -EIO; -		goto out_free_resp; -	} -  	resp_len = iwl_rx_packet_payload_len(pkt);  	if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {  		ret = -EIO; @@ -187,7 +182,7 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,  /*   * We assume that the caller set the status to the sucess value   */ -int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len, +int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,  				const void *data, u32 *status)  {  	struct iwl_host_cmd cmd = { @@ -243,8 +238,7 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)  	return fw_rate_idx_to_plcp[rate_idx];  } -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, -			  struct iwl_device_cmd *cmd) +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -256,7 +250,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,  		le32_to_cpu(err_resp->error_service));  	IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n",  		le64_to_cpu(err_resp->timestamp)); -	return 0;  }  /* diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2ed1e4d2774d..b0825c402c73 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -368,12 +368,14 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  /* 3165 Series */  	{IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3166, 0x4212, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)},  	{IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)},  /* 7265 Series */  	{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, @@ -426,9 +428,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {  	{IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, +	{IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, -	{IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)}, -	{IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},  	{IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, @@ -613,6 +614,7 @@ static int iwl_pci_resume(struct device *device)  {  	struct pci_dev *pdev = to_pci_dev(device);  	struct iwl_trans *trans = pci_get_drvdata(pdev); +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill;  	/* Before you put code here, think about WoWLAN. You cannot check here @@ -630,20 +632,16 @@ static int iwl_pci_resume(struct device *device)  		return 0;  	/* -	 * On suspend, ict is disabled, and the interrupt mask -	 * gets cleared. Reconfigure them both in case of d0i3 -	 * image. Otherwise, only enable rfkill interrupt (in -	 * order to keep track of the rfkill status) +	 * Enable rfkill interrupt (in order to keep track of +	 * the rfkill status)  	 */ -	if (trans->wowlan_d0i3) { -		iwl_pcie_reset_ict(trans); -		iwl_enable_interrupts(trans); -	} else { -		iwl_enable_rfkill_int(trans); -	} +	iwl_enable_rfkill_int(trans);  	hw_rfkill = iwl_is_rfkill_set(trans); + +	mutex_lock(&trans_pcie->mutex);  	iwl_trans_pcie_rf_kill(trans, hw_rfkill); +	mutex_unlock(&trans_pcie->mutex);  	return 0;  } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 31f72a61cc3f..feb2f7e81134 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -44,6 +44,12 @@  #include "iwl-io.h"  #include "iwl-op-mode.h" +/* We need 2 entries for the TX command and header, and another one might + * be needed for potential data in the SKB's head. The remaining ones can + * be used for frags. + */ +#define IWL_PCIE_MAX_FRAGS (IWL_NUM_OF_TBS - 3) +  /*   * RX related structures and functions   */ @@ -299,8 +305,10 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)   * @rx_buf_size_8k: 8 kB RX buffer size   * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)   * @scd_set_active: should the transport configure the SCD for HCMD queue + * @wide_cmd_header: true when ucode supports wide command header format   * @rx_page_order: page order for receive buffer size   * @reg_lock: protect hw register access + * @mutex: to protect stop_device / start_fw / start_hw   * @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 @@ -320,9 +328,11 @@ struct iwl_trans_pcie {  	dma_addr_t ict_tbl_dma;  	int ict_index;  	bool use_ict; +	bool is_down;  	struct isr_statistics isr_stats;  	spinlock_t irq_lock; +	struct mutex mutex;  	u32 inta_mask;  	u32 scd_base_addr;  	struct iwl_dma_ptr scd_bc_tbls; @@ -349,6 +359,7 @@ struct iwl_trans_pcie {  	bool rx_buf_size_8k;  	bool bc_table_dword;  	bool scd_set_active; +	bool wide_cmd_header;  	u32 rx_page_order;  	const char *const *command_names; @@ -420,7 +431,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);  int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);  void iwl_pcie_hcmd_complete(struct iwl_trans *trans, -			    struct iwl_rx_cmd_buffer *rxb, int handler_status); +			    struct iwl_rx_cmd_buffer *rxb);  void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,  			    struct sk_buff_head *skbs);  void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a3fbaa0ef5e0..e06591f625c4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -281,12 +281,13 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)   * iwl_pcie_rx_alloc_page - allocates and returns a page.   *   */ -static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans) +static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, +					   gfp_t priority)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rxq *rxq = &trans_pcie->rxq;  	struct page *page; -	gfp_t gfp_mask = GFP_KERNEL; +	gfp_t gfp_mask = priority;  	if (rxq->free_count > RX_LOW_WATERMARK)  		gfp_mask |= __GFP_NOWARN; @@ -324,7 +325,7 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)   * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly   * allocated buffers.   */ -static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans) +static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rxq *rxq = &trans_pcie->rxq; @@ -340,7 +341,7 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)  		spin_unlock(&rxq->lock);  		/* Alloc a new receive buffer */ -		page = iwl_pcie_rx_alloc_page(trans); +		page = iwl_pcie_rx_alloc_page(trans, priority);  		if (!page)  			return; @@ -414,7 +415,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)   */  static void iwl_pcie_rx_replenish(struct iwl_trans *trans)  { -	iwl_pcie_rxq_alloc_rbs(trans); +	iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);  	iwl_pcie_rxq_restock(trans);  } @@ -429,17 +430,22 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rb_allocator *rba = &trans_pcie->rba; +	struct list_head local_empty; +	int pending = atomic_xchg(&rba->req_pending, 0); -	while (atomic_read(&rba->req_pending)) { +	IWL_DEBUG_RX(trans, "Pending allocation requests = %d\n", pending); + +	/* If we were scheduled - there is at least one request */ +	spin_lock(&rba->lock); +	/* swap out the rba->rbd_empty to a local list */ +	list_replace_init(&rba->rbd_empty, &local_empty); +	spin_unlock(&rba->lock); + +	while (pending) {  		int i; -		struct list_head local_empty;  		struct list_head local_allocated;  		INIT_LIST_HEAD(&local_allocated); -		spin_lock(&rba->lock); -		/* swap out the entire rba->rbd_empty to a local list */ -		list_replace_init(&rba->rbd_empty, &local_empty); -		spin_unlock(&rba->lock);  		for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {  			struct iwl_rx_mem_buffer *rxb; @@ -457,7 +463,7 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)  			BUG_ON(rxb->page);  			/* Alloc a new receive buffer */ -			page = iwl_pcie_rx_alloc_page(trans); +			page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL);  			if (!page)  				continue;  			rxb->page = page; @@ -481,16 +487,28 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)  			i++;  		} +		pending--; +		if (!pending) { +			pending = atomic_xchg(&rba->req_pending, 0); +			IWL_DEBUG_RX(trans, +				     "Pending allocation requests = %d\n", +				     pending); +		} +  		spin_lock(&rba->lock);  		/* add the allocated rbds to the allocator allocated list */  		list_splice_tail(&local_allocated, &rba->rbd_allocated); -		/* add the unused rbds back to the allocator empty list */ -		list_splice_tail(&local_empty, &rba->rbd_empty); +		/* get more empty RBDs for current pending requests */ +		list_splice_tail_init(&rba->rbd_empty, &local_empty);  		spin_unlock(&rba->lock); -		atomic_dec(&rba->req_pending);  		atomic_inc(&rba->req_ready);  	} + +	spin_lock(&rba->lock); +	/* return unused rbds to the allocator empty list */ +	list_splice_tail(&local_empty, &rba->rbd_empty); +	spin_unlock(&rba->lock);  }  /* @@ -507,13 +525,16 @@ static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,  	struct iwl_rb_allocator *rba = &trans_pcie->rba;  	int i; -	if (atomic_dec_return(&rba->req_ready) < 0) { -		atomic_inc(&rba->req_ready); -		IWL_DEBUG_RX(trans, -			     "Allocation request not ready, pending requests = %d\n", -			     atomic_read(&rba->req_pending)); +	/* +	 * atomic_dec_if_positive returns req_ready - 1 for any scenario. +	 * If req_ready is 0 atomic_dec_if_positive will return -1 and this +	 * function will return -ENOMEM, as there are no ready requests. +	 * atomic_dec_if_positive will perofrm the *actual* decrement only if +	 * req_ready > 0, i.e. - there are ready requests and the function +	 * hands one request to the caller. +	 */ +	if (atomic_dec_if_positive(&rba->req_ready) < 0)  		return -ENOMEM; -	}  	spin_lock(&rba->lock);  	for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) { @@ -777,18 +798,21 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)   */  static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,  				  struct iwl_rx_mem_buffer *rxb, -				  struct iwl_rxq *rxq) +				  struct iwl_rxq *rxq, bool emergency)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rb_allocator *rba = &trans_pcie->rba; -	/* Count the used RBDs */ -	rxq->used_count++; -  	/* Move the RBD to the used list, will be moved to allocator in batches  	 * before claiming or posting a request*/  	list_add_tail(&rxb->list, &rxq->rx_used); +	if (unlikely(emergency)) +		return; + +	/* Count the allocator owned RBDs */ +	rxq->used_count++; +  	/* If we have RX_POST_REQ_ALLOC new released rx buffers -  	 * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is  	 * used for the case we failed to claim RX_CLAIM_REQ_ALLOC, @@ -807,7 +831,8 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,  }  static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, -				struct iwl_rx_mem_buffer *rxb) +				struct iwl_rx_mem_buffer *rxb, +				bool emergency)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rxq *rxq = &trans_pcie->rxq; @@ -823,10 +848,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  	while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {  		struct iwl_rx_packet *pkt; -		struct iwl_device_cmd *cmd;  		u16 sequence;  		bool reclaim; -		int index, cmd_index, err, len; +		int index, cmd_index, len;  		struct iwl_rx_cmd_buffer rxcb = {  			._offset = offset,  			._rx_page_order = trans_pcie->rx_page_order, @@ -874,12 +898,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  		index = SEQ_TO_INDEX(sequence);  		cmd_index = get_cmd_index(&txq->q, index); -		if (reclaim) -			cmd = txq->entries[cmd_index].cmd; -		else -			cmd = NULL; - -		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); +		iwl_op_mode_rx(trans->op_mode, &trans_pcie->napi, &rxcb);  		if (reclaim) {  			kzfree(txq->entries[cmd_index].free_buf); @@ -897,7 +916,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  			 * iwl_trans_send_cmd()  			 * as we reclaim the driver command queue */  			if (!rxcb._page_stolen) -				iwl_pcie_hcmd_complete(trans, &rxcb, err); +				iwl_pcie_hcmd_complete(trans, &rxcb);  			else  				IWL_WARN(trans, "Claim null rxb?\n");  		} @@ -928,13 +947,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,  			 */  			__free_pages(rxb->page, trans_pcie->rx_page_order);  			rxb->page = NULL; -			iwl_pcie_rx_reuse_rbd(trans, rxb, rxq); +			iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency);  		} else {  			list_add_tail(&rxb->list, &rxq->rx_free);  			rxq->free_count++;  		}  	} else -		iwl_pcie_rx_reuse_rbd(trans, rxb, rxq); +		iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency);  }  /* @@ -944,7 +963,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_rxq *rxq = &trans_pcie->rxq; -	u32 r, i, j; +	u32 r, i, j, count = 0; +	bool emergency = false;  restart:  	spin_lock(&rxq->lock); @@ -960,12 +980,15 @@ restart:  	while (i != r) {  		struct iwl_rx_mem_buffer *rxb; +		if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2)) +			emergency = true; +  		rxb = rxq->queue[i];  		rxq->queue[i] = NULL;  		IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",  			     r, i, rxb); -		iwl_pcie_rx_handle_rb(trans, rxb); +		iwl_pcie_rx_handle_rb(trans, rxb, emergency);  		i = (i + 1) & RX_QUEUE_MASK; @@ -975,10 +998,16 @@ restart:  			struct iwl_rb_allocator *rba = &trans_pcie->rba;  			struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC]; -			/* Add the remaining 6 empty RBDs for allocator use */ -			spin_lock(&rba->lock); -			list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); -			spin_unlock(&rba->lock); +			if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && +			    !emergency) { +				/* Add the remaining 6 empty RBDs +				* for allocator use +				 */ +				spin_lock(&rba->lock); +				list_splice_tail_init(&rxq->rx_used, +						      &rba->rbd_empty); +				spin_unlock(&rba->lock); +			}  			/* If not ready - continue, will try to reclaim later.  			* No need to reschedule work - allocator exits only on @@ -995,9 +1024,22 @@ restart:  				}  			}  		} -		/* handle restock for two cases: +		if (emergency) { +			count++; +			if (count == 8) { +				count = 0; +				if (rxq->used_count < RX_QUEUE_SIZE / 3) +					emergency = false; +				spin_unlock(&rxq->lock); +				iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); +				spin_lock(&rxq->lock); +			} +		} +		/* handle restock for three cases, can be all of them at once:  		* - we just pulled buffers from the allocator -		* - we have 8+ unstolen pages accumulated */ +		* - we have 8+ unstolen pages accumulated +		* - we are in emergency and allocated buffers +		 */  		if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {  			rxq->read = i;  			spin_unlock(&rxq->lock); @@ -1010,6 +1052,21 @@ restart:  	rxq->read = i;  	spin_unlock(&rxq->lock); +	/* +	 * handle a case where in emergency there are some unallocated RBDs. +	 * those RBDs are in the used list, but are not tracked by the queue's +	 * used_count which counts allocator owned RBDs. +	 * unallocated emergency RBDs must be allocated on exit, otherwise +	 * when called again the function may not be in emergency mode and +	 * they will be handed to the allocator with no tracking in the RBD +	 * allocator counters, which will lead to them never being claimed back +	 * by the queue. +	 * by allocating them here, they are now in the queue free list, and +	 * will be restocked by the next call of iwl_pcie_rxq_restock. +	 */ +	if (unlikely(emergency && count)) +		iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); +  	if (trans_pcie->napi.poll)  		napi_gro_flush(&trans_pcie->napi, false);  } @@ -1020,6 +1077,7 @@ restart:  static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	int i;  	/* W/A for WiFi/WiMAX coex and WiMAX own the RF */  	if (trans->cfg->internal_wimax_coex && @@ -1043,6 +1101,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)  	iwl_trans_fw_error(trans);  	local_bh_enable(); +	for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) +		del_timer(&trans_pcie->txq[i].stuck_timer); +  	clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);  	wake_up(&trans_pcie->wait_command_queue);  } @@ -1251,7 +1312,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)  		isr_stats->rfkill++; +		mutex_lock(&trans_pcie->mutex);  		iwl_trans_pcie_rf_kill(trans, hw_rfkill); +		mutex_unlock(&trans_pcie->mutex);  		if (hw_rfkill) {  			set_bit(STATUS_RFKILL, &trans->status);  			if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, @@ -1443,8 +1506,9 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)  	val = trans_pcie->ict_tbl_dma >> ICT_SHIFT; -	val |= CSR_DRAM_INT_TBL_ENABLE; -	val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; +	val |= CSR_DRAM_INT_TBL_ENABLE | +	       CSR_DRAM_INIT_TBL_WRAP_CHECK | +	       CSR_DRAM_INIT_TBL_WRITE_POINTER;  	IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 43ae658af6ec..6ba7d300b08f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -182,7 +182,7 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)  static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)  { -	if (!trans->cfg->apmg_not_supported) +	if (trans->cfg->apmg_not_supported)  		return;  	if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) @@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)  		if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)  			iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,  					  APMG_PCIDEV_STT_VAL_WAKE_ME); -		else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) +		else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { +			iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, +				    CSR_RESET_LINK_PWR_MGMT_DISABLED);  			iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,  				    CSR_HW_IF_CONFIG_REG_PREPARE |  				    CSR_HW_IF_CONFIG_REG_ENABLE_PME); +			mdelay(1); +			iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, +				      CSR_RESET_LINK_PWR_MGMT_DISABLED); +		}  		mdelay(5);  	} @@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)  	if (ret >= 0)  		return 0; +	iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, +		    CSR_RESET_LINK_PWR_MGMT_DISABLED); +	msleep(1); +  	for (iter = 0; iter < 10; iter++) {  		/* If HW is not ready, prepare the conditions to check again */  		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)  		do {  			ret = iwl_pcie_set_hw_ready(trans); -			if (ret >= 0) -				return 0; +			if (ret >= 0) { +				ret = 0; +				goto out; +			}  			usleep_range(200, 1000);  			t += 200; @@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)  	IWL_ERR(trans, "Couldn't prepare the card\n"); +out: +	iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, +		      CSR_RESET_LINK_PWR_MGMT_DISABLED); +  	return ret;  } @@ -764,8 +780,15 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans,  	for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {  		last_read_idx = i; +		/* +		 * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between +		 * CPU1 to CPU2. +		 * PAGING_SEPARATOR_SECTION delimiter - separate between +		 * CPU2 non paged to CPU2 paging sec. +		 */  		if (!image->sec[i].data || -		    image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { +		    image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || +		    image->sec[i].offset == PAGING_SEPARATOR_SECTION) {  			IWL_DEBUG_FW(trans,  				     "Break since Data not valid or Empty section, sec = %d\n",  				     i); @@ -813,8 +836,15 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,  	for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {  		last_read_idx = i; +		/* +		 * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between +		 * CPU1 to CPU2. +		 * PAGING_SEPARATOR_SECTION delimiter - separate between +		 * CPU2 non paged to CPU2 paging sec. +		 */  		if (!image->sec[i].data || -		    image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { +		    image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || +		    image->sec[i].offset == PAGING_SEPARATOR_SECTION) {  			IWL_DEBUG_FW(trans,  				     "Break since Data not valid or Empty section, sec = %d\n",  				     i); @@ -881,6 +911,14 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)  		case PRPH_CLEARBIT:  			iwl_clear_bits_prph(trans, addr, BIT(val));  			break; +		case PRPH_BLOCKBIT: +			if (iwl_read_prph(trans, addr) & BIT(val)) { +				IWL_ERR(trans, +					"BIT(%u) in address 0x%x is 1, stopping FW configuration\n", +					val, addr); +				goto monitor; +			} +			break;  		default:  			IWL_ERR(trans, "FW debug - unknown OP %d\n",  				dest->reg_ops[i].op); @@ -888,6 +926,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)  		}  	} +monitor:  	if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {  		iwl_write_prph(trans, le32_to_cpu(dest->base_reg),  			       trans_pcie->fw_mon_phys >> dest->base_shift); @@ -982,13 +1021,25 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,  static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  				   const struct fw_img *fw, bool run_in_rfkill)  { -	int ret; +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill; +	int ret; + +	mutex_lock(&trans_pcie->mutex); + +	/* Someone called stop_device, don't try to start_fw */ +	if (trans_pcie->is_down) { +		IWL_WARN(trans, +			 "Can't start_fw since the HW hasn't been started\n"); +		ret = EIO; +		goto out; +	}  	/* This may fail if AMT took ownership of the device */  	if (iwl_pcie_prepare_card_hw(trans)) {  		IWL_WARN(trans, "Exit HW not ready\n"); -		return -EIO; +		ret = -EIO; +		goto out;  	}  	iwl_enable_rfkill_int(trans); @@ -1000,15 +1051,17 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  	else  		clear_bit(STATUS_RFKILL, &trans->status);  	iwl_trans_pcie_rf_kill(trans, hw_rfkill); -	if (hw_rfkill && !run_in_rfkill) -		return -ERFKILL; +	if (hw_rfkill && !run_in_rfkill) { +		ret = -ERFKILL; +		goto out; +	}  	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);  	ret = iwl_pcie_nic_init(trans);  	if (ret) {  		IWL_ERR(trans, "Unable to init nic\n"); -		return ret; +		goto out;  	}  	/* make sure rfkill handshake bits are cleared */ @@ -1026,9 +1079,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,  	/* Load the given image to the HW */  	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) -		return iwl_pcie_load_given_ucode_8000(trans, fw); +		ret = iwl_pcie_load_given_ucode_8000(trans, fw);  	else -		return iwl_pcie_load_given_ucode(trans, fw); +		ret = iwl_pcie_load_given_ucode(trans, fw); + +out: +	mutex_unlock(&trans_pcie->mutex); +	return ret;  }  static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) @@ -1037,11 +1094,18 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)  	iwl_pcie_tx_start(trans, scd_addr);  } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill, was_hw_rfkill; +	lockdep_assert_held(&trans_pcie->mutex); + +	if (trans_pcie->is_down) +		return; + +	trans_pcie->is_down = true; +  	was_hw_rfkill = iwl_is_rfkill_set(trans);  	/* tell the device to stop sending interrupts */ @@ -1131,14 +1195,36 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)  	iwl_pcie_prepare_card_hw(trans);  } +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +{ +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +	mutex_lock(&trans_pcie->mutex); +	_iwl_trans_pcie_stop_device(trans, low_power); +	mutex_unlock(&trans_pcie->mutex); +} +  void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)  { +	struct iwl_trans_pcie __maybe_unused *trans_pcie = +		IWL_TRANS_GET_PCIE_TRANS(trans); + +	lockdep_assert_held(&trans_pcie->mutex); +  	if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) -		iwl_trans_pcie_stop_device(trans, true); +		_iwl_trans_pcie_stop_device(trans, true);  }  static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +	if (trans->wowlan_d0i3) { +		/* Enable persistence mode to avoid reset */ +		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, +			    CSR_HW_IF_CONFIG_REG_PERSIST_MODE); +	} +  	iwl_disable_interrupts(trans);  	/* @@ -1150,17 +1236,21 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)  	iwl_pcie_disable_ict(trans); +	synchronize_irq(trans_pcie->pci_dev->irq); +  	iwl_clear_bit(trans, CSR_GP_CNTRL,  		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);  	iwl_clear_bit(trans, CSR_GP_CNTRL,  		      CSR_GP_CNTRL_REG_FLAG_INIT_DONE); -	/* -	 * reset TX queues -- some of their registers reset during S3 -	 * so if we don't reset everything here the D3 image would try -	 * to execute some invalid memory upon resume -	 */ -	iwl_trans_pcie_tx_reset(trans); +	if (!trans->wowlan_d0i3) { +		/* +		 * reset TX queues -- some of their registers reset during S3 +		 * so if we don't reset everything here the D3 image would try +		 * to execute some invalid memory upon resume +		 */ +		iwl_trans_pcie_tx_reset(trans); +	}  	iwl_pcie_set_pwr(trans, true);  } @@ -1202,12 +1292,18 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,  	iwl_pcie_set_pwr(trans, false); -	iwl_trans_pcie_tx_reset(trans); +	if (trans->wowlan_d0i3) { +		iwl_clear_bit(trans, CSR_GP_CNTRL, +			      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +	} else { +		iwl_trans_pcie_tx_reset(trans); -	ret = iwl_pcie_rx_init(trans); -	if (ret) { -		IWL_ERR(trans, "Failed to resume the device (RX reset)\n"); -		return ret; +		ret = iwl_pcie_rx_init(trans); +		if (ret) { +			IWL_ERR(trans, +				"Failed to resume the device (RX reset)\n"); +			return ret; +		}  	}  	val = iwl_read32(trans, CSR_RESET); @@ -1219,11 +1315,14 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,  	return 0;  } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)  { +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	bool hw_rfkill;  	int err; +	lockdep_assert_held(&trans_pcie->mutex); +  	err = iwl_pcie_prepare_card_hw(trans);  	if (err) {  		IWL_ERR(trans, "Error while preparing HW: %d\n", err); @@ -1240,20 +1339,38 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)  	/* From now on, the op_mode will be kept updated about RF kill state */  	iwl_enable_rfkill_int(trans); +	/* Set is_down to false here so that...*/ +	trans_pcie->is_down = false; +  	hw_rfkill = iwl_is_rfkill_set(trans);  	if (hw_rfkill)  		set_bit(STATUS_RFKILL, &trans->status);  	else  		clear_bit(STATUS_RFKILL, &trans->status); +	/* ... rfkill can call stop_device and set it false if needed */  	iwl_trans_pcie_rf_kill(trans, hw_rfkill);  	return 0;  } +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	int ret; + +	mutex_lock(&trans_pcie->mutex); +	ret = _iwl_trans_pcie_start_hw(trans, low_power); +	mutex_unlock(&trans_pcie->mutex); + +	return ret; +} +  static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	mutex_lock(&trans_pcie->mutex); +  	/* disable interrupts - don't enable HW RF kill interrupt */  	spin_lock(&trans_pcie->irq_lock);  	iwl_disable_interrupts(trans); @@ -1266,6 +1383,10 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)  	spin_unlock(&trans_pcie->irq_lock);  	iwl_pcie_disable_ict(trans); + +	mutex_unlock(&trans_pcie->mutex); + +	synchronize_irq(trans_pcie->pci_dev->irq);  }  static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -1326,6 +1447,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,  	else  		trans_pcie->rx_page_order = get_order(4 * 1024); +	trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header;  	trans_pcie->command_names = trans_cfg->command_names;  	trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;  	trans_pcie->scd_set_active = trans_cfg->scd_set_active; @@ -1338,11 +1460,10 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,  	 * As this function may be called again in some corner cases don't  	 * do anything if NAPI was already initialized.  	 */ -	if (!trans_pcie->napi.poll && trans->op_mode->ops->napi_add) { +	if (!trans_pcie->napi.poll) {  		init_dummy_netdev(&trans_pcie->napi_dev); -		iwl_op_mode_napi_add(trans->op_mode, &trans_pcie->napi, -				     &trans_pcie->napi_dev, -				     iwl_pcie_dummy_napi_poll, 64); +		netif_napi_add(&trans_pcie->napi_dev, &trans_pcie->napi, +			       iwl_pcie_dummy_napi_poll, 64);  	}  } @@ -2169,6 +2290,47 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans,  	return prph_len;  } +static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, +				   struct iwl_fw_error_dump_data **data, +				   int allocated_rb_nums) +{ +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	int max_len = PAGE_SIZE << trans_pcie->rx_page_order; +	struct iwl_rxq *rxq = &trans_pcie->rxq; +	u32 i, r, j, rb_len = 0; + +	spin_lock(&rxq->lock); + +	r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; + +	for (i = rxq->read, j = 0; +	     i != r && j < allocated_rb_nums; +	     i = (i + 1) & RX_QUEUE_MASK, j++) { +		struct iwl_rx_mem_buffer *rxb = rxq->queue[i]; +		struct iwl_fw_error_dump_rb *rb; + +		dma_unmap_page(trans->dev, rxb->page_dma, max_len, +			       DMA_FROM_DEVICE); + +		rb_len += sizeof(**data) + sizeof(*rb) + max_len; + +		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RB); +		(*data)->len = cpu_to_le32(sizeof(*rb) + max_len); +		rb = (void *)(*data)->data; +		rb->index = cpu_to_le32(i); +		memcpy(rb->data, page_address(rxb->page), max_len); +		/* remap the page for the free benefit */ +		rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, +						     max_len, +						     DMA_FROM_DEVICE); + +		*data = iwl_fw_error_next_data(*data); +	} + +	spin_unlock(&rxq->lock); + +	return rb_len; +}  #define IWL_CSR_TO_DUMP (0x250)  static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, @@ -2238,17 +2400,97 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,  	return monitor_len;  } -static -struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) +static u32 +iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, +			    struct iwl_fw_error_dump_data **data, +			    u32 monitor_len) +{ +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	u32 len = 0; + +	if ((trans_pcie->fw_mon_page && +	     trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || +	    trans->dbg_dest_tlv) { +		struct iwl_fw_error_dump_fw_mon *fw_mon_data; +		u32 base, write_ptr, wrap_cnt; + +		/* If there was a dest TLV - use the values from there */ +		if (trans->dbg_dest_tlv) { +			write_ptr = +				le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); +			wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); +			base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); +		} else { +			base = MON_BUFF_BASE_ADDR; +			write_ptr = MON_BUFF_WRPTR; +			wrap_cnt = MON_BUFF_CYCLE_CNT; +		} + +		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); +		fw_mon_data = (void *)(*data)->data; +		fw_mon_data->fw_mon_wr_ptr = +			cpu_to_le32(iwl_read_prph(trans, write_ptr)); +		fw_mon_data->fw_mon_cycle_cnt = +			cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); +		fw_mon_data->fw_mon_base_ptr = +			cpu_to_le32(iwl_read_prph(trans, base)); + +		len += sizeof(**data) + sizeof(*fw_mon_data); +		if (trans_pcie->fw_mon_page) { +			/* +			 * 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); + +			monitor_len = trans_pcie->fw_mon_size; +		} else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { +			/* +			 * Update pointers to reflect actual values after +			 * shifting +			 */ +			base = iwl_read_prph(trans, base) << +			       trans->dbg_dest_tlv->base_shift; +			iwl_trans_read_mem(trans, base, fw_mon_data->data, +					   monitor_len / sizeof(u32)); +		} else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { +			monitor_len = +				iwl_trans_pci_dump_marbh_monitor(trans, +								 fw_mon_data, +								 monitor_len); +		} else { +			/* Didn't match anything - output no monitor data */ +			monitor_len = 0; +		} + +		len += monitor_len; +		(*data)->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); +	} + +	return len; +} + +static struct iwl_trans_dump_data +*iwl_trans_pcie_dump_data(struct iwl_trans *trans, +			  struct iwl_fw_dbg_trigger_tlv *trigger)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct iwl_fw_error_dump_data *data;  	struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];  	struct iwl_fw_error_dump_txcmd *txcmd;  	struct iwl_trans_dump_data *dump_data; -	u32 len; +	u32 len, num_rbs;  	u32 monitor_len;  	int i, ptr; +	bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status);  	/* transport dump header */  	len = sizeof(*dump_data); @@ -2257,22 +2499,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)  	len += sizeof(*data) +  		cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); -	/* CSR registers */ -	len += sizeof(*data) + IWL_CSR_TO_DUMP; - -	/* PRPH registers */ -	for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { -		/* The range includes both boundaries */ -		int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - -			iwl_prph_dump_addr[i].start + 4; - -		len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + -			num_bytes_in_chunk; -	} - -	/* FH registers */ -	len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); -  	/* FW monitor */  	if (trans_pcie->fw_mon_page) {  		len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + @@ -2300,6 +2526,45 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)  		monitor_len = 0;  	} +	if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) { +		dump_data = vzalloc(len); +		if (!dump_data) +			return NULL; + +		data = (void *)dump_data->data; +		len = iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); +		dump_data->len = len; + +		return dump_data; +	} + +	/* CSR registers */ +	len += sizeof(*data) + IWL_CSR_TO_DUMP; + +	/* PRPH registers */ +	for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { +		/* The range includes both boundaries */ +		int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - +			iwl_prph_dump_addr[i].start + 4; + +		len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + +		       num_bytes_in_chunk; +	} + +	/* FH registers */ +	len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + +	if (dump_rbs) { +		/* RBs */ +		num_rbs = le16_to_cpu(ACCESS_ONCE( +				      trans_pcie->rxq.rb_stts->closed_rb_num)) +				      & 0x0FFF; +		num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; +		len += num_rbs * (sizeof(*data) + +				  sizeof(struct iwl_fw_error_dump_rb) + +				  (PAGE_SIZE << trans_pcie->rx_page_order)); +	} +  	dump_data = vzalloc(len);  	if (!dump_data)  		return NULL; @@ -2336,74 +2601,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)  	len += iwl_trans_pcie_dump_prph(trans, &data);  	len += iwl_trans_pcie_dump_csr(trans, &data);  	len += iwl_trans_pcie_fh_regs_dump(trans, &data); -	/* data is already pointing to the next section */ - -	if ((trans_pcie->fw_mon_page && -	     trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || -	    trans->dbg_dest_tlv) { -		struct iwl_fw_error_dump_fw_mon *fw_mon_data; -		u32 base, write_ptr, wrap_cnt; - -		/* If there was a dest TLV - use the values from there */ -		if (trans->dbg_dest_tlv) { -			write_ptr = -				le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); -			wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); -			base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); -		} else { -			base = MON_BUFF_BASE_ADDR; -			write_ptr = MON_BUFF_WRPTR; -			wrap_cnt = MON_BUFF_CYCLE_CNT; -		} +	if (dump_rbs) +		len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); -		data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); -		fw_mon_data = (void *)data->data; -		fw_mon_data->fw_mon_wr_ptr = -			cpu_to_le32(iwl_read_prph(trans, write_ptr)); -		fw_mon_data->fw_mon_cycle_cnt = -			cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); -		fw_mon_data->fw_mon_base_ptr = -			cpu_to_le32(iwl_read_prph(trans, base)); - -		len += sizeof(*data) + sizeof(*fw_mon_data); -		if (trans_pcie->fw_mon_page) { -			/* -			 * 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); - -			monitor_len = trans_pcie->fw_mon_size; -		} else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { -			/* -			 * Update pointers to reflect actual values after -			 * shifting -			 */ -			base = iwl_read_prph(trans, base) << -			       trans->dbg_dest_tlv->base_shift; -			iwl_trans_read_mem(trans, base, fw_mon_data->data, -					   monitor_len / sizeof(u32)); -		} else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { -			monitor_len = -				iwl_trans_pci_dump_marbh_monitor(trans, -								 fw_mon_data, -								 monitor_len); -		} else { -			/* Didn't match anything - output no monitor data */ -			monitor_len = 0; -		} - -		len += monitor_len; -		data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); -	} +	len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len);  	dump_data->len = len; @@ -2459,23 +2660,26 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	struct iwl_trans_pcie *trans_pcie;  	struct iwl_trans *trans;  	u16 pci_cmd; -	int err; +	int ret;  	trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),  				&pdev->dev, cfg, &trans_ops_pcie, 0);  	if (!trans)  		return ERR_PTR(-ENOMEM); +	trans->max_skb_frags = IWL_PCIE_MAX_FRAGS; +  	trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	trans_pcie->trans = trans;  	spin_lock_init(&trans_pcie->irq_lock);  	spin_lock_init(&trans_pcie->reg_lock);  	spin_lock_init(&trans_pcie->ref_lock); +	mutex_init(&trans_pcie->mutex);  	init_waitqueue_head(&trans_pcie->ucode_write_waitq); -	err = pci_enable_device(pdev); -	if (err) +	ret = pci_enable_device(pdev); +	if (ret)  		goto out_no_pci;  	if (!cfg->base_params->pcie_l1_allowed) { @@ -2491,23 +2695,23 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	pci_set_master(pdev); -	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); -	if (!err) -		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); -	if (err) { -		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); -		if (!err) -			err = pci_set_consistent_dma_mask(pdev, +	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); +	if (!ret) +		ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); +	if (ret) { +		ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); +		if (!ret) +			ret = pci_set_consistent_dma_mask(pdev,  							  DMA_BIT_MASK(32));  		/* both attempts failed: */ -		if (err) { +		if (ret) {  			dev_err(&pdev->dev, "No suitable DMA available\n");  			goto out_pci_disable_device;  		}  	} -	err = pci_request_regions(pdev, DRV_NAME); -	if (err) { +	ret = pci_request_regions(pdev, DRV_NAME); +	if (ret) {  		dev_err(&pdev->dev, "pci_request_regions failed\n");  		goto out_pci_disable_device;  	} @@ -2515,7 +2719,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);  	if (!trans_pcie->hw_base) {  		dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); -		err = -ENODEV; +		ret = -ENODEV;  		goto out_pci_release_regions;  	} @@ -2527,9 +2731,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	trans_pcie->pci_dev = pdev;  	iwl_disable_interrupts(trans); -	err = pci_enable_msi(pdev); -	if (err) { -		dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err); +	ret = pci_enable_msi(pdev); +	if (ret) { +		dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret);  		/* enable rfkill interrupt: hw bug w/a */  		pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);  		if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { @@ -2547,11 +2751,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	 */  	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {  		unsigned long flags; -		int ret;  		trans->hw_rev = (trans->hw_rev & 0xfff0) |  				(CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); +		ret = iwl_pcie_prepare_card_hw(trans); +		if (ret) { +			IWL_WARN(trans, "Exit HW not ready\n"); +			goto out_pci_disable_msi; +		} +  		/*  		 * in-order to recognize C step driver should read chip version  		 * id located at the AUX bus MISC address space. @@ -2591,13 +2800,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,  	/* Initialize the wait queue for commands */  	init_waitqueue_head(&trans_pcie->wait_command_queue); -	if (iwl_pcie_alloc_ict(trans)) +	ret = iwl_pcie_alloc_ict(trans); +	if (ret)  		goto out_pci_disable_msi; -	err = request_threaded_irq(pdev->irq, iwl_pcie_isr, +	ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,  				   iwl_pcie_irq_handler,  				   IRQF_SHARED, DRV_NAME, trans); -	if (err) { +	if (ret) {  		IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);  		goto out_free_ict;  	} @@ -2617,5 +2827,5 @@ out_pci_disable_device:  	pci_disable_device(pdev);  out_no_pci:  	iwl_trans_free(trans); -	return ERR_PTR(err); +	return ERR_PTR(ret);  } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2b86c2135de3..a8c8a4a7420b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -219,8 +219,6 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,  	scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; -	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); -  	sta_id = tx_cmd->sta_id;  	sec_ctl = tx_cmd->sec_ctl; @@ -239,6 +237,9 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,  	if (trans_pcie->bc_table_dword)  		len = DIV_ROUND_UP(len, 4); +	if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) +		return; +  	bc_ent = cpu_to_le16(len | (sta_id << 12));  	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; @@ -387,11 +388,18 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  	/* first TB is never freed - it's the scratchbuf data */ -	for (i = 1; i < num_tbs; i++) -		dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), -				 iwl_pcie_tfd_tb_get_len(tfd, i), -				 DMA_TO_DEVICE); - +	for (i = 1; i < num_tbs; i++) { +		if (meta->flags & BIT(i + CMD_TB_BITMAP_POS)) +			dma_unmap_page(trans->dev, +				       iwl_pcie_tfd_tb_get_addr(tfd, i), +				       iwl_pcie_tfd_tb_get_len(tfd, i), +				       DMA_TO_DEVICE); +		else +			dma_unmap_single(trans->dev, +					 iwl_pcie_tfd_tb_get_addr(tfd, i), +					 iwl_pcie_tfd_tb_get_len(tfd, i), +					 DMA_TO_DEVICE); +	}  	tfd->num_tbs = 0;  } @@ -467,7 +475,7 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq,  	iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); -	return 0; +	return num_tbs;  }  static int iwl_pcie_txq_alloc(struct iwl_trans *trans, @@ -915,6 +923,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)  		}  	} +	iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE);  	if (trans->cfg->base_params->num_of_queues > 20)  		iwl_set_bits_prph(trans, SCD_GP_CTRL,  				  SCD_GP_CTRL_ENABLE_31_QUEUES); @@ -1320,13 +1329,24 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	int idx;  	u16 copy_size, cmd_size, scratch_size;  	bool had_nocopy = false; +	u8 group_id = iwl_cmd_groupid(cmd->id);  	int i, ret;  	u32 cmd_pos;  	const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];  	u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; -	copy_size = sizeof(out_cmd->hdr); -	cmd_size = sizeof(out_cmd->hdr); +	if (WARN(!trans_pcie->wide_cmd_header && +		 group_id > IWL_ALWAYS_LONG_GROUP, +		 "unsupported wide command %#x\n", cmd->id)) +		return -EINVAL; + +	if (group_id != 0) { +		copy_size = sizeof(struct iwl_cmd_header_wide); +		cmd_size = sizeof(struct iwl_cmd_header_wide); +	} else { +		copy_size = sizeof(struct iwl_cmd_header); +		cmd_size = sizeof(struct iwl_cmd_header); +	}  	/* need one for the header if the first is NOCOPY */  	BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); @@ -1416,16 +1436,32 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		out_meta->source = cmd;  	/* set up the header */ - -	out_cmd->hdr.cmd = cmd->id; -	out_cmd->hdr.flags = 0; -	out_cmd->hdr.sequence = -		cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | -					 INDEX_TO_SEQ(q->write_ptr)); +	if (group_id != 0) { +		out_cmd->hdr_wide.cmd = iwl_cmd_opcode(cmd->id); +		out_cmd->hdr_wide.group_id = group_id; +		out_cmd->hdr_wide.version = iwl_cmd_version(cmd->id); +		out_cmd->hdr_wide.length = +			cpu_to_le16(cmd_size - +				    sizeof(struct iwl_cmd_header_wide)); +		out_cmd->hdr_wide.reserved = 0; +		out_cmd->hdr_wide.sequence = +			cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | +						 INDEX_TO_SEQ(q->write_ptr)); + +		cmd_pos = sizeof(struct iwl_cmd_header_wide); +		copy_size = sizeof(struct iwl_cmd_header_wide); +	} else { +		out_cmd->hdr.cmd = iwl_cmd_opcode(cmd->id); +		out_cmd->hdr.sequence = +			cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | +						 INDEX_TO_SEQ(q->write_ptr)); +		out_cmd->hdr.group_id = 0; + +		cmd_pos = sizeof(struct iwl_cmd_header); +		copy_size = sizeof(struct iwl_cmd_header); +	}  	/* and copy the data that needs to be copied */ -	cmd_pos = offsetof(struct iwl_device_cmd, payload); -	copy_size = sizeof(out_cmd->hdr);  	for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {  		int copy; @@ -1464,9 +1500,10 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  	}  	IWL_DEBUG_HC(trans, -		     "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", +		     "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",  		     get_cmd_string(trans_pcie, out_cmd->hdr.cmd), -		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), +		     group_id, out_cmd->hdr.cmd, +		     le16_to_cpu(out_cmd->hdr.sequence),  		     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);  	/* start the TFD with the scratchbuf */ @@ -1516,12 +1553,14 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  		iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], false);  	} +	BUILD_BUG_ON(IWL_NUM_OF_TBS + CMD_TB_BITMAP_POS > +		     sizeof(out_meta->flags) * BITS_PER_BYTE);  	out_meta->flags = cmd->flags;  	if (WARN_ON_ONCE(txq->entries[idx].free_buf))  		kzfree(txq->entries[idx].free_buf);  	txq->entries[idx].free_buf = dup_buf; -	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); +	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr_wide);  	/* start timer if queue currently empty */  	if (q->read_ptr == q->write_ptr && txq->wd_timeout) @@ -1552,15 +1591,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,  /*   * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them   * @rxb: Rx buffer to reclaim - * @handler_status: return value of the handler of the command - *	(put in setup_rx_handlers)   *   * If an Rx buffer has an async callback associated with it the callback   * will be executed.  The attached skb (if present) will only be freed   * if the callback returns 1   */  void iwl_pcie_hcmd_complete(struct iwl_trans *trans, -			    struct iwl_rx_cmd_buffer *rxb, int handler_status) +			    struct iwl_rx_cmd_buffer *rxb)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1599,7 +1636,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,  		meta->source->resp_pkt = pkt;  		meta->source->_rx_page_addr = (unsigned long)page_address(p);  		meta->source->_rx_page_order = trans_pcie->rx_page_order; -		meta->source->handler_status = handler_status;  	}  	iwl_pcie_cmdq_reclaim(trans, txq_id, index); @@ -1762,7 +1798,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		      struct iwl_device_cmd *dev_cmd, int txq_id)  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); -	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +	struct ieee80211_hdr *hdr;  	struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;  	struct iwl_cmd_meta *out_meta;  	struct iwl_txq *txq; @@ -1771,9 +1807,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	void *tb1_addr;  	u16 len, tb1_len, tb2_len;  	bool wait_write_ptr; -	__le16 fc = hdr->frame_control; -	u8 hdr_len = ieee80211_hdrlen(fc); +	__le16 fc; +	u8 hdr_len;  	u16 wifi_seq; +	int i;  	txq = &trans_pcie->txq[txq_id];  	q = &txq->q; @@ -1782,6 +1819,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		      "TX on unused queue %d\n", txq_id))  		return -EINVAL; +	if (skb_is_nonlinear(skb) && +	    skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS && +	    __skb_linearize(skb)) +		return -ENOMEM; + +	/* mac80211 always puts the full header into the SKB's head, +	 * so there's no need to check if it's readable there +	 */ +	hdr = (struct ieee80211_hdr *)skb->data; +	fc = hdr->frame_control; +	hdr_len = ieee80211_hdrlen(fc); +  	spin_lock(&txq->lock);  	/* In AGG mode, the index in the ring must correspond to the WiFi @@ -1812,6 +1861,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	/* Set up first empty entry in queue's array of Tx/cmd buffers */  	out_meta = &txq->entries[q->write_ptr].meta; +	out_meta->flags = 0;  	/*  	 * The second TB (tb1) points to the remainder of the TX command @@ -1845,9 +1895,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	/*  	 * Set up TFD's third entry to point directly to remainder -	 * of skb, if any (802.11 null frames have no payload). +	 * of skb's head, if any  	 */ -	tb2_len = skb->len - hdr_len; +	tb2_len = skb_headlen(skb) - hdr_len;  	if (tb2_len > 0) {  		dma_addr_t tb2_phys = dma_map_single(trans->dev,  						     skb->data + hdr_len, @@ -1860,6 +1910,29 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  		iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false);  	} +	/* set up the remaining entries to point to the data */ +	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { +		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; +		dma_addr_t tb_phys; +		int tb_idx; + +		if (!skb_frag_size(frag)) +			continue; + +		tb_phys = skb_frag_dma_map(trans->dev, frag, 0, +					   skb_frag_size(frag), DMA_TO_DEVICE); + +		if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { +			iwl_pcie_tfd_unmap(trans, out_meta, +					   &txq->tfds[q->write_ptr]); +			goto out_err; +		} +		tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, +						skb_frag_size(frag), false); + +		out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS); +	} +  	/* Set up entry for this TFD in Tx byte-count array */  	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); @@ -1869,14 +1942,25 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  			     &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,  			     skb->data + hdr_len, tb2_len);  	trace_iwlwifi_dev_tx_data(trans->dev, skb, -				  skb->data + hdr_len, tb2_len); +				  hdr_len, skb->len - hdr_len);  	wait_write_ptr = ieee80211_has_morefrags(fc);  	/* start timer if queue currently empty */  	if (q->read_ptr == q->write_ptr) { -		if (txq->wd_timeout) -			mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); +		if (txq->wd_timeout) { +			/* +			 * If the TXQ is active, then set the timer, if not, +			 * set the timer in remainder so that the timer will +			 * be armed with the right value when the station will +			 * wake up. +			 */ +			if (!txq->frozen) +				mod_timer(&txq->stuck_timer, +					  jiffies + txq->wd_timeout); +			else +				txq->frozen_expiry_remainder = txq->wd_timeout; +		}  		IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);  		iwl_trans_pcie_ref(trans);  	} diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 99e873dc8684..520bef80747f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2399,6 +2399,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,  	ieee80211_hw_set(hw, AMPDU_AGGREGATION);  	ieee80211_hw_set(hw, MFP_CAPABLE);  	ieee80211_hw_set(hw, SIGNAL_DBM); +	ieee80211_hw_set(hw, TDLS_WIDER_BW);  	if (rctbl)  		ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); @@ -2676,7 +2677,7 @@ static void hwsim_mon_setup(struct net_device *dev)  	dev->netdev_ops = &hwsim_netdev_ops;  	dev->destructor = free_netdev;  	ether_setup(dev); -	dev->tx_queue_len = 0; +	dev->priv_flags |= IFF_NO_QUEUE;  	dev->type = ARPHRD_IEEE80211_RADIOTAP;  	eth_zero_addr(dev->dev_addr);  	dev->dev_addr[0] = 0x12; @@ -3120,8 +3121,10 @@ static int hwsim_init_netlink(void)  		goto failure;  	rc = netlink_register_notifier(&hwsim_netlink_notifier); -	if (rc) +	if (rc) { +		genl_unregister_family(&hwsim_genl_family);  		goto failure; +	}  	return 0; diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 7217da4f1543..57a80cfa39b1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,  	if (!skb)  		return; -	ieee80211_rx_ni(dev->hw, skb); +	spin_lock(&dev->mac_lock); +	ieee80211_rx(dev->hw, skb); +	spin_unlock(&dev->mac_lock);  }  static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) @@ -236,23 +238,42 @@ static void mt7601u_complete_tx(struct urb *urb)  	skb = q->e[q->start].skb;  	trace_mt_tx_dma_done(dev, skb); -	mt7601u_tx_status(dev, skb); +	__skb_queue_tail(&dev->tx_skb_done, skb); +	tasklet_schedule(&dev->tx_tasklet);  	if (q->used == q->entries - q->entries / 8)  		ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb));  	q->start = (q->start + 1) % q->entries;  	q->used--; +out: +	spin_unlock_irqrestore(&dev->tx_lock, flags); +} -	if (urb->status) -		goto out; +static void mt7601u_tx_tasklet(unsigned long data) +{ +	struct mt7601u_dev *dev = (struct mt7601u_dev *) data; +	struct sk_buff_head skbs; +	unsigned long flags; + +	__skb_queue_head_init(&skbs); + +	spin_lock_irqsave(&dev->tx_lock, flags);  	set_bit(MT7601U_STATE_MORE_STATS, &dev->state);  	if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state))  		queue_delayed_work(dev->stat_wq, &dev->stat_work,  				   msecs_to_jiffies(10)); -out: + +	skb_queue_splice_init(&dev->tx_skb_done, &skbs); +  	spin_unlock_irqrestore(&dev->tx_lock, flags); + +	while (!skb_queue_empty(&skbs)) { +		struct sk_buff *skb = __skb_dequeue(&skbs); + +		mt7601u_tx_status(dev, skb); +	}  }  static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, @@ -475,6 +496,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev)  {  	int ret = -ENOMEM; +	tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev);  	tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev);  	ret = mt7601u_alloc_tx(dev); @@ -502,4 +524,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev)  	mt7601u_free_rx(dev);  	mt7601u_free_tx(dev); + +	tasklet_kill(&dev->tx_tasklet);  } diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index df3dd56199a7..26190fd33407 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -454,8 +454,10 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)  	spin_lock_init(&dev->tx_lock);  	spin_lock_init(&dev->rx_lock);  	spin_lock_init(&dev->lock); +	spin_lock_init(&dev->mac_lock);  	spin_lock_init(&dev->con_mon_lock);  	atomic_set(&dev->avg_ampdu_len, 1); +	skb_queue_head_init(&dev->tx_skb_done);  	dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0);  	if (!dev->stat_wq) { diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index 7514bce1ac91..e21c53ed09fb 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)  	}  	mt76_mac_fill_tx_status(dev, &info, stat); + +	spin_lock_bh(&dev->mac_lock);  	ieee80211_tx_status_noskb(dev->hw, sta, &info); +	spin_unlock_bh(&dev->mac_lock); +  	rcu_read_unlock();  } diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 9102be6b95cb..428bd2f10b7b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -141,12 +141,13 @@ enum {  /**   * struct mt7601u_dev - adapter structure   * @lock:		protects @wcid->tx_rate. + * @mac_lock:		locks out mac80211's tx status and rx paths.   * @tx_lock:		protects @tx_q and changes of MT7601U_STATE_*_STATS -			flags in @state. + *			flags in @state.   * @rx_lock:		protects @rx_q.   * @con_mon_lock:	protects @ap_bssid, @bcn_*, @avg_rssi.   * @mutex:		ensures exclusive access from mac80211 callbacks. - * @vendor_req_mutex:	ensures atomicity of vendor requests. + * @vendor_req_mutex:	protects @vend_buf, ensures atomicity of split writes.   * @reg_atomic_mutex:	ensures atomicity of indirect register accesses   *			(accesses to RF and BBP).   * @hw_atomic_mutex:	ensures exclusive access to HW during critical @@ -177,6 +178,7 @@ struct mt7601u_dev {  	struct mt76_wcid __rcu *wcid[N_WCIDS];  	spinlock_t lock; +	spinlock_t mac_lock;  	const u16 *beacon_offsets; @@ -184,6 +186,8 @@ struct mt7601u_dev {  	struct mt7601u_eeprom_params *ee;  	struct mutex vendor_req_mutex; +	void *vend_buf; +  	struct mutex reg_atomic_mutex;  	struct mutex hw_atomic_mutex; @@ -197,7 +201,9 @@ struct mt7601u_dev {  	/* TX */  	spinlock_t tx_lock; +	struct tasklet_struct tx_tasklet;  	struct mt7601u_tx_queue *tx_q; +	struct sk_buff_head tx_skb_done;  	atomic_t avg_ampdu_len; diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index 0be2080ceab3..a0a33dc8f6bc 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)  	ieee80211_tx_info_clear_status(info);  	info->status.rates[0].idx = -1;  	info->flags |= IEEE80211_TX_STAT_ACK; + +	spin_lock(&dev->mac_lock);  	ieee80211_tx_status(dev->hw, skb); +	spin_unlock(&dev->mac_lock);  }  static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 54dba4001865..416c6045ff31 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb)  	complete(cmpl);  } -static int -__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, -			 const u8 direction, const u16 val, const u16 offset, -			 void *buf, const size_t buflen) +int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, +			   const u8 direction, const u16 val, const u16 offset, +			   void *buf, const size_t buflen)  {  	int i, ret;  	struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); @@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,  		trace_mt_vend_req(dev, pipe, req, req_type, val, offset,  				  buf, buflen, ret); +		if (ret == -ENODEV) +			set_bit(MT7601U_STATE_REMOVED, &dev->state);  		if (ret >= 0 || ret == -ENODEV)  			return ret; @@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,  	return ret;  } -int -mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, -		       const u8 direction, const u16 val, const u16 offset, -		       void *buf, const size_t buflen) -{ -	int ret; - -	mutex_lock(&dev->vendor_req_mutex); - -	ret = __mt7601u_vendor_request(dev, req, direction, val, offset, -				       buf, buflen); -	if (ret == -ENODEV) -		set_bit(MT7601U_STATE_REMOVED, &dev->state); - -	mutex_unlock(&dev->vendor_req_mutex); - -	return ret; -} -  void mt7601u_vendor_reset(struct mt7601u_dev *dev)  {  	mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, @@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev)  u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)  {  	int ret; -	__le32 reg; -	u32 val; +	u32 val = ~0;  	WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); +	mutex_lock(&dev->vendor_req_mutex); +  	ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, -				     0, offset, ®, sizeof(reg)); -	val = le32_to_cpu(reg); -	if (ret > 0 && ret != sizeof(reg)) { +				     0, offset, dev->vend_buf, MT_VEND_BUF); +	if (ret == MT_VEND_BUF) +		val = get_unaligned_le32(dev->vend_buf); +	else if (ret > 0)  		dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",  			ret, offset); -		val = ~0; -	} + +	mutex_unlock(&dev->vendor_req_mutex);  	trace_reg_read(dev, offset, val);  	return val; @@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,  {  	int ret; +	mutex_lock(&dev->vendor_req_mutex); +  	ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT,  				     val & 0xffff, offset, NULL, 0); -	if (ret) -		return ret; -	return mt7601u_vendor_request(dev, req, USB_DIR_OUT, -				      val >> 16, offset + 2, NULL, 0); +	if (!ret) +		ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, +					     val >> 16, offset + 2, NULL, 0); + +	mutex_unlock(&dev->vendor_req_mutex); + +	return ret;  }  void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) @@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf,  	usb_set_intfdata(usb_intf, dev); +	dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); +	if (!dev->vend_buf) { +		ret = -ENOMEM; +		goto err; +	} +  	ret = mt7601u_assign_pipes(usb_intf, dev);  	if (ret)  		goto err; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h index 49e188fa3798..bc182022b9d6 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.h +++ b/drivers/net/wireless/mediatek/mt7601u/usb.h @@ -23,6 +23,8 @@  #define MT_VEND_DEV_MODE_RESET	1 +#define MT_VEND_BUF		sizeof(__le32) +  enum mt_vendor_req {  	MT_VEND_DEV_MODE = 1,  	MT_VEND_WRITE = 2, diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 48edf387683e..317d99189556 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -9,36 +9,36 @@ config MWIFIEX  	  mwifiex.  config MWIFIEX_SDIO -	tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897" +	tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897/SD8997"  	depends on MWIFIEX && MMC  	select FW_LOADER  	select WANT_DEV_COREDUMP  	---help---  	  This adds support for wireless adapters based on Marvell -	  8786/8787/8797/8887/8897 chipsets with SDIO interface. +	  8786/8787/8797/8887/8897/8997 chipsets with SDIO interface.  	  If you choose to build it as a module, it will be called  	  mwifiex_sdio.  config MWIFIEX_PCIE -	tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" +	tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897/8997"  	depends on MWIFIEX && PCI  	select FW_LOADER  	select WANT_DEV_COREDUMP  	---help---  	  This adds support for wireless adapters based on Marvell -	  8766/8897 chipsets with PCIe interface. +	  8766/8897/8997 chipsets with PCIe interface.  	  If you choose to build it as a module, it will be called  	  mwifiex_pcie.  config MWIFIEX_USB -	tristate "Marvell WiFi-Ex Driver for USB8766/8797/8897" +	tristate "Marvell WiFi-Ex Driver for USB8766/8797/8897/8997"  	depends on MWIFIEX && USB  	select FW_LOADER  	---help---  	  This adds support for wireless adapters based on Marvell -	  8797/8897 chipset with USB interface. +	  8797/8897/8997 chipset with USB interface.  	  If you choose to build it as a module, it will be called  	  mwifiex_usb. diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b15e4c7acbec..ff63cb5632eb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -19,6 +19,7 @@  #include "cfg80211.h"  #include "main.h" +#include "11n.h"  static char *reg_alpha2;  module_param(reg_alpha2, charp, 0); @@ -34,12 +35,38 @@ static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {  	},  }; -static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta = {  	.limits = mwifiex_ap_sta_limits,  	.num_different_channels = 1,  	.n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits),  	.max_interfaces = MWIFIEX_MAX_BSS_NUM,  	.beacon_int_infra_match = true, +	.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | +				BIT(NL80211_CHAN_WIDTH_20) | +				BIT(NL80211_CHAN_WIDTH_40), +}; + +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta_vht = { +	.limits = mwifiex_ap_sta_limits, +	.num_different_channels = 1, +	.n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), +	.max_interfaces = MWIFIEX_MAX_BSS_NUM, +	.beacon_int_infra_match = true, +	.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | +				BIT(NL80211_CHAN_WIDTH_20) | +				BIT(NL80211_CHAN_WIDTH_40) | +				BIT(NL80211_CHAN_WIDTH_80), +}; + +static const struct +ieee80211_iface_combination mwifiex_iface_comb_ap_sta_drcs = { +	.limits = mwifiex_ap_sta_limits, +	.num_different_channels = 2, +	.n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), +	.max_interfaces = MWIFIEX_MAX_BSS_NUM, +	.beacon_int_infra_match = true,  };  /* @@ -441,7 +468,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,   *      - Country codes   *      - Sub bands (first channel, number of channels, maximum Tx power)   */ -static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)  {  	u8 no_of_triplet = 0;  	struct ieee80211_country_ie_triplet *t; @@ -804,10 +831,13 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,  		priv->bss_type = MWIFIEX_BSS_TYPE_STA;  		break;  	case NL80211_IFTYPE_P2P_CLIENT: -	case NL80211_IFTYPE_P2P_GO:  		priv->bss_role =  MWIFIEX_BSS_ROLE_STA;  		priv->bss_type = MWIFIEX_BSS_TYPE_P2P;  		break; +	case NL80211_IFTYPE_P2P_GO: +		priv->bss_role =  MWIFIEX_BSS_ROLE_UAP; +		priv->bss_type = MWIFIEX_BSS_TYPE_P2P; +		break;  	case NL80211_IFTYPE_AP:  		priv->bss_type = MWIFIEX_BSS_TYPE_UAP;  		priv->bss_role = MWIFIEX_BSS_ROLE_UAP; @@ -1115,8 +1145,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,  	case NL80211_IFTYPE_P2P_GO:  		switch (type) {  		case NL80211_IFTYPE_STATION: -			if (mwifiex_cfg80211_init_p2p_client(priv)) +			if (mwifiex_cfg80211_deinit_p2p(priv))  				return -EFAULT; +			priv->adapter->curr_iface_comb.p2p_intf--; +			priv->adapter->curr_iface_comb.sta_intf++;  			dev->ieee80211_ptr->iftype = type;  			break;  		case NL80211_IFTYPE_ADHOC: @@ -2788,6 +2820,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  {  	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);  	struct mwifiex_adapter *adapter = priv->adapter; +	struct sk_buff *skb, *tmp;  #ifdef CONFIG_DEBUG_FS  	mwifiex_dev_debugfs_remove(priv); @@ -2795,6 +2828,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)  	mwifiex_stop_net_dev_queue(priv->netdev, adapter); +	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) +		mwifiex_write_data_complete(priv->adapter, skb, 0, -1); +  	if (netif_carrier_ok(priv->netdev))  		netif_carrier_off(priv->netdev); @@ -2954,7 +2990,6 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,  					MWIFIEX_MEF_MAX_BYTESEQ)) {  			mwifiex_dbg(priv->adapter, ERROR,  				    "Pattern not supported\n"); -			kfree(mef_entry);  			return -EOPNOTSUPP;  		} @@ -3036,9 +3071,12 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,  	mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); -	if (wowlan->n_patterns || wowlan->magic_pkt) +	if (wowlan->n_patterns || wowlan->magic_pkt) {  		ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg,  						   &mef_entry[1], wowlan); +		if (ret) +			goto err; +	}  	if (!mef_cfg.criteria)  		mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -3048,6 +3086,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,  	ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,  			HostCmd_ACT_GEN_SET, 0,  			&mef_cfg, true); + +err:  	kfree(mef_entry);  	return ret;  } @@ -3360,6 +3400,72 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,  }  static int +mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev, +				  const u8 *addr, u8 oper_class, +				  struct cfg80211_chan_def *chandef) +{ +	struct mwifiex_sta_node *sta_ptr; +	unsigned long flags; +	u16 chan; +	u8 second_chan_offset, band; +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	spin_lock_irqsave(&priv->sta_list_spinlock, flags); +	sta_ptr = mwifiex_get_sta_entry(priv, addr); +	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + +	if (!sta_ptr) { +		wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", +			  __func__, addr); +		return -ENOENT; +	} + +	if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] & +	      WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) { +		wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); +		return -ENOENT; +	} + +	if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || +	    sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) { +		wiphy_err(wiphy, "channel switch is running, abort request\n"); +		return -EALREADY; +	} + +	chan = chandef->chan->hw_value; +	second_chan_offset = mwifiex_get_sec_chan_offset(chan); +	band = chandef->chan->band; +	mwifiex_start_tdls_cs(priv, addr, chan, second_chan_offset, band); + +	return 0; +} + +static void +mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, +					 struct net_device *dev, +					 const u8 *addr) +{ +	struct mwifiex_sta_node *sta_ptr; +	unsigned long flags; +	struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + +	spin_lock_irqsave(&priv->sta_list_spinlock, flags); +	sta_ptr = mwifiex_get_sta_entry(priv, addr); +	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + +	if (!sta_ptr) { +		wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", +			  __func__, addr); +	} else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || +		     sta_ptr->tdls_status == TDLS_IN_BASE_CHAN || +		     sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) { +		wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n", +			  addr); +	} else +		mwifiex_stop_tdls_cs(priv, addr); +} + +static int  mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,  			     const u8 *mac, struct station_parameters *params)  { @@ -3575,6 +3681,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {  	.set_coalesce = mwifiex_cfg80211_set_coalesce,  	.tdls_mgmt = mwifiex_cfg80211_tdls_mgmt,  	.tdls_oper = mwifiex_cfg80211_tdls_oper, +	.tdls_channel_switch = mwifiex_cfg80211_tdls_chan_switch, +	.tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch,  	.add_station = mwifiex_cfg80211_add_station,  	.change_station = mwifiex_cfg80211_change_station,  	.get_channel = mwifiex_cfg80211_get_channel, @@ -3672,7 +3780,12 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	else  		wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; -	wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; +	if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) +		wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; +	else if (adapter->is_hw_11ac_capable) +		wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_vht; +	else +		wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta;  	wiphy->n_iface_combinations = 1;  	/* Initialize cipher suits */ @@ -3709,6 +3822,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  			   NL80211_FEATURE_INACTIVITY_TIMER |  			   NL80211_FEATURE_NEED_OBSS_SCAN; +	if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) +		wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; +  	if (adapter->fw_api_ver == MWIFIEX_FW_V15)  		wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 207da40500f4..45ae38e32621 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -167,8 +167,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,  		mwifiex_dbg(adapter, ERROR,  			    "DNLD_CMD: FW in reset state, ignore cmd %#x\n",  			cmd_code); -		if (cmd_node->wait_q_enabled) -			mwifiex_complete_cmd(adapter, cmd_node);  		mwifiex_recycle_cmd_node(adapter, cmd_node);  		queue_work(adapter->workqueue, &adapter->main_work);  		return -1; @@ -809,17 +807,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)  	adapter->is_cmd_timedout = 0;  	resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; -	if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { -		mwifiex_dbg(adapter, ERROR, -			    "CMD_RESP: %#x been canceled\n", -			    le16_to_cpu(resp->command)); -		mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); -		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); -		adapter->curr_cmd = NULL; -		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -		return -1; -	} -  	if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {  		/* Copy original response back to response buffer */  		struct mwifiex_ds_misc_cmd *hostcmd; @@ -989,12 +976,13 @@ mwifiex_cmd_timeout_func(unsigned long function_context)  		if (cmd_node->wait_q_enabled) {  			adapter->cmd_wait_q.status = -ETIMEDOUT; -			wake_up_interruptible(&adapter->cmd_wait_q.wait);  			mwifiex_cancel_pending_ioctl(adapter);  		}  	} -	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) +	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {  		mwifiex_init_fw_complete(adapter); +		return; +	}  	if (adapter->if_ops.device_dump)  		adapter->if_ops.device_dump(adapter); @@ -1024,6 +1012,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)  		adapter->curr_cmd->wait_q_enabled = false;  		adapter->cmd_wait_q.status = -1;  		mwifiex_complete_cmd(adapter, adapter->curr_cmd); +		/* no recycle probably wait for response */  	}  	/* Cancel all pending command */  	spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -1032,11 +1021,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)  		list_del(&cmd_node->list);  		spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); -		if (cmd_node->wait_q_enabled) { +		if (cmd_node->wait_q_enabled)  			adapter->cmd_wait_q.status = -1; -			mwifiex_complete_cmd(adapter, cmd_node); -			cmd_node->wait_q_enabled = false; -		}  		mwifiex_recycle_cmd_node(adapter, cmd_node);  		spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);  	} @@ -1094,12 +1080,18 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)  	    (adapter->curr_cmd->wait_q_enabled)) {  		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);  		cmd_node = adapter->curr_cmd; -		cmd_node->wait_q_enabled = false; -		cmd_node->cmd_flag |= CMD_F_CANCELED; -		mwifiex_recycle_cmd_node(adapter, cmd_node); -		mwifiex_complete_cmd(adapter, adapter->curr_cmd); +		/* setting curr_cmd to NULL is quite dangerous, because +		 * mwifiex_process_cmdresp checks curr_cmd to be != NULL +		 * at the beginning then relies on it and dereferences +		 * it at will +		 * this probably works since mwifiex_cmd_timeout_func +		 * is the only caller of this function and responses +		 * at that point +		 */  		adapter->curr_cmd = NULL;  		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + +		mwifiex_recycle_cmd_node(adapter, cmd_node);  	}  	/* Cancel all pending scan command */ @@ -1129,7 +1121,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)  			}  		}  	} -	adapter->cmd_wait_q.status = -1;  }  /* diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 51e344789ba2..098e1f14dc9a 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -141,6 +141,9 @@ enum mwifiex_tdls_status {  	TDLS_SETUP_COMPLETE,  	TDLS_SETUP_FAILURE,  	TDLS_LINK_TEARDOWN, +	TDLS_CHAN_SWITCHING, +	TDLS_IN_BASE_CHAN, +	TDLS_IN_OFF_CHAN,  };  enum mwifiex_tdls_error_code { diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cd09051710e6..3ec2ac82e394 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -169,14 +169,17 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {  #define TLV_TYPE_UAP_PS_AO_TIMER    (PROPRIETARY_TLV_BASE_ID + 123)  #define TLV_TYPE_PWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 145)  #define TLV_TYPE_GWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_TX_PAUSE           (PROPRIETARY_TLV_BASE_ID + 148)  #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)  #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_MULTI_CHAN_INFO    (PROPRIETARY_TLV_BASE_ID + 183)  #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)  #define TLV_TYPE_SCAN_CHANNEL_GAP   (PROPRIETARY_TLV_BASE_ID + 197)  #define TLV_TYPE_API_REV            (PROPRIETARY_TLV_BASE_ID + 199)  #define TLV_TYPE_CHANNEL_STATS      (PROPRIETARY_TLV_BASE_ID + 198)  #define TLV_BTCOEX_WL_AGGR_WINSIZE  (PROPRIETARY_TLV_BASE_ID + 202)  #define TLV_BTCOEX_WL_SCANTIME      (PROPRIETARY_TLV_BASE_ID + 203) +#define TLV_TYPE_BSS_MODE           (PROPRIETARY_TLV_BASE_ID + 206)  #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048 @@ -200,6 +203,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {  #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))  #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_DRCS_ENABLED(FwCapInfo) (FwCapInfo & BIT(15))  #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16))  #define MWIFIEX_DEF_HT_CAP	(IEEE80211_HT_CAP_DSSSCCK40 | \ @@ -359,6 +363,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {  #define HostCmd_CMD_MGMT_FRAME_REG                    0x010c  #define HostCmd_CMD_REMAIN_ON_CHAN                    0x010d  #define HostCmd_CMD_11AC_CFG			      0x0112 +#define HostCmd_CMD_TDLS_CONFIG                       0x0100 +#define HostCmd_CMD_MC_POLICY                         0x0121  #define HostCmd_CMD_TDLS_OPER                         0x0122  #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG               0x0223 @@ -432,7 +438,6 @@ enum P2P_MODES {  #define CMD_F_HOSTCMD           (1 << 0) -#define CMD_F_CANCELED          (1 << 1)  #define HostCmd_CMD_ID_MASK             0x0fff @@ -509,8 +514,10 @@ enum P2P_MODES {  #define EVENT_TDLS_GENERIC_EVENT        0x00000052  #define EVENT_RADAR_DETECTED		0x00000053  #define EVENT_CHANNEL_REPORT_RDY        0x00000054 +#define EVENT_TX_DATA_PAUSE             0x00000055  #define EVENT_EXT_SCAN_REPORT           0x00000058  #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f +#define EVENT_MULTI_CHAN_INFO           0x0000006a  #define EVENT_TX_STATUS_REPORT		0x00000074  #define EVENT_BT_COEX_WLAN_PARA_CHANGE	0X00000076 @@ -545,7 +552,27 @@ enum P2P_MODES {  #define ACT_TDLS_DELETE            0x00  #define ACT_TDLS_CREATE            0x01  #define ACT_TDLS_CONFIG            0x02 -#define TDLS_EVENT_LINK_TEAR_DOWN  3 + +#define TDLS_EVENT_LINK_TEAR_DOWN      3 +#define TDLS_EVENT_CHAN_SWITCH_RESULT  7 +#define TDLS_EVENT_START_CHAN_SWITCH   8 +#define TDLS_EVENT_CHAN_SWITCH_STOPPED 9 + +#define TDLS_BASE_CHANNEL	       0 +#define TDLS_OFF_CHANNEL	       1 + +#define ACT_TDLS_CS_ENABLE_CONFIG 0x00 +#define ACT_TDLS_CS_INIT	  0x06 +#define ACT_TDLS_CS_STOP	  0x07 +#define ACT_TDLS_CS_PARAMS	  0x08 + +#define MWIFIEX_DEF_CS_UNIT_TIME	2 +#define MWIFIEX_DEF_CS_THR_OTHERLINK	10 +#define MWIFIEX_DEF_THR_DIRECTLINK	0 +#define MWIFIEX_DEF_CS_TIME		10 +#define MWIFIEX_DEF_CS_TIMEOUT		16 +#define MWIFIEX_DEF_CS_REG_CLASS	12 +#define MWIFIEX_DEF_CS_PERIODICITY	1  #define MWIFIEX_FW_V15		   15 @@ -658,6 +685,7 @@ struct mwifiex_fw_chan_stats {  enum mwifiex_chan_scan_mode_bitmasks {  	MWIFIEX_PASSIVE_SCAN = BIT(0),  	MWIFIEX_DISABLE_CHAN_FILT = BIT(1), +	MWIFIEX_HIDDEN_SSID_REPORT = BIT(4),  };  struct mwifiex_chan_scan_param_set { @@ -1131,6 +1159,13 @@ struct host_cmd_ds_tx_rate_query {  	u8 ht_info;  } __packed; +struct mwifiex_tx_pause_tlv { +	struct mwifiex_ie_types_header header; +	u8 peermac[ETH_ALEN]; +	u8 tx_pause; +	u8 pkt_cnt; +} __packed; +  enum Host_Sleep_Action {  	HS_CONFIGURE = 0x0001,  	HS_ACTIVATE  = 0x0002, @@ -1249,6 +1284,36 @@ struct host_cmd_ds_tdls_oper {  	u8 peer_mac[ETH_ALEN];  } __packed; +struct mwifiex_tdls_config { +	__le16 enable; +}; + +struct mwifiex_tdls_config_cs_params { +	u8 unit_time; +	u8 thr_otherlink; +	u8 thr_directlink; +}; + +struct mwifiex_tdls_init_cs_params { +	u8 peer_mac[ETH_ALEN]; +	u8 primary_chan; +	u8 second_chan_offset; +	u8 band; +	__le16 switch_time; +	__le16 switch_timeout; +	u8 reg_class; +	u8 periodicity; +} __packed; + +struct mwifiex_tdls_stop_cs_params { +	u8 peer_mac[ETH_ALEN]; +}; + +struct host_cmd_ds_tdls_config { +	__le16 tdls_action; +	u8 tdls_data[1]; +} __packed; +  struct mwifiex_chan_desc {  	__le16 start_freq;  	u8 chan_width; @@ -1370,6 +1435,11 @@ struct host_cmd_ds_802_11_scan_ext {  	u8    tlv_buffer[1];  } __packed; +struct mwifiex_ie_types_bss_mode { +	struct mwifiex_ie_types_header  header; +	u8 bss_mode; +} __packed; +  struct mwifiex_ie_types_bss_scan_rsp {  	struct mwifiex_ie_types_header header;  	u8 bssid[ETH_ALEN]; @@ -1908,6 +1978,12 @@ struct mwifiex_radar_det_event {  	__le32 passed;  } __packed; +struct mwifiex_ie_types_multi_chan_info { +	struct mwifiex_ie_types_header header; +	__le16 status; +	u8 tlv_buffer[0]; +} __packed; +  struct meas_rpt_map {  	u8 rssi:3;  	u8 unmeasured:1; @@ -1927,10 +2003,18 @@ struct host_cmd_ds_802_11_subsc_evt {  	__le16 events;  } __packed; +struct chan_switch_result { +	u8 cur_chan; +	u8 status; +	u8 reason; +} __packed; +  struct mwifiex_tdls_generic_event {  	__le16 type;  	u8 peer_mac[ETH_ALEN];  	union { +		struct chan_switch_result switch_result; +		u8 cs_stop_reason;  		__le16 reason_code;  		__le16 reserved;  	} u; @@ -1971,6 +2055,11 @@ struct host_cmd_ds_coalesce_cfg {  	struct coalesce_receive_filt_rule rule[0];  } __packed; +struct host_cmd_ds_multi_chan_policy { +	__le16 action; +	__le16 policy; +} __packed; +  struct host_cmd_ds_command {  	__le16 command;  	__le16 size; @@ -2035,9 +2124,11 @@ struct host_cmd_ds_command {  		struct host_cmd_ds_sta_list sta_list;  		struct host_cmd_11ac_vht_cfg vht_cfg;  		struct host_cmd_ds_coalesce_cfg coalesce_cfg; +		struct host_cmd_ds_tdls_config tdls_config;  		struct host_cmd_ds_tdls_oper tdls_oper;  		struct host_cmd_ds_chan_rpt_req chan_rpt_req;  		struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; +		struct host_cmd_ds_multi_chan_policy mc_policy;  	} params;  } __packed; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 0ba894509413..abf52d25b981 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -409,6 +409,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,  	int ret;  	ret = mwifiex_uap_parse_tail_ies(priv, info); + +	if (ret)  		return ret;  	return mwifiex_set_mgmt_beacon_data_ies(priv, info); @@ -477,6 +479,7 @@ int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)  						   ar_ie, &priv->assocresp_idx);  done: +	kfree(gen_ie);  	kfree(beacon_ie);  	kfree(pr_ie);  	kfree(ar_ie); diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index df7fdc09d38c..5d3ae63baea4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -77,7 +77,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)  	priv->media_connected = false;  	eth_broadcast_addr(priv->curr_addr); - +	priv->port_open = false;  	priv->pkt_tx_ctrl = 0;  	priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;  	priv->data_rate = 0;	/* Initially indicate the rate as auto */ @@ -301,7 +301,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)  	adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM;  	adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM;  	adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM; - +	adapter->active_scan_triggered = false;  	setup_timer(&adapter->wakeup_timer, wakeup_timer_fn,  		    (unsigned long)adapter);  } @@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)  		INIT_LIST_HEAD(&priv->sta_list);  		INIT_LIST_HEAD(&priv->auto_tdls_list);  		skb_queue_head_init(&priv->tdls_txq); +		skb_queue_head_init(&priv->bypass_txq);  		spin_lock_init(&priv->tx_ba_stream_tbl_lock);  		spin_lock_init(&priv->rx_reorder_tbl_lock); @@ -550,11 +551,6 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)  		}  	} -	if (adapter->if_ops.init_fw_port) { -		if (adapter->if_ops.init_fw_port(adapter)) -			return -1; -	} -  	for (i = 0; i < adapter->priv_num; i++) {  		if (adapter->priv[i]) {  			ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta, diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 56b024a6aaa5..3cda1f956f0b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -783,6 +783,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,  	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)  		priv->scan_block = true; +	else +		priv->port_open = true;  done:  	/* Need to indicate IOCTL complete */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3ba4e0e04223..278dc94eaecb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -276,6 +276,7 @@ process_start:  		     !adapter->pm_wakeup_fw_try) &&  		    (is_command_pending(adapter) ||  		     !skb_queue_empty(&adapter->tx_data_q) || +		     !mwifiex_bypass_txlist_empty(adapter) ||  		     !mwifiex_wmm_lists_empty(adapter))) {  			adapter->pm_wakeup_fw_try = true;  			mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); @@ -299,9 +300,16 @@ process_start:  			if ((!adapter->scan_chan_gap_enabled &&  			     adapter->scan_processing) || adapter->data_sent || +			     mwifiex_is_tdls_chan_switching +			     (mwifiex_get_priv(adapter, +					       MWIFIEX_BSS_ROLE_STA)) ||  			    (mwifiex_wmm_lists_empty(adapter) && +			     mwifiex_bypass_txlist_empty(adapter) &&  			     skb_queue_empty(&adapter->tx_data_q))) {  				if (adapter->cmd_sent || adapter->curr_cmd || +					!mwifiex_is_send_cmd_allowed +						(mwifiex_get_priv(adapter, +						MWIFIEX_BSS_ROLE_STA)) ||  				    (!is_command_pending(adapter)))  					break;  			} @@ -342,7 +350,9 @@ process_start:  			continue;  		} -		if (!adapter->cmd_sent && !adapter->curr_cmd) { +		if (!adapter->cmd_sent && !adapter->curr_cmd && +		    mwifiex_is_send_cmd_allowed +		    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {  			if (mwifiex_exec_next_cmd(adapter) == -1) {  				ret = -1;  				break; @@ -365,7 +375,25 @@ process_start:  		if ((adapter->scan_chan_gap_enabled ||  		     !adapter->scan_processing) && -		    !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { +		    !adapter->data_sent && +		    !mwifiex_bypass_txlist_empty(adapter) && +		    !mwifiex_is_tdls_chan_switching +			(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { +			mwifiex_process_bypass_tx(adapter); +			if (adapter->hs_activated) { +				adapter->is_hs_configured = false; +				mwifiex_hs_activated_event +					(mwifiex_get_priv +					 (adapter, MWIFIEX_BSS_ROLE_ANY), +					 false); +			} +		} + +		if ((adapter->scan_chan_gap_enabled || +		     !adapter->scan_processing) && +		    !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && +		    !mwifiex_is_tdls_chan_switching +			(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {  			mwifiex_wmm_process_tx(adapter);  			if (adapter->hs_activated) {  				adapter->is_hs_configured = false; @@ -379,6 +407,7 @@ process_start:  		if (adapter->delay_null_pkt && !adapter->cmd_sent &&  		    !adapter->curr_cmd && !is_command_pending(adapter) &&  		    (mwifiex_wmm_lists_empty(adapter) && +		     mwifiex_bypass_txlist_empty(adapter) &&  		     skb_queue_empty(&adapter->tx_data_q))) {  			if (!mwifiex_send_null_packet  			    (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), @@ -649,6 +678,26 @@ mwifiex_close(struct net_device *dev)  	return 0;  } +static bool +mwifiex_bypass_tx_queue(struct mwifiex_private *priv, +			struct sk_buff *skb) +{ +	struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + +	if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || +	    mwifiex_is_skb_mgmt_frame(skb) || +	    (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && +	     ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && +	     (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { +		mwifiex_dbg(priv->adapter, DATA, +			    "bypass txqueue; eth type %#x, mgmt %d\n", +			     ntohs(eth_hdr->h_proto), +			     mwifiex_is_skb_mgmt_frame(skb)); +		return true; +	} + +	return false; +}  /*   * Add buffer into wmm tx queue and queue work to transmit it.   */ @@ -666,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)  		}  	} -	atomic_inc(&priv->adapter->tx_pending); -	mwifiex_wmm_add_buf_txqueue(priv, skb); +	if (mwifiex_bypass_tx_queue(priv, skb)) { +		atomic_inc(&priv->adapter->tx_pending); +		atomic_inc(&priv->adapter->bypass_tx_pending); +		mwifiex_wmm_add_buf_bypass_txqueue(priv, skb); +	 } else { +		atomic_inc(&priv->adapter->tx_pending); +		mwifiex_wmm_add_buf_txqueue(priv, skb); +	 }  	mwifiex_queue_main_work(priv->adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ae98b5b83b1f..6b9512140e7a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -281,6 +281,7 @@ struct mwifiex_ra_list_tbl {  	u8 amsdu_in_ampdu;  	u16 total_pkt_count;  	bool tdls_link; +	bool tx_paused;  };  struct mwifiex_tid_tbl { @@ -294,6 +295,7 @@ struct mwifiex_tid_tbl {  struct mwifiex_wmm_desc {  	struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];  	u32 packets_out[MAX_NUM_TID]; +	u32 pkts_paused[MAX_NUM_TID];  	/* spin lock to protect ra_list */  	spinlock_t ra_list_spinlock;  	struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; @@ -517,6 +519,7 @@ struct mwifiex_private {  	u8 frame_type;  	u8 curr_addr[ETH_ALEN];  	u8 media_connected; +	u8 port_open;  	u32 num_tx_timeout;  	/* track consecutive timeout */  	u8 tx_timeout_cnt; @@ -662,6 +665,8 @@ struct mwifiex_private {  	struct cfg80211_beacon_data beacon_after;  	struct mwifiex_11h_intf_state state_11h;  	struct mwifiex_ds_mem_rw mem_rw; +	struct sk_buff_head bypass_txq; +	struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];  }; @@ -768,6 +773,7 @@ struct mwifiex_sta_node {  	u8 tdls_status;  	struct mwifiex_tdls_capab tdls_cap;  	struct mwifiex_station_stats stats; +	u8 tx_pause;  };  struct mwifiex_auto_tdls_peer { @@ -831,6 +837,7 @@ struct mwifiex_adapter {  	wait_queue_head_t init_wait_q;  	void *card;  	struct mwifiex_if_ops if_ops; +	atomic_t bypass_tx_pending;  	atomic_t rx_pending;  	atomic_t tx_pending;  	atomic_t cmd_pending; @@ -979,6 +986,8 @@ struct mwifiex_adapter {  	u8 coex_win_size;  	u8 coex_tx_win_size;  	u8 coex_rx_win_size; +	bool drcs_enabled; +	u8 active_scan_triggered;  };  void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); @@ -1330,6 +1339,21 @@ static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv)  	return 0;  } +static inline u8 mwifiex_is_tdls_link_setup(u8 status) +{ +	switch (status) { +	case TDLS_SETUP_COMPLETE: +	case TDLS_CHAN_SWITCHING: +	case TDLS_IN_BASE_CHAN: +	case TDLS_IN_OFF_CHAN: +		return true; +	default: +		break; +	} + +	return false; +} +  int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,  			     u32 func_init_shutdown);  int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); @@ -1458,6 +1482,9 @@ struct mwifiex_sta_node *  mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac);  struct mwifiex_sta_node *  mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac); +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv); +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv); +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv);  int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,  				 u8 action_code, u8 dialog_token,  				 u16 status_code, const u8 *extra_ies, @@ -1488,6 +1515,13 @@ void mwifiex_check_auto_tdls(unsigned long context);  void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);  void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);  void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_config_tdls_enable(struct mwifiex_private *priv); +int mwifiex_config_tdls_disable(struct mwifiex_private *priv); +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv); +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac); +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, +			  u8 primary_chan, u8 second_chan_offset, u8 band); +  int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,  					  struct host_cmd_ds_command *cmd,  					  void *data_buf); @@ -1522,6 +1556,12 @@ void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);  void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);  void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);  void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, +				    struct sk_buff *event); +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, +				      struct sk_buff *event_skb); +  #ifdef CONFIG_DEBUG_FS  void mwifiex_debugfs_init(void);  void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 77b9055a2d14..408b68460716 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -266,12 +266,17 @@ static const struct pci_device_id mwifiex_ids[] = {  	{  		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,  		PCI_ANY_ID, PCI_ANY_ID, 0, 0, -		.driver_data = (unsigned long) &mwifiex_pcie8766, +		.driver_data = (unsigned long)&mwifiex_pcie8766,  	},  	{  		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,  		PCI_ANY_ID, PCI_ANY_ID, 0, 0, -		.driver_data = (unsigned long) &mwifiex_pcie8897, +		.driver_data = (unsigned long)&mwifiex_pcie8897, +	}, +	{ +		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997, +		PCI_ANY_ID, PCI_ANY_ID, 0, 0, +		.driver_data = (unsigned long)&mwifiex_pcie8997,  	},  	{},  }; @@ -1082,6 +1087,7 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)  			card->txbd_rdptr++;  			break;  		case PCIE_DEVICE_ID_MARVELL_88W8897: +		case PCIE_DEVICE_ID_MARVELL_88W8997:  			card->txbd_rdptr += reg->ring_tx_start_ptr;  			break;  		} @@ -1179,6 +1185,7 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,  			card->txbd_wrptr++;  			break;  		case PCIE_DEVICE_ID_MARVELL_88W8897: +		case PCIE_DEVICE_ID_MARVELL_88W8997:  			card->txbd_wrptr += reg->ring_tx_start_ptr;  			break;  		} @@ -1807,6 +1814,8 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,  	if (!card->evt_buf_list[rdptr]) {  		skb_push(skb, INTF_HEADER_LEN); +		skb_put(skb, MAX_EVENT_SIZE - skb->len); +		memset(skb->data, 0, MAX_EVENT_SIZE);  		if (mwifiex_map_pci_memory(adapter, skb,  					   MAX_EVENT_SIZE,  					   PCI_DMA_FROMDEVICE)) @@ -2731,3 +2740,4 @@ MODULE_VERSION(PCIE_VERSION);  MODULE_LICENSE("GPL v2");  MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME);  MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME); +MODULE_FIRMWARE(PCIE8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 0e7ee8b72358..48e549c3b285 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -30,10 +30,12 @@  #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"  #define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" +#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcie8997_uapsta.bin"  #define PCIE_VENDOR_ID_MARVELL              (0x11ab)  #define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)  #define PCIE_DEVICE_ID_MARVELL_88W8897		(0x2b38) +#define PCIE_DEVICE_ID_MARVELL_88W8997		(0x2b42)  /* Constants for Buffer Descriptor (BD) rings */  #define MWIFIEX_MAX_TXRX_BD			0x20 @@ -197,7 +199,38 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {  	.sleep_cookie = 0,  	.fw_dump_ctrl = 0xcf4,  	.fw_dump_start = 0xcf8, -	.fw_dump_end = 0xcff +	.fw_dump_end = 0xcff, +}; + +static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { +	.cmd_addr_lo = PCIE_SCRATCH_0_REG, +	.cmd_addr_hi = PCIE_SCRATCH_1_REG, +	.cmd_size = PCIE_SCRATCH_2_REG, +	.fw_status = PCIE_SCRATCH_3_REG, +	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, +	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, +	.tx_rdptr = 0xC1A4, +	.tx_wrptr = 0xC1A8, +	.rx_rdptr = 0xC1A8, +	.rx_wrptr = 0xC1A4, +	.evt_rdptr = PCIE_SCRATCH_10_REG, +	.evt_wrptr = PCIE_SCRATCH_11_REG, +	.drv_rdy = PCIE_SCRATCH_12_REG, +	.tx_start_ptr = 16, +	.tx_mask = 0x0FFF0000, +	.tx_wrap_mask = 0x01FF0000, +	.rx_mask = 0x00000FFF, +	.rx_wrap_mask = 0x000001FF, +	.tx_rollover_ind = BIT(28), +	.rx_rollover_ind = BIT(12), +	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, +	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP, +	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP, +	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, +	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, +	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, +	.pfu_enabled = 1, +	.sleep_cookie = 0,  };  struct mwifiex_pcie_device { @@ -227,6 +260,15 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {  	.can_ext_scan = true,  }; +static const struct mwifiex_pcie_device mwifiex_pcie8997 = { +	.firmware       = PCIE8997_DEFAULT_FW_NAME, +	.reg            = &mwifiex_reg_8997, +	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, +	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, +	.can_dump_fw = false, +	.can_ext_scan = true, +}; +  struct mwifiex_evt_buf_desc {  	u64 paddr;  	u16 len; @@ -325,6 +367,7 @@ mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)  			return 1;  		break;  	case PCIE_DEVICE_ID_MARVELL_88W8897: +	case PCIE_DEVICE_ID_MARVELL_88W8997:  		if (((card->txbd_wrptr & reg->tx_mask) !=  		     (card->txbd_rdptr & reg->tx_mask)) ||  		    ((card->txbd_wrptr & reg->tx_rollover_ind) == diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index baf9715ddc10..5847863a2d6b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -527,7 +527,8 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,  			if (ch->flags & IEEE80211_CHAN_NO_IR)  				scan_chan_list[chan_idx].chan_scan_mode_bitmap -					|= MWIFIEX_PASSIVE_SCAN; +					|= (MWIFIEX_PASSIVE_SCAN | +					    MWIFIEX_HIDDEN_SSID_REPORT);  			else  				scan_chan_list[chan_idx].chan_scan_mode_bitmap  					&= ~MWIFIEX_PASSIVE_SCAN; @@ -823,6 +824,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,  	int i;  	u8 ssid_filter;  	struct mwifiex_ie_types_htcap *ht_cap; +	struct mwifiex_ie_types_bss_mode *bss_mode;  	/* The tlv_buf_len is calculated for each scan command.  The TLVs added  	   in this routine will be preserved since the routine that sends the @@ -908,6 +910,10 @@ mwifiex_config_scan(struct mwifiex_private *priv,  				wildcard_ssid_tlv->max_ssid_length =  							IEEE80211_MAX_SSID_LEN; +			if (!memcmp(user_scan_in->ssid_list[i].ssid, +				    "DIRECT-", 7)) +				wildcard_ssid_tlv->max_ssid_length = 0xfe; +  			memcpy(wildcard_ssid_tlv->ssid,  			       user_scan_in->ssid_list[i].ssid, ssid_len); @@ -968,6 +974,15 @@ mwifiex_config_scan(struct mwifiex_private *priv,  	else  		*max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; +	if (adapter->ext_scan) { +		bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; +		bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); +		bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); +		bss_mode->bss_mode = scan_cfg_out->bss_mode; +		tlv_pos += sizeof(bss_mode->header) + +			   le16_to_cpu(bss_mode->header.len); +	} +  	/* If the input config or adapter has the number of Probes set,  	   add tlv */  	if (num_probes) { @@ -1035,7 +1050,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,  			if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)  				(scan_chan_list +  				 chan_idx)->chan_scan_mode_bitmap -					|= MWIFIEX_PASSIVE_SCAN; +					|= (MWIFIEX_PASSIVE_SCAN | +					    MWIFIEX_HIDDEN_SSID_REPORT);  			else  				(scan_chan_list +  				 chan_idx)->chan_scan_mode_bitmap @@ -1586,6 +1602,62 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,  	return ret;  } +/* This function checks if SSID string contains all zeroes or length is zero */ +static bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid) +{ +	int idx; + +	for (idx = 0; idx < ssid->ssid_len; idx++) { +		if (ssid->ssid[idx]) +			return false; +	} + +	return true; +} + +/* This function checks if any hidden SSID found in passive scan channels + * and save those channels for specific SSID active scan + */ +static int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv, +					     struct cfg80211_bss *bss) +{ +	struct mwifiex_bssdescriptor *bss_desc; +	int ret; +	int chid; + +	/* Allocate and fill new bss descriptor */ +	bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); +	if (!bss_desc) +		return -ENOMEM; + +	ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); +	if (ret) +		goto done; + +	if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) { +		mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n"); +		for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) { +			if (priv->hidden_chan[chid].chan_number == +			    bss->channel->hw_value) +				break; + +			if (!priv->hidden_chan[chid].chan_number) { +				priv->hidden_chan[chid].chan_number = +					bss->channel->hw_value; +				priv->hidden_chan[chid].radio_type = +					bss->channel->band; +				priv->hidden_chan[chid].scan_type = +					MWIFIEX_SCAN_TYPE_ACTIVE; +				break; +			} +		} +	} + +done: +	kfree(bss_desc); +	return 0; +} +  static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,  					  struct cfg80211_bss *bss)  { @@ -1775,6 +1847,14 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,  				    .mac_address, ETH_ALEN))  				mwifiex_update_curr_bss_params(priv, bss);  			cfg80211_put_bss(priv->wdev.wiphy, bss); + +			if ((chan->flags & IEEE80211_CHAN_RADAR) || +			    (chan->flags & IEEE80211_CHAN_NO_IR)) { +				mwifiex_dbg(adapter, INFO, +					    "radar or passive channel %d\n", +					    channel); +				mwifiex_save_hidden_ssid_channels(priv, bss); +			}  		}  	} else {  		mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n"); @@ -1798,6 +1878,57 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)  	}  } +/* This function checks if any hidden SSID found in passive scan channels + * and do specific SSID active scan for those channels + */ +static int +mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv) +{ +	int ret; +	struct mwifiex_adapter *adapter = priv->adapter; +	u8 id = 0; +	struct mwifiex_user_scan_cfg  *user_scan_cfg; + +	if (adapter->active_scan_triggered) { +		adapter->active_scan_triggered = false; +		return 0; +	} + +	if (!priv->hidden_chan[0].chan_number) { +		mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n"); +		return 0; +	} +	user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); + +	if (!user_scan_cfg) +		return -ENOMEM; + +	memset(user_scan_cfg, 0, sizeof(*user_scan_cfg)); + +	for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) { +		if (!priv->hidden_chan[id].chan_number) +			break; +		memcpy(&user_scan_cfg->chan_list[id], +		       &priv->hidden_chan[id], +		       sizeof(struct mwifiex_user_scan_chan)); +	} + +	adapter->active_scan_triggered = true; +	user_scan_cfg->num_ssids = priv->scan_request->n_ssids; +	user_scan_cfg->ssid_list = priv->scan_request->ssids; + +	ret = mwifiex_scan_networks(priv, user_scan_cfg); +	kfree(user_scan_cfg); + +	memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan)); + +	if (ret) { +		dev_err(priv->adapter->dev, "scan failed: %d\n", ret); +		return ret; +	} + +	return 0; +}  static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)  {  	struct mwifiex_adapter *adapter = priv->adapter; @@ -1811,6 +1942,8 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)  		adapter->scan_processing = false;  		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); +		mwifiex_active_scan_req_for_passive_chan(priv); +  		if (!adapter->ext_scan)  			mwifiex_complete_scan(priv); @@ -1837,15 +1970,17 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)  		adapter->scan_processing = false;  		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); -		if (priv->scan_request) { -			mwifiex_dbg(adapter, INFO, -				    "info: aborting scan\n"); -			cfg80211_scan_done(priv->scan_request, 1); -			priv->scan_request = NULL; -		} else { -			priv->scan_aborting = false; -			mwifiex_dbg(adapter, INFO, -				    "info: scan already aborted\n"); +		if (!adapter->active_scan_triggered) { +			if (priv->scan_request) { +				mwifiex_dbg(adapter, INFO, +					    "info: aborting scan\n"); +				cfg80211_scan_done(priv->scan_request, 1); +				priv->scan_request = NULL; +			} else { +				priv->scan_aborting = false; +				mwifiex_dbg(adapter, INFO, +					    "info: scan already aborted\n"); +			}  		}  	} else {  		/* Get scan command from scan_pending_q and put to diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index a0b121f3460c..5d05c6fe6429 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -51,6 +51,10 @@ static unsigned long iface_work_flags;  static struct semaphore add_remove_card_sem; +static struct memory_type_mapping generic_mem_type_map[] = { +	{"DUMP", NULL, 0, 0xDD}, +}; +  static struct memory_type_mapping mem_type_mapping_tbl[] = {  	{"ITCM", NULL, 0, 0xF0},  	{"DTCM", NULL, 0, 0xF1}, @@ -91,6 +95,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)  		return -ENOMEM;  	card->func = func; +	card->device_id = id;  	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; @@ -107,6 +112,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)  		card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size;  		card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;  		card->can_dump_fw = data->can_dump_fw; +		card->fw_dump_enh = data->fw_dump_enh;  		card->can_auto_tdls = data->can_auto_tdls;  		card->can_ext_scan = data->can_ext_scan;  	} @@ -287,6 +293,8 @@ static int mwifiex_sdio_suspend(struct device *dev)  #define SDIO_DEVICE_ID_MARVELL_8887   (0x9135)  /* Device ID for SD8801 */  #define SDIO_DEVICE_ID_MARVELL_8801   (0x9139) +/* Device ID for SD8997 */ +#define SDIO_DEVICE_ID_MARVELL_8997   (0x9141)  /* WLAN IDs */ @@ -303,6 +311,8 @@ static const struct sdio_device_id mwifiex_ids[] = {  		.driver_data = (unsigned long)&mwifiex_sdio_sd8887},  	{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801),  		.driver_data = (unsigned long)&mwifiex_sdio_sd8801}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997), +		.driver_data = (unsigned long)&mwifiex_sdio_sd8997},  	{},  }; @@ -910,6 +920,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,  	if (!fwbuf)  		return -ENOMEM; +	sdio_claim_host(card->func); +  	/* Perform firmware data transfer */  	do {  		/* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY @@ -1014,6 +1026,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,  		offset += txlen;  	} while (true); +	sdio_release_host(card->func); +  	mwifiex_dbg(adapter, MSG,  		    "info: FW download over, size %d bytes\n", offset); @@ -1964,8 +1978,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)  	adapter->dev = &func->dev;  	strcpy(adapter->fw_name, card->firmware); -	adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; -	adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); +	if (card->fw_dump_enh) { +		adapter->mem_type_mapping_tbl = generic_mem_type_map; +		adapter->num_mem_types = 1; +	} else { +		adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; +		adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); +	}  	return 0;  } @@ -2107,26 +2126,46 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)  		    port, card->mp_data_port_mask);  } +static void mwifiex_recreate_adapter(struct sdio_mmc_card *card) +{ +	struct sdio_func *func = card->func; +	const struct sdio_device_id *device_id = card->device_id; + +	/* TODO mmc_hw_reset does not require destroying and re-probing the +	 * whole adapter. Hence there was no need to for this rube-goldberg +	 * design to reload the fw from an external workqueue. If we don't +	 * destroy the adapter we could reload the fw from +	 * mwifiex_main_work_queue directly. +	 * The real difficulty with fw reset is to restore all the user +	 * settings applied through ioctl. By destroying and recreating the +	 * adapter, we take the easy way out, since we rely on user space to +	 * restore them. We assume that user space will treat the new +	 * incarnation of the adapter(interfaces) as if they had been just +	 * discovered and initializes them from scratch. +	 */ + +	mwifiex_sdio_remove(func); + +	/* power cycle the adapter */ +	sdio_claim_host(func); +	mmc_hw_reset(func->card->host); +	sdio_release_host(func); + +	mwifiex_sdio_probe(func, device_id); +} +  static struct mwifiex_adapter *save_adapter;  static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)  {  	struct sdio_mmc_card *card = adapter->card; -	struct mmc_host *target = card->func->card->host; - -	/* The actual reset operation must be run outside of driver thread. -	 * This is because mmc_remove_host() will cause the device to be -	 * instantly destroyed, and the driver then needs to end its thread, -	 * leading to a deadlock. -	 * -	 * We run it in a totally independent workqueue. -	 */ -	mwifiex_dbg(adapter, WARN, "Resetting card...\n"); -	mmc_remove_host(target); -	/* 200ms delay is based on experiment with sdhci controller */ -	mdelay(200); -	target->rescan_entered = 0; /* rescan non-removable cards */ -	mmc_add_host(target); +	/* TODO card pointer is unprotected. If the adapter is removed +	 * physically, sdio core might trigger mwifiex_sdio_remove, before this +	 * workqueue is run, which will destroy the adapter struct. When this +	 * workqueue eventually exceutes it will dereference an invalid adapter +	 * pointer +	 */ +	mwifiex_recreate_adapter(card);  }  /* This function read/write firmware */ @@ -2138,8 +2177,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,  	int ret, tries;  	u8 ctrl_data = 0; -	sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl, -		    &ret); +	sdio_writeb(card->func, card->reg->fw_dump_host_ready, +		    card->reg->fw_dump_ctrl, &ret);  	if (ret) {  		mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n");  		return RDWR_STATUS_FAILURE; @@ -2155,10 +2194,10 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,  			break;  		if (doneflag && ctrl_data == doneflag)  			return RDWR_STATUS_DONE; -		if (ctrl_data != FW_DUMP_HOST_READY) { +		if (ctrl_data != card->reg->fw_dump_host_ready) {  			mwifiex_dbg(adapter, WARN, -				    "The ctrl reg was changed, re-try again!\n"); -			sdio_writeb(card->func, FW_DUMP_HOST_READY, +				    "The ctrl reg was changed, re-try again\n"); +			sdio_writeb(card->func, card->reg->fw_dump_host_ready,  				    card->reg->fw_dump_ctrl, &ret);  			if (ret) {  				mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); @@ -2167,7 +2206,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,  		}  		usleep_range(100, 200);  	} -	if (ctrl_data == FW_DUMP_HOST_READY) { +	if (ctrl_data == card->reg->fw_dump_host_ready) {  		mwifiex_dbg(adapter, ERROR,  			    "Fail to pull ctrl_data\n");  		return RDWR_STATUS_FAILURE; @@ -2300,10 +2339,129 @@ done:  	sdio_release_host(card->func);  } +static void mwifiex_sdio_generic_fw_dump(struct mwifiex_adapter *adapter) +{ +	struct sdio_mmc_card *card = adapter->card; +	struct memory_type_mapping *entry = &generic_mem_type_map[0]; +	unsigned int reg, reg_start, reg_end; +	u8 start_flag = 0, done_flag = 0; +	u8 *dbg_ptr, *end_ptr; +	enum rdwr_status stat; +	int ret = -1, tries; + +	if (!card->fw_dump_enh) +		return; + +	if (entry->mem_ptr) { +		vfree(entry->mem_ptr); +		entry->mem_ptr = NULL; +	} +	entry->mem_size = 0; + +	mwifiex_pm_wakeup_card(adapter); +	sdio_claim_host(card->func); + +	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); + +	stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); +	if (stat == RDWR_STATUS_FAILURE) +		goto done; + +	reg_start = card->reg->fw_dump_start; +	reg_end = card->reg->fw_dump_end; +	for (reg = reg_start; reg <= reg_end; reg++) { +		for (tries = 0; tries < MAX_POLL_TRIES; tries++) { +			start_flag = sdio_readb(card->func, reg, &ret); +			if (ret) { +				mwifiex_dbg(adapter, ERROR, +					    "SDIO read err\n"); +				goto done; +			} +			if (start_flag == 0) +				break; +			if (tries == MAX_POLL_TRIES) { +				mwifiex_dbg(adapter, ERROR, +					    "FW not ready to dump\n"); +				ret = -1; +				goto done; +			} +		} +		usleep_range(100, 200); +	} + +	entry->mem_ptr = vmalloc(0xf0000 + 1); +	if (!entry->mem_ptr) { +		ret = -1; +		goto done; +	} +	dbg_ptr = entry->mem_ptr; +	entry->mem_size = 0xf0000; +	end_ptr = dbg_ptr + entry->mem_size; + +	done_flag = entry->done_flag; +	mwifiex_dbg(adapter, DUMP, +		    "Start %s output, please wait...\n", entry->mem_name); + +	while (true) { +		stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); +		if (stat == RDWR_STATUS_FAILURE) +			goto done; +		for (reg = reg_start; reg <= reg_end; reg++) { +			*dbg_ptr = sdio_readb(card->func, reg, &ret); +			if (ret) { +				mwifiex_dbg(adapter, ERROR, +					    "SDIO read err\n"); +				goto done; +			} +			dbg_ptr++; +			if (dbg_ptr >= end_ptr) { +				u8 *tmp_ptr; + +				tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1); +				if (!tmp_ptr) +					goto done; + +				memcpy(tmp_ptr, entry->mem_ptr, +				       entry->mem_size); +				vfree(entry->mem_ptr); +				entry->mem_ptr = tmp_ptr; +				tmp_ptr = NULL; +				dbg_ptr = entry->mem_ptr + entry->mem_size; +				entry->mem_size += 0x4000; +				end_ptr = entry->mem_ptr + entry->mem_size; +			} +		} +		if (stat == RDWR_STATUS_DONE) { +			entry->mem_size = dbg_ptr - entry->mem_ptr; +			mwifiex_dbg(adapter, DUMP, "dump %s done size=0x%x\n", +				    entry->mem_name, entry->mem_size); +			ret = 0; +			break; +		} +	} +	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); + +done: +	if (ret) { +		mwifiex_dbg(adapter, ERROR, "firmware dump failed\n"); +		if (entry->mem_ptr) { +			vfree(entry->mem_ptr); +			entry->mem_ptr = NULL; +		} +		entry->mem_size = 0; +	} +	sdio_release_host(card->func); +} +  static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter)  { +	struct sdio_mmc_card *card = adapter->card; +  	mwifiex_drv_info_dump(adapter); -	mwifiex_sdio_fw_dump(adapter); +	if (card->fw_dump_enh) +		mwifiex_sdio_generic_fw_dump(adapter); +	else +		mwifiex_sdio_fw_dump(adapter);  	mwifiex_upload_device_dump(adapter);  } @@ -2510,3 +2668,4 @@ MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);  MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME);  MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME);  MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME); +MODULE_FIRMWARE(SD8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6f645cf47369..b9fbc5cf6262 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -35,6 +35,7 @@  #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin"  #define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin"  #define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin" +#define SD8997_DEFAULT_FW_NAME "mrvl/sd8997_uapsta.bin"  #define BLOCK_MODE	1  #define BYTE_MODE	0 @@ -222,6 +223,7 @@ struct mwifiex_sdio_card_reg {  	u8 cmd_cfg_1;  	u8 cmd_cfg_2;  	u8 cmd_cfg_3; +	u8 fw_dump_host_ready;  	u8 fw_dump_ctrl;  	u8 fw_dump_start;  	u8 fw_dump_end; @@ -257,11 +259,15 @@ struct sdio_mmc_card {  	bool supports_sdio_new_mode;  	bool has_control_mask;  	bool can_dump_fw; +	bool fw_dump_enh;  	bool can_auto_tdls;  	bool can_ext_scan;  	struct mwifiex_sdio_mpa_tx mpa_tx;  	struct mwifiex_sdio_mpa_rx mpa_rx; + +	/* needed for card reset */ +	const struct sdio_device_id *device_id;  };  struct mwifiex_sdio_device { @@ -275,6 +281,7 @@ struct mwifiex_sdio_device {  	bool supports_sdio_new_mode;  	bool has_control_mask;  	bool can_dump_fw; +	bool fw_dump_enh;  	bool can_auto_tdls;  	bool can_ext_scan;  }; @@ -350,6 +357,7 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {  	.cmd_cfg_1 = 0xb9,  	.cmd_cfg_2 = 0xba,  	.cmd_cfg_3 = 0xbb, +	.fw_dump_host_ready = 0xee,  	.fw_dump_ctrl = 0xe2,  	.fw_dump_start = 0xe3,  	.fw_dump_end = 0xea, @@ -361,6 +369,59 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {  				 0x59, 0x5c, 0x5d},  }; +static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = { +	.start_rd_port = 0, +	.start_wr_port = 0, +	.base_0_reg = 0xF8, +	.base_1_reg = 0xF9, +	.poll_reg = 0x5C, +	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | +			CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, +	.host_int_rsr_reg = 0x4, +	.host_int_status_reg = 0x0C, +	.host_int_mask_reg = 0x08, +	.status_reg_0 = 0xE8, +	.status_reg_1 = 0xE9, +	.sdio_int_mask = 0xff, +	.data_port_mask = 0xffffffff, +	.io_port_0_reg = 0xE4, +	.io_port_1_reg = 0xE5, +	.io_port_2_reg = 0xE6, +	.max_mp_regs = 196, +	.rd_bitmap_l = 0x10, +	.rd_bitmap_u = 0x11, +	.rd_bitmap_1l = 0x12, +	.rd_bitmap_1u = 0x13, +	.wr_bitmap_l = 0x14, +	.wr_bitmap_u = 0x15, +	.wr_bitmap_1l = 0x16, +	.wr_bitmap_1u = 0x17, +	.rd_len_p0_l = 0x18, +	.rd_len_p0_u = 0x19, +	.card_misc_cfg_reg = 0xd8, +	.card_cfg_2_1_reg = 0xd9, +	.cmd_rd_len_0 = 0xc0, +	.cmd_rd_len_1 = 0xc1, +	.cmd_rd_len_2 = 0xc2, +	.cmd_rd_len_3 = 0xc3, +	.cmd_cfg_0 = 0xc4, +	.cmd_cfg_1 = 0xc5, +	.cmd_cfg_2 = 0xc6, +	.cmd_cfg_3 = 0xc7, +	.fw_dump_host_ready = 0xcc, +	.fw_dump_ctrl = 0xf0, +	.fw_dump_start = 0xf1, +	.fw_dump_end = 0xf8, +	.func1_dump_reg_start = 0x10, +	.func1_dump_reg_end = 0x17, +	.func1_scratch_reg = 0xe8, +	.func1_spec_reg_num = 13, +	.func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, +				 0x60, 0x61, 0x62, 0x64, +				 0x65, 0x66, 0x68, 0x69, +				 0x6a}, +}; +  static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = {  	.start_rd_port = 0,  	.start_wr_port = 0, @@ -469,6 +530,22 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {  	.can_ext_scan = true,  }; +static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { +	.firmware = SD8997_DEFAULT_FW_NAME, +	.reg = &mwifiex_reg_sd8997, +	.max_ports = 32, +	.mp_agg_pkt_limit = 16, +	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, +	.mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, +	.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, +	.supports_sdio_new_mode = true, +	.has_control_mask = false, +	.can_dump_fw = true, +	.fw_dump_enh = true, +	.can_auto_tdls = false, +	.can_ext_scan = true, +}; +  static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {  	.firmware = SD8887_DEFAULT_FW_NAME,  	.reg = &mwifiex_reg_sd8887, diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 037adcd1f484..a49a80dd773e 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@  #include "11n.h"  #include "11ac.h" +static bool drcs; +module_param(drcs, bool, 0644); +MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0"); +  static bool disable_auto_ds;  module_param(disable_auto_ds, bool, 0);  MODULE_PARM_DESC(disable_auto_ds, @@ -1512,6 +1516,22 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,  }  static int +mwifiex_cmd_set_mc_policy(struct mwifiex_private *priv, +			  struct host_cmd_ds_command *cmd, +			  u16 cmd_action, void *data_buf) +{ +	struct host_cmd_ds_multi_chan_policy *mc_pol = &cmd->params.mc_policy; +	const u16 *drcs_info = data_buf; + +	mc_pol->action = cpu_to_le16(cmd_action); +	mc_pol->policy = cpu_to_le16(*drcs_info); +	cmd->command = cpu_to_le16(HostCmd_CMD_MC_POLICY); +	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_multi_chan_policy) + +				S_DS_GEN); +	return 0; +} + +static int  mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,  			 struct host_cmd_ds_command *cmd,  			 u16 cmd_action, void *data_buf) @@ -1576,6 +1596,50 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,  }  static int +mwifiex_cmd_tdls_config(struct mwifiex_private *priv, +			struct host_cmd_ds_command *cmd, +			u16 cmd_action, void *data_buf) +{ +	struct host_cmd_ds_tdls_config *tdls_config = &cmd->params.tdls_config; +	struct mwifiex_tdls_init_cs_params *config; +	struct mwifiex_tdls_config *init_config; +	u16 len; + +	cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG); +	cmd->size = cpu_to_le16(S_DS_GEN); +	tdls_config->tdls_action = cpu_to_le16(cmd_action); +	le16_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); + +	switch (cmd_action) { +	case ACT_TDLS_CS_ENABLE_CONFIG: +		init_config = data_buf; +		len = sizeof(*init_config); +		memcpy(tdls_config->tdls_data, init_config, len); +		break; +	case ACT_TDLS_CS_INIT: +		config = data_buf; +		len = sizeof(*config); +		memcpy(tdls_config->tdls_data, config, len); +		break; +	case ACT_TDLS_CS_STOP: +		len = sizeof(struct mwifiex_tdls_stop_cs_params); +		memcpy(tdls_config->tdls_data, data_buf, len); +		break; +	case ACT_TDLS_CS_PARAMS: +		len = sizeof(struct mwifiex_tdls_config_cs_params); +		memcpy(tdls_config->tdls_data, data_buf, len); +		break; +	default: +		mwifiex_dbg(priv->adapter, ERROR, +			    "Unknown TDLS configuration\n"); +		return -ENOTSUPP; +	} + +	le16_add_cpu(&cmd->size, len); +	return 0; +} + +static int  mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,  		      struct host_cmd_ds_command *cmd,  		      void *data_buf) @@ -1933,10 +1997,12 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,  		if (priv->bss_mode == NL80211_IFTYPE_ADHOC)  			cmd_ptr->params.bss_mode.con_type =  				CONNECTION_TYPE_ADHOC; -		else if (priv->bss_mode == NL80211_IFTYPE_STATION) +		else if (priv->bss_mode == NL80211_IFTYPE_STATION || +			 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT)  			cmd_ptr->params.bss_mode.con_type =  				CONNECTION_TYPE_INFRA; -		else if (priv->bss_mode == NL80211_IFTYPE_AP) +		else if (priv->bss_mode == NL80211_IFTYPE_AP || +			 priv->bss_mode == NL80211_IFTYPE_P2P_GO)  			cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP;  		cmd_ptr->size = cpu_to_le16(sizeof(struct  				host_cmd_ds_set_bss_mode) + S_DS_GEN); @@ -1958,6 +2024,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,  	case HostCmd_CMD_TDLS_OPER:  		ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);  		break; +	case HostCmd_CMD_TDLS_CONFIG: +		ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action, +					      data_buf); +		break;  	case HostCmd_CMD_CHAN_REPORT_REQUEST:  		ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,  							    data_buf); @@ -1966,6 +2036,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,  		ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,  						   data_buf);  		break; +	case HostCmd_CMD_MC_POLICY: +		ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action, +						data_buf); +		break;  	default:  		mwifiex_dbg(priv->adapter, ERROR,  			    "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -2082,6 +2156,18 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)  			if (ret)  				return -1;  		} + +		if (drcs) { +			adapter->drcs_enabled = true; +			if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) +				ret = mwifiex_send_cmd(priv, +						       HostCmd_CMD_MC_POLICY, +						       HostCmd_ACT_GEN_SET, 0, +						       &adapter->drcs_enabled, +						       true); +			if (ret) +				return -1; +		}  	}  	/* get tx rate */ diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b645884b3b97..87b69d8ad120 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -599,6 +599,7 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv,  				    "info: key: GTK is set\n");  			priv->wpa_is_gtk_set = true;  			priv->scan_block = false; +			priv->port_open = true;  		}  	} @@ -629,6 +630,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,  			mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n");  			priv->wpa_is_gtk_set = true;  			priv->scan_block = false; +			priv->port_open = true;  		}  	} @@ -893,7 +895,7 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,  	case ACT_TDLS_DELETE:  		if (reason) {  			if (!node || reason == TDLS_ERR_LINK_NONEXISTENT) -				mwifiex_dbg(priv->adapter, ERROR, +				mwifiex_dbg(priv->adapter, MSG,  					    "TDLS link delete for %pM failed: reason %d\n",  					    cmd_tdls_oper->peer_mac, reason);  			else @@ -1191,12 +1193,15 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,  		break;  	case HostCmd_CMD_TDLS_OPER:  		ret = mwifiex_ret_tdls_oper(priv, resp); +	case HostCmd_CMD_MC_POLICY:  		break;  	case HostCmd_CMD_CHAN_REPORT_REQUEST:  		break;  	case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:  		ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp);  		break; +	case HostCmd_CMD_TDLS_CONFIG: +		break;  	default:  		mwifiex_dbg(adapter, ERROR,  			    "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 848de2621958..3d18c585e543 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -54,6 +54,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)  	priv->media_connected = false;  	priv->scan_block = false; +	priv->port_open = false;  	if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&  	    ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { @@ -153,6 +154,7 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,  	struct mwifiex_sta_node *sta_ptr;  	struct mwifiex_tdls_generic_event *tdls_evt =  			(void *)event_skb->data + sizeof(adapter->event_cause); +	u8 *mac = tdls_evt->peer_mac;  	/* reserved 2 bytes are not mandatory in tdls event */  	if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) - @@ -175,6 +177,59 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,  					   le16_to_cpu(tdls_evt->u.reason_code),  					   GFP_KERNEL);  		break; +	case TDLS_EVENT_CHAN_SWITCH_RESULT: +		mwifiex_dbg(adapter, EVENT, "tdls channel switch result :\n"); +		mwifiex_dbg(adapter, EVENT, +			    "status=0x%x, reason=0x%x cur_chan=%d\n", +			    tdls_evt->u.switch_result.status, +			    tdls_evt->u.switch_result.reason, +			    tdls_evt->u.switch_result.cur_chan); + +		/* tdls channel switch failed */ +		if (tdls_evt->u.switch_result.status != 0) { +			switch (tdls_evt->u.switch_result.cur_chan) { +			case TDLS_BASE_CHANNEL: +				sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; +				break; +			case TDLS_OFF_CHANNEL: +				sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; +				break; +			default: +				break; +			} +			return ret; +		} + +		/* tdls channel switch success */ +		switch (tdls_evt->u.switch_result.cur_chan) { +		case TDLS_BASE_CHANNEL: +			if (sta_ptr->tdls_status == TDLS_IN_BASE_CHAN) +				break; +			mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, +								  false); +			sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; +			break; +		case TDLS_OFF_CHANNEL: +			if (sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) +				break; +			mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, +								  true); +			sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; +			break; +		default: +			break; +		} + +		break; +	case TDLS_EVENT_START_CHAN_SWITCH: +		mwifiex_dbg(adapter, EVENT, "tdls start channel switch...\n"); +		sta_ptr->tdls_status = TDLS_CHAN_SWITCHING; +		break; +	case TDLS_EVENT_CHAN_SWITCH_STOPPED: +		mwifiex_dbg(adapter, EVENT, +			    "tdls chan switch stopped, reason=%d\n", +			    tdls_evt->u.cs_stop_reason); +		break;  	default:  		break;  	} @@ -182,6 +237,145 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,  	return ret;  } +static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv, +					 struct mwifiex_ie_types_header *tlv) +{ +	struct mwifiex_tx_pause_tlv *tp; +	struct mwifiex_sta_node *sta_ptr; +	unsigned long flags; + +	tp = (void *)tlv; +	mwifiex_dbg(priv->adapter, EVENT, +		    "uap tx_pause: %pM pause=%d, pkts=%d\n", +		    tp->peermac, tp->tx_pause, +		    tp->pkt_cnt); + +	if (ether_addr_equal(tp->peermac, priv->netdev->dev_addr)) { +		if (tp->tx_pause) +			priv->port_open = false; +		else +			priv->port_open = true; +	} else if (is_multicast_ether_addr(tp->peermac)) { +		mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); +	} else { +		spin_lock_irqsave(&priv->sta_list_spinlock, flags); +		sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); +		spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + +		if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { +			sta_ptr->tx_pause = tp->tx_pause; +			mwifiex_update_ralist_tx_pause(priv, tp->peermac, +						       tp->tx_pause); +		} +	} +} + +static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, +					 struct mwifiex_ie_types_header *tlv) +{ +	struct mwifiex_tx_pause_tlv *tp; +	struct mwifiex_sta_node *sta_ptr; +	int status; +	unsigned long flags; + +	tp = (void *)tlv; +	mwifiex_dbg(priv->adapter, EVENT, +		    "sta tx_pause: %pM pause=%d, pkts=%d\n", +		    tp->peermac, tp->tx_pause, +		    tp->pkt_cnt); + +	if (ether_addr_equal(tp->peermac, priv->cfg_bssid)) { +		if (tp->tx_pause) +			priv->port_open = false; +		else +			priv->port_open = true; +	} else { +		if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) +			return; + +		status = mwifiex_get_tdls_link_status(priv, tp->peermac); +		if (mwifiex_is_tdls_link_setup(status)) { +			spin_lock_irqsave(&priv->sta_list_spinlock, flags); +			sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); +			spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + +			if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { +				sta_ptr->tx_pause = tp->tx_pause; +				mwifiex_update_ralist_tx_pause(priv, +							       tp->peermac, +							       tp->tx_pause); +			} +		} +	} +} + +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, +				      struct sk_buff *event_skb) +{ +	struct mwifiex_ie_types_multi_chan_info *chan_info; +	u16 status; + +	chan_info = (void *)event_skb->data + sizeof(u32); + +	if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) { +		mwifiex_dbg(priv->adapter, ERROR, +			    "unknown TLV in chan_info event\n"); +		return; +	} + +	status = le16_to_cpu(chan_info->status); + +	if (status) { +		mwifiex_dbg(priv->adapter, EVENT, +			    "multi-channel operation started\n"); +	} else { +		mwifiex_dbg(priv->adapter, EVENT, +			    "multi-channel operation over\n"); +	} +} + +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, +				    struct sk_buff *event_skb) +{ +	struct mwifiex_ie_types_header *tlv; +	u16 tlv_type, tlv_len; +	int tlv_buf_left; + +	if (!priv->media_connected) { +		mwifiex_dbg(priv->adapter, ERROR, +			    "tx_pause event while disconnected; bss_role=%d\n", +			    priv->bss_role); +		return; +	} + +	tlv_buf_left = event_skb->len - sizeof(u32); +	tlv = (void *)event_skb->data + sizeof(u32); + +	while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { +		tlv_type = le16_to_cpu(tlv->type); +		tlv_len  = le16_to_cpu(tlv->len); +		if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > +		    tlv_buf_left) { +			mwifiex_dbg(priv->adapter, ERROR, +				    "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", +				    tlv_len, tlv_buf_left); +			break; +		} +		if (tlv_type == TLV_TYPE_TX_PAUSE) { +			if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) +				mwifiex_process_sta_tx_pause(priv, tlv); +			else +				mwifiex_process_uap_tx_pause(priv, tlv); +		} + +		tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + +				tlv_len; +		tlv = (void *)((u8 *)tlv + tlv_len + +			       sizeof(struct mwifiex_ie_types_header)); +	} + +} +  /*  * This function handles coex events generated by firmware  */ @@ -359,7 +553,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)  	case EVENT_PS_AWAKE:  		mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); -		if (!adapter->pps_uapsd_mode && +		if (!adapter->pps_uapsd_mode && priv->port_open &&  		    priv->media_connected && adapter->sleep_period.period) {  				adapter->pps_uapsd_mode = true;  				mwifiex_dbg(adapter, EVENT, @@ -438,6 +632,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)  	case EVENT_PORT_RELEASE:  		mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); +		priv->port_open = true;  		break;  	case EVENT_EXT_SCAN_REPORT: @@ -573,6 +768,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)  		ret = mwifiex_parse_tdls_event(priv, adapter->event_skb);  		break; +	case EVENT_TX_DATA_PAUSE: +		mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); +		mwifiex_process_tx_pause_event(priv, adapter->event_skb); +		break; + +	case EVENT_MULTI_CHAN_INFO: +		mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); +		mwifiex_process_multi_chan_event(priv, adapter->event_skb); +		break; +  	case EVENT_TX_STATUS_REPORT:  		mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n");  		mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d8b7d9c20450..a6c8a4f7bfe9 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -66,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,  	if (status <= 0) {  		if (status == 0)  			status = -ETIMEDOUT; -		mwifiex_dbg(adapter, ERROR, -			    "cmd_wait_q terminated: %d\n", status); +		mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n", +			    status);  		mwifiex_cancel_all_pending_cmd(adapter);  		return status;  	} diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 2faa1bc42abe..b3e163de9899 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -49,7 +49,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,  		tid = skb->priority;  		tid_down = mwifiex_wmm_downgrade_tid(priv, tid); -		if (status == TDLS_SETUP_COMPLETE) { +		if (mwifiex_is_tdls_link_setup(status)) {  			ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);  			ra_list->tdls_link = true;  			tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; @@ -164,7 +164,7 @@ static void mwifiex_tdls_add_aid(struct mwifiex_private *priv,  	pos = (void *)skb_put(skb, 4);  	*pos++ = WLAN_EID_AID;  	*pos++ = 2; -	*pos++ = le16_to_cpu(assoc_rsp->a_id); +	memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id));  	return;  } @@ -355,6 +355,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,  	extcap->ieee_hdr.len = 8;  	memset(extcap->ext_capab, 0, 8);  	extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED; +	extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH;  	if (priv->adapter->is_hw_11ac_capable)  		extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED; @@ -1071,6 +1072,11 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)  			for (i = 0; i < MAX_NUM_TID; i++)  				sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;  		} +		if (sta_ptr->tdls_cap.extcap.ext_capab[3] & +		    WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) { +			mwifiex_config_tdls_enable(priv); +			mwifiex_config_tdls_cs_params(priv); +		}  		memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));  		mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); @@ -1141,7 +1147,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv,  	spin_lock_irqsave(&priv->sta_list_spinlock, flags);  	list_for_each_entry(sta_ptr, &priv->sta_list, list) { -		if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { +		if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) {  			ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr);  			peer++;  			count++; @@ -1295,7 +1301,7 @@ void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,  			if ((link_status == TDLS_NOT_SETUP) &&  			    (peer->tdls_status == TDLS_SETUP_INPROGRESS))  				peer->failure_count++; -			else if (link_status == TDLS_SETUP_COMPLETE) +			else if (mwifiex_is_tdls_link_setup(link_status))  				peer->failure_count = 0;  			peer->tdls_status = link_status; @@ -1367,7 +1373,7 @@ void mwifiex_check_auto_tdls(unsigned long context)  		if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) ||  		     !tdls_peer->rssi) && -		    tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) { +		    mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) {  			tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;  			mwifiex_dbg(priv->adapter, MSG,  				    "teardown TDLS link,peer=%pM rssi=%d\n", @@ -1416,3 +1422,67 @@ void mwifiex_clean_auto_tdls(struct mwifiex_private *priv)  		mwifiex_flush_auto_tdls_list(priv);  	}  } + +static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable) +{ +	struct mwifiex_tdls_config config; + +	config.enable = cpu_to_le16(enable); +	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, +				ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true); +} + +int mwifiex_config_tdls_enable(struct mwifiex_private *priv) +{ +	return mwifiex_config_tdls(priv, true); +} + +int mwifiex_config_tdls_disable(struct mwifiex_private *priv) +{ +	return mwifiex_config_tdls(priv, false); +} + +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv) +{ +	struct mwifiex_tdls_config_cs_params config_tdls_cs_params; + +	config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME; +	config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK; +	config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK; + +	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, +				ACT_TDLS_CS_PARAMS, 0, +				&config_tdls_cs_params, true); +} + +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac) +{ +	struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params; + +	ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac); + +	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, +				ACT_TDLS_CS_STOP, 0, +				&stop_tdls_cs_params, true); +} + +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, +			  u8 primary_chan, u8 second_chan_offset, u8 band) +{ +	struct mwifiex_tdls_init_cs_params start_tdls_cs_params; + +	ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac); +	start_tdls_cs_params.primary_chan = primary_chan; +	start_tdls_cs_params.second_chan_offset = second_chan_offset; +	start_tdls_cs_params.band = band; + +	start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME); +	start_tdls_cs_params.switch_timeout = +					cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT); +	start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS; +	start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY; + +	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, +				ACT_TDLS_CS_INIT, 0, +				&start_tdls_cs_params, true); +} diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 5ed9b794053e..8b1e5b5d47fe 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -370,8 +370,28 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,  			/* consumes ack_skb */  			skb_complete_wifi_ack(ack_skb, !tx_status->status);  		} else { +			/* Remove broadcast address which was added by driver */ +			memmove(ack_skb->data + +				sizeof(struct ieee80211_hdr_3addr) + +				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), +				ack_skb->data + +				sizeof(struct ieee80211_hdr_3addr) + +				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + +				ETH_ALEN, ack_skb->len - +				(sizeof(struct ieee80211_hdr_3addr) + +				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + +				ETH_ALEN)); +			ack_skb->len = ack_skb->len - ETH_ALEN; +			/* Remove driver's proprietary header including 2 bytes +			 * of packet length and pass actual management frame buffer +			 * to cfg80211. +			 */  			cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, -						ack_skb->data, ack_skb->len, +						ack_skb->data + +						MWIFIEX_MGMT_FRAME_HEADER_SIZE + +						sizeof(u16), ack_skb->len - +						(MWIFIEX_MGMT_FRAME_HEADER_SIZE +						 + sizeof(u16)),  						!tx_status->status, GFP_ATOMIC);  			dev_kfree_skb_any(ack_skb);  		} diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index b74930054b8c..4d5a6e3b6361 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -808,7 +808,7 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv,  			     struct mwifiex_uap_bss_param *bss_cfg,  			     struct cfg80211_chan_def chandef)  { -	u8 config_bands = 0; +	u8 config_bands = 0, old_bands = priv->adapter->config_bands;  	priv->bss_chandef = chandef; @@ -834,6 +834,11 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv,  	}  	priv->adapter->config_bands = config_bands; + +	if (old_bands != config_bands) { +		mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy); +		mwifiex_dnld_txpwr_table(priv); +	}  }  int mwifiex_config_start_uap(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 7bc1f850e3b7..46c972a650a4 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -41,6 +41,8 @@ static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv,  	mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:",  			 event->data, event->len); +	skb_push(event, MWIFIEX_BSS_START_EVT_FIX_SIZE); +  	while ((evt_len >= sizeof(tlv_hdr->header))) {  		tlv_hdr = (struct mwifiex_ie_types_data *)curr;  		tlv_len = le16_to_cpu(tlv_hdr->header.len); @@ -176,6 +178,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)  		break;  	case EVENT_UAP_BSS_IDLE:  		priv->media_connected = false; +		priv->port_open = false;  		if (netif_carrier_ok(priv->netdev))  			netif_carrier_off(priv->netdev);  		mwifiex_stop_net_dev_queue(priv->netdev, adapter); @@ -185,6 +188,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)  		break;  	case EVENT_UAP_BSS_ACTIVE:  		priv->media_connected = true; +		priv->port_open = true;  		if (!netif_carrier_ok(priv->netdev))  			netif_carrier_on(priv->netdev);  		mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); @@ -192,6 +196,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)  	case EVENT_UAP_BSS_START:  		mwifiex_dbg(adapter, EVENT,  			    "AP EVENT: event id: %#x\n", eventcause); +		priv->port_open = false;  		memcpy(priv->netdev->dev_addr, adapter->event_body + 2,  		       ETH_ALEN);  		if (priv->hist_data) @@ -297,6 +302,16 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)  		mwifiex_bt_coex_wlan_param_update_event(priv,  							adapter->event_skb);  		break; +	case EVENT_TX_DATA_PAUSE: +		mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); +		mwifiex_process_tx_pause_event(priv, adapter->event_skb); +		break; + +	case EVENT_MULTI_CHAN_INFO: +		mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); +		mwifiex_process_multi_chan_event(priv, adapter->event_skb); +		break; +  	default:  		mwifiex_dbg(adapter, EVENT,  			    "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index aada93425f80..5e789b2e06ea 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -47,6 +47,11 @@ static struct usb_device_id mwifiex_usb_table[] = {  	{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2,  				       USB_CLASS_VENDOR_SPEC,  				       USB_SUBCLASS_VENDOR_SPEC, 0xff)}, +	/* 8997 */ +	{USB_DEVICE(USB8XXX_VID, USB8997_PID_1)}, +	{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8997_PID_2, +				       USB_CLASS_VENDOR_SPEC, +				       USB_SUBCLASS_VENDOR_SPEC, 0xff)},  	{ }	/* Terminating entry */  }; @@ -244,9 +249,11 @@ setup_for_next:  	if (card->rx_cmd_ep == context->ep) {  		mwifiex_usb_submit_rx_urb(context, size);  	} else { -		context->skb = NULL; -		if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) +		if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){  			mwifiex_usb_submit_rx_urb(context, size); +		}else{ +			context->skb = NULL; +		}  	}  	return; @@ -380,12 +387,14 @@ static int mwifiex_usb_probe(struct usb_interface *intf,  	case USB8797_PID_1:  	case USB8801_PID_1:  	case USB8897_PID_1: +	case USB8997_PID_1:  		card->usb_boot_state = USB8XXX_FW_DNLD;  		break;  	case USB8766_PID_2:  	case USB8797_PID_2:  	case USB8801_PID_2:  	case USB8897_PID_2: +	case USB8997_PID_2:  		card->usb_boot_state = USB8XXX_FW_READY;  		break;  	default: @@ -812,6 +821,12 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)  	adapter->dev = &card->udev->dev;  	switch (le16_to_cpu(card->udev->descriptor.idProduct)) { +	case USB8997_PID_1: +	case USB8997_PID_2: +		adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; +		strcpy(adapter->fw_name, USB8997_DEFAULT_FW_NAME); +		adapter->ext_scan = true; +		break;  	case USB8897_PID_1:  	case USB8897_PID_2:  		adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; @@ -868,8 +883,10 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,  	/* Allocate memory for transmit */  	fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL); -	if (!fwdata) +	if (!fwdata) { +		ret = -ENOMEM;  		goto fw_exit; +	}  	/* Allocate memory for receive */  	recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL); @@ -1119,3 +1136,4 @@ MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME);  MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME);  MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME);  MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); +MODULE_FIRMWARE(USB8997_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index 57e1a5736318..f0051f8c8981 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -32,6 +32,8 @@  #define USB8897_PID_2		0x2046  #define USB8801_PID_1		0x2049  #define USB8801_PID_2		0x204a +#define USB8997_PID_1		0x204d +#define USB8997_PID_2		0x204e  #define USB8XXX_FW_DNLD		1 @@ -46,6 +48,7 @@  #define USB8797_DEFAULT_FW_NAME	"mrvl/usb8797_uapsta.bin"  #define USB8801_DEFAULT_FW_NAME	"mrvl/usb8801_uapsta.bin"  #define USB8897_DEFAULT_FW_NAME	"mrvl/usb8897_uapsta.bin" +#define USB8997_DEFAULT_FW_NAME	"mrvl/usb8997_uapsta.bin"  #define FW_DNLD_TX_BUF_SIZE	620  #define FW_DNLD_RX_BUF_SIZE	2048 diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 790e61953abf..0cec8a64473e 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -126,6 +126,10 @@ static int num_of_items = ARRAY_SIZE(items);  int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)  { +	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) +		if (adapter->if_ops.init_fw_port) +			adapter->if_ops.init_fw_port(adapter); +  	adapter->init_wait_q_woken = true;  	wake_up_interruptible(&adapter->init_wait_q);  	return 0; @@ -496,16 +500,12 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)  int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,  			 struct cmd_ctrl_node *cmd_node)  { -	mwifiex_dbg(adapter, CMD, -		    "cmd completed: status=%d\n", +	WARN_ON(!cmd_node->wait_q_enabled); +	mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n",  		    adapter->cmd_wait_q.status); -	*(cmd_node->condition) = true; - -	if (adapter->cmd_wait_q.status == -ETIMEDOUT) -		mwifiex_dbg(adapter, ERROR, "cmd timeout\n"); -	else -		wake_up_interruptible(&adapter->cmd_wait_q.wait); +	*cmd_node->condition = true; +	wake_up_interruptible(&adapter->cmd_wait_q.wait);  	return 0;  } @@ -531,6 +531,65 @@ mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)  	return NULL;  } +static struct mwifiex_sta_node * +mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) +{ +	struct mwifiex_sta_node *node; + +	list_for_each_entry(node, &priv->sta_list, list) { +		if (node->tdls_status == status) +			return node; +	} + +	return NULL; +} + +/* If tdls channel switching is on-going, tx data traffic should be + * blocked until the switching stage completed. + */ +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) +{ +	struct mwifiex_sta_node *sta_ptr; + +	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) +		return false; + +	sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); +	if (sta_ptr) +		return true; + +	return false; +} + +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) +{ +	struct mwifiex_sta_node *sta_ptr; + +	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) +		return false; + +	sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); +	if (sta_ptr) +		return true; + +	return false; +} + +/* If tdls channel switching is on-going or tdls operate on off-channel, + * cmd path should be blocked until tdls switched to base-channel. + */ +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) +{ +	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) +		return true; + +	if (mwifiex_is_tdls_chan_switching(priv) || +	    mwifiex_is_tdls_off_chan(priv)) +		return false; + +	return true; +} +  /* This function will add a sta_node entry to associated station list   * table with the given mac address.   * If entry exist already, existing entry is returned. diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index a8ea21c3340c..173d3663c2e0 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -160,9 +160,10 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)  		ra_list->tdls_link = false;  		ra_list->ba_status = BA_SETUP_NONE;  		ra_list->amsdu_in_ampdu = false; +		ra_list->tx_paused = false;  		if (!mwifiex_queuing_ra_based(priv)) { -			if (mwifiex_get_tdls_link_status(priv, ra) == -			    TDLS_SETUP_COMPLETE) { +			if (mwifiex_is_tdls_link_setup +				(mwifiex_get_tdls_link_status(priv, ra))) {  				ra_list->tdls_link = true;  				ra_list->is_11n_enabled =  					mwifiex_tdls_peer_11n_enabled(priv, ra); @@ -448,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)  	}  } +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter) +{ +	return atomic_read(&adapter->bypass_tx_pending) ? false : true; +} +  /*   * This function checks if WMM Tx queue is empty.   */ @@ -459,6 +465,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)  	for (i = 0; i < adapter->priv_num; ++i) {  		priv = adapter->priv[i]; +		if (priv && !priv->port_open) +			continue;  		if (priv && atomic_read(&priv->wmm.tx_pkts_queued))  			return false;  	} @@ -580,6 +588,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)  	skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)  		mwifiex_write_data_complete(priv->adapter, skb, 0, -1); +	skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) +		mwifiex_write_data_complete(priv->adapter, skb, 0, -1); +	atomic_set(&priv->adapter->bypass_tx_pending, 0); +  	idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);  	idr_destroy(&priv->ack_status_frames);  } @@ -603,6 +615,88 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,  	return NULL;  } +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, +				    u8 tx_pause) +{ +	struct mwifiex_ra_list_tbl *ra_list; +	u32 pkt_cnt = 0, tx_pkts_queued; +	unsigned long flags; +	int i; + +	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + +	for (i = 0; i < MAX_NUM_TID; ++i) { +		ra_list = mwifiex_wmm_get_ralist_node(priv, i, mac); +		if (ra_list && ra_list->tx_paused != tx_pause) { +			pkt_cnt += ra_list->total_pkt_count; +			ra_list->tx_paused = tx_pause; +			if (tx_pause) +				priv->wmm.pkts_paused[i] += +					ra_list->total_pkt_count; +			else +				priv->wmm.pkts_paused[i] -= +					ra_list->total_pkt_count; +		} +	} + +	if (pkt_cnt) { +		tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); +		if (tx_pause) +			tx_pkts_queued -= pkt_cnt; +		else +			tx_pkts_queued += pkt_cnt; + +		atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); +		atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); +	} +	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* This function update non-tdls peer ralist tx_pause while + * tdls channel swithing + */ +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, +					       u8 *mac, u8 tx_pause) +{ +	struct mwifiex_ra_list_tbl *ra_list; +	u32 pkt_cnt = 0, tx_pkts_queued; +	unsigned long flags; +	int i; + +	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + +	for (i = 0; i < MAX_NUM_TID; ++i) { +		list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list, +				    list) { +			if (!memcmp(ra_list->ra, mac, ETH_ALEN)) +				continue; + +			if (ra_list && ra_list->tx_paused != tx_pause) { +				pkt_cnt += ra_list->total_pkt_count; +				ra_list->tx_paused = tx_pause; +				if (tx_pause) +					priv->wmm.pkts_paused[i] += +						ra_list->total_pkt_count; +				else +					priv->wmm.pkts_paused[i] -= +						ra_list->total_pkt_count; +			} +		} +	} + +	if (pkt_cnt) { +		tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); +		if (tx_pause) +			tx_pkts_queued -= pkt_cnt; +		else +			tx_pkts_queued += pkt_cnt; + +		atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); +		atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); +	} +	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} +  /*   * This function retrieves an RA list node for a given TID and   * RA address pair. @@ -670,6 +764,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv,  }  /* + * This function adds a packet to bypass TX queue. + * This is special TX queue for packets which can be sent even when port_open + * is false. + */ +void +mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, +				   struct sk_buff *skb) +{ +	skb_queue_tail(&priv->bypass_txq, skb); +} + +/*   * This function adds a packet to WMM queue.   *   * In disconnected state the packet is immediately dropped and the @@ -723,6 +829,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,  	    !mwifiex_is_skb_mgmt_frame(skb)) {  		switch (tdls_status) {  		case TDLS_SETUP_COMPLETE: +		case TDLS_CHAN_SWITCHING: +		case TDLS_IN_BASE_CHAN: +		case TDLS_IN_OFF_CHAN:  			ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down,  							      ra);  			tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; @@ -765,7 +874,10 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,  		atomic_set(&priv->wmm.highest_queued_prio,  			   priv->tos_to_tid_inv[tid_down]); -	atomic_inc(&priv->wmm.tx_pkts_queued); +	if (ra_list->tx_paused) +		priv->wmm.pkts_paused[tid_down]++; +	else +		atomic_inc(&priv->wmm.tx_pkts_queued);  	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);  } @@ -970,7 +1082,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,  			priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv; -			if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0) +			if (!priv_tmp->port_open || +			    (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0))  				continue;  			/* iterate over the WMM queues of the BSS */ @@ -987,7 +1100,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,  				list_for_each_entry(ptr, &tid_ptr->ra_list,  						    list) { -					if (!skb_queue_empty(&ptr->skb_head)) +					if (!ptr->tx_paused && +					    !skb_queue_empty(&ptr->skb_head))  						/* holds both locks */  						goto found;  				} @@ -1339,6 +1453,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)  	return 0;  } +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter) +{ +	struct mwifiex_tx_param tx_param; +	struct sk_buff *skb; +	struct mwifiex_txinfo *tx_info; +	struct mwifiex_private *priv; +	int i; + +	if (adapter->data_sent || adapter->tx_lock_flag) +		return; + +	for (i = 0; i < adapter->priv_num; ++i) { +		priv = adapter->priv[i]; + +		if (skb_queue_empty(&priv->bypass_txq)) +			continue; + +		skb = skb_dequeue(&priv->bypass_txq); +		tx_info = MWIFIEX_SKB_TXCB(skb); + +		/* no aggregation for bypass packets */ +		tx_param.next_pkt_len = 0; + +		if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { +			skb_queue_head(&priv->bypass_txq, skb); +			tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; +		} else { +			atomic_dec(&adapter->bypass_tx_pending); +		} +	} +} +  /*   * This function transmits the highest priority packet awaiting in the   * WMM Queues. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 48ece0b35591..38f09762bd2f 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)  void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,  				 struct sk_buff *skb); +void mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, +					struct sk_buff *skb);  void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra);  void mwifiex_rotate_priolists(struct mwifiex_private *priv,  			      struct mwifiex_ra_list_tbl *ra, int tid);  int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter);  void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter);  int mwifiex_is_ralist_valid(struct mwifiex_private *priv,  			    struct mwifiex_ra_list_tbl *ra_list, int tid); @@ -126,6 +130,10 @@ struct mwifiex_ra_list_tbl *  mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid,  			    const u8 *ra_addr);  u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, +				    u8 tx_pause); +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, +					       u8 *mac, u8 tx_pause);  struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private  					*priv, u8 tid, const u8 *ra_addr); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 77361af68b18..9420fc61c2e6 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5019,35 +5019,36 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  		memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16);  		rcu_read_unlock(); -	} -	if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && -	    !priv->ap_fw) { -		rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); -		if (rc) -			goto out; +		if (changed & BSS_CHANGED_ASSOC) { +			if (!priv->ap_fw) { +				rc = mwl8k_cmd_set_rate(hw, vif, +							ap_legacy_rates, +							ap_mcs_rates); +				if (rc) +					goto out; -		rc = mwl8k_cmd_use_fixed_rate_sta(hw); -		if (rc) -			goto out; -	} else { -		if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc && -		    priv->ap_fw) { -			int idx; -			int rate; +				rc = mwl8k_cmd_use_fixed_rate_sta(hw); +				if (rc) +					goto out; +			} else { +				int idx; +				int rate; -			/* Use AP firmware specific rate command. -			 */ -			idx = ffs(vif->bss_conf.basic_rates); -			if (idx) -				idx--; +				/* Use AP firmware specific rate command. +				 */ +				idx = ffs(vif->bss_conf.basic_rates); +				if (idx) +					idx--; -			if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) -				rate = mwl8k_rates_24[idx].hw_value; -			else -				rate = mwl8k_rates_50[idx].hw_value; +				if (hw->conf.chandef.chan->band == +				    IEEE80211_BAND_2GHZ) +					rate = mwl8k_rates_24[idx].hw_value; +				else +					rate = mwl8k_rates_50[idx].hw_value; -			mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); +				mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); +			}  		}  	} diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index c410180479e6..7b5c554323c7 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2321,8 +2321,6 @@ void free_orinocodev(struct orinoco_private *priv)  	struct orinoco_rx_data *rx_data, *temp;  	struct orinoco_scan_data *sd, *sdtemp; -	wiphy_unregister(wiphy); -  	/* If the tasklet is scheduled when we call tasklet_kill it  	 * will run one final time. However the tasklet will only  	 * drain priv->rx_list if the hw is still available. */ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index c0a27377d9e2..a956f965a1e5 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -118,6 +118,7 @@ static void orinoco_cs_detach(struct pcmcia_device *link)  	orinoco_cs_release(link); +	wiphy_unregister(priv_to_wiphy(priv));  	free_orinocodev(priv);  }				/* orinoco_cs_detach */ diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 1b543e30eff7..048693b6c6c2 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -223,13 +223,15 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,  	err = orinoco_if_add(priv, 0, 0, NULL);  	if (err) {  		printk(KERN_ERR PFX "orinoco_if_add() failed\n"); -		goto fail; +		goto fail_wiphy;  	}  	pci_set_drvdata(pdev, priv);  	return 0; + fail_wiphy: +	wiphy_unregister(priv_to_wiphy(priv));   fail:  	free_irq(pdev->irq, priv); @@ -263,6 +265,7 @@ static void orinoco_nortel_remove_one(struct pci_dev *pdev)  	iowrite16(0, card->bridge_io + 10);  	orinoco_if_del(priv); +	wiphy_unregister(priv_to_wiphy(priv));  	free_irq(pdev->irq, priv);  	free_orinocodev(priv);  	pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 74219d59d7e1..4938a2208a37 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -173,13 +173,15 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,  	err = orinoco_if_add(priv, 0, 0, NULL);  	if (err) {  		printk(KERN_ERR PFX "orinoco_if_add() failed\n"); -		goto fail; +		goto fail_wiphy;  	}  	pci_set_drvdata(pdev, priv);  	return 0; + fail_wiphy: +	wiphy_unregister(priv_to_wiphy(priv));   fail:  	free_irq(pdev->irq, priv); @@ -203,6 +205,7 @@ static void orinoco_pci_remove_one(struct pci_dev *pdev)  	struct orinoco_private *priv = pci_get_drvdata(pdev);  	orinoco_if_del(priv); +	wiphy_unregister(priv_to_wiphy(priv));  	free_irq(pdev->irq, priv);  	free_orinocodev(priv);  	pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 8b045236b6e0..221352027779 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -262,13 +262,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,  	err = orinoco_if_add(priv, 0, 0, NULL);  	if (err) {  		printk(KERN_ERR PFX "orinoco_if_add() failed\n"); -		goto fail; +		goto fail_wiphy;  	}  	pci_set_drvdata(pdev, priv);  	return 0; + fail_wiphy: +	wiphy_unregister(priv_to_wiphy(priv));   fail:  	free_irq(pdev->irq, priv); @@ -299,6 +301,7 @@ static void orinoco_plx_remove_one(struct pci_dev *pdev)  	struct orinoco_pci_card *card = priv->card;  	orinoco_if_del(priv); +	wiphy_unregister(priv_to_wiphy(priv));  	free_irq(pdev->irq, priv);  	free_orinocodev(priv);  	pci_iounmap(pdev, priv->hw.iobase); diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 91f05442de28..26a57d773d30 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -1502,6 +1502,7 @@ static inline void ezusb_delete(struct ezusb_priv *upriv)  	if (upriv->dev) {  		struct orinoco_private *priv = ndev_priv(upriv->dev);  		orinoco_if_del(priv); +		wiphy_unregister(priv_to_wiphy(upriv));  		free_orinocodev(priv);  	}  } @@ -1695,6 +1696,7 @@ static int ezusb_probe(struct usb_interface *interface,  	if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {  		upriv->dev = NULL;  		err("%s: orinoco_if_add() failed", __func__); +		wiphy_unregister(priv_to_wiphy(priv));  		goto error;  	}  	upriv->dev = priv->ndev; diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index b6cc9ff47fc2..40d72312f3df 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)  		(struct rsi_91x_sdiodev *)adapter->rsi_dev;  	u32 len;  	u32 num_blocks; +	const u8 *fw;  	const struct firmware *fw_entry = NULL;  	u32 block_size = dev->tx_blk_size;  	int status = 0; @@ -200,6 +201,12 @@ static int rsi_load_ta_instructions(struct rsi_common *common)  		return status;  	} +	/* Copy firmware into DMA-accessible memory */ +	fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); +	if (!fw) { +		status = -ENOMEM; +		goto out; +	}  	len = fw_entry->size;  	if (len % 4) @@ -210,7 +217,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)  	rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);  	rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); -	status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks); +	status = rsi_copy_to_card(common, fw, len, num_blocks); +	kfree(fw); + +out:  	release_firmware(fw_entry);  	return status;  } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 1106ce76707e..de4900862836 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -146,7 +146,12 @@ static int rsi_load_ta_instructions(struct rsi_common *common)  		return status;  	} +	/* Copy firmware into DMA-accessible memory */  	fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); +	if (!fw) { +		status = -ENOMEM; +		goto out; +	}  	len = fw_entry->size;  	if (len % 4) @@ -158,6 +163,9 @@ static int rsi_load_ta_instructions(struct rsi_common *common)  	rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);  	status = rsi_copy_to_card(common, fw, len, num_blocks); +	kfree(fw); + +out:  	release_firmware(fw_entry);  	return status;  } diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 2b4ef256c6b9..de62f5dcb62f 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -240,7 +240,6 @@ config RT2X00_LIB_USB  config RT2X00_LIB  	tristate -	select AVERAGE  config RT2X00_LIB_FIRMWARE  	bool diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index afba0739c3b8..78cc035b2d17 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -54,7 +54,7 @@  #define CSR_REG_BASE			0x0400  #define CSR_REG_SIZE			0x0100  #define EEPROM_BASE			0x0000 -#define EEPROM_SIZE			0x006a +#define EEPROM_SIZE			0x006e  #define BBP_BASE			0x0000  #define BBP_SIZE			0x0060  #define RF_BASE				0x0004 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9bb398bed9bb..3282ddb766f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -254,6 +254,8 @@ struct link_qual {  	int tx_failed;  }; +DECLARE_EWMA(rssi, 1024, 8) +  /*   * Antenna settings about the currently active link.   */ @@ -285,7 +287,7 @@ struct link_ant {  	 * Similar to the avg_rssi in the link_qual structure  	 * this value is updated by using the walking average.  	 */ -	struct ewma rssi_ant; +	struct ewma_rssi rssi_ant;  };  /* @@ -314,7 +316,7 @@ struct link {  	/*  	 * Currently active average RSSI value  	 */ -	struct ewma avg_rssi; +	struct ewma_rssi avg_rssi;  	/*  	 * Work structure for scheduling periodic link tuning. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 9b941c0c1264..017188e5a736 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -33,15 +33,11 @@   */  #define DEFAULT_RSSI		-128 -/* Constants for EWMA calculations. */ -#define RT2X00_EWMA_FACTOR	1024 -#define RT2X00_EWMA_WEIGHT	8 - -static inline int rt2x00link_get_avg_rssi(struct ewma *ewma) +static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)  {  	unsigned long avg; -	avg = ewma_read(ewma); +	avg = ewma_rssi_read(ewma);  	if (avg)  		return -avg; @@ -76,8 +72,7 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,  static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)  { -	ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR, -		  RT2X00_EWMA_WEIGHT); +	ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);  }  static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) @@ -225,12 +220,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,  	/*  	 * Update global RSSI  	 */ -	ewma_add(&link->avg_rssi, -rxdesc->rssi); +	ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);  	/*  	 * Update antenna RSSI  	 */ -	ewma_add(&ant->rssi_ant, -rxdesc->rssi); +	ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);  }  void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) @@ -285,8 +280,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)  	 */  	rt2x00dev->link.count = 0;  	memset(qual, 0, sizeof(*qual)); -	ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR, -		  RT2X00_EWMA_WEIGHT); +	ewma_rssi_init(&rt2x00dev->link.avg_rssi);  	/*  	 * Restore the VGC level as stored in the registers, diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 3b3a88b53b11..585d0883c7e5 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct sk_buff *skb = ieee80211_beacon_get(hw, vif); +	struct rtl_tcb_desc tcb_desc; -	if (skb) -		rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL); +	if (skb) { +		memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); +		rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); +	}  }  static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c index c8058aa73ecf..629125658b87 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c @@ -200,7 +200,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); -	struct rtl92c_firmware_header *pfwheader; +	struct rtlwifi_firmware_header *pfwheader;  	u8 *pfwdata;  	u32 fwsize;  	int err; @@ -209,7 +209,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,  	if (!rtlhal->pfirmware)  		return 1; -	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; +	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;  	pfwdata = rtlhal->pfirmware;  	fwsize = rtlhal->fwsize;  	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, @@ -219,10 +219,10 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,  		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,  			 "Firmware Version(%d), Signature(%#x), Size(%d)\n",  			  pfwheader->version, pfwheader->signature, -			  (int)sizeof(struct rtl92c_firmware_header)); +			  (int)sizeof(struct rtlwifi_firmware_header)); -		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); -		fwsize = fwsize - sizeof(struct rtl92c_firmware_header); +		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); +		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);  	}  	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h index 05e944e451f4..21bd4a5337ab 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h @@ -37,7 +37,7 @@  #define FW_8192C_POLLING_TIMEOUT_COUNT		3000  #define IS_FW_HEADER_EXIST(_pfwhdr)		\ -	((_pfwhdr->signature&0xFFFF) == 0x88E1) +	((le16_to_cpu(_pfwhdr->signature) & 0xFFFF) == 0x88E1)  #define USE_OLD_WOWLAN_DEBUG_FW			0  #define H2C_88E_RSVDPAGE_LOC_LEN		5 @@ -131,25 +131,6 @@  #define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))  #define	FW_PWR_STATE_RF_OFF		0 -struct rtl92c_firmware_header { -	u16 signature; -	u8 category; -	u8 function; -	u16 version; -	u8 subversion; -	u8 rsvd1; -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	u16 ramcodesize; -	u16 rsvd2; -	u32 svnindex; -	u32 rsvd3; -	u32 rsvd4; -	u32 rsvd5; -}; -  enum rtl8188e_h2c_cmd {  	H2C_88E_RSVDPAGE = 0,  	H2C_88E_JOINBSSRPT = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 0aca6f47487c..03cbe4cf110b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -39,6 +39,7 @@  #define BT_RSSI_STATE_SPECIAL_LOW	BIT_OFFSET_LEN_MASK_32(2, 1)  #define BT_RSSI_STATE_BG_EDCA_LOW	BIT_OFFSET_LEN_MASK_32(3, 1)  #define BT_RSSI_STATE_TXPOWER_LOW	BIT_OFFSET_LEN_MASK_32(4, 1) +#define BT_MASK				0x00ffffff  #define RTLPRIV			(struct rtl_priv *)  #define GET_UNDECORATED_AVERAGE_RSSI(_priv)	\ @@ -312,7 +313,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)  	struct dig_t *digtable = &rtlpriv->dm_digtable;  	u32 isbt; -	/* modify DIG lower bound, deal with abnorally large false alarm */ +	/* modify DIG lower bound, deal with abnormally large false alarm */  	if (rtlpriv->falsealm_cnt.cnt_all > 10000) {  		digtable->large_fa_hit++;  		if (digtable->forbidden_igi < digtable->cur_igvalue) { @@ -1536,13 +1537,11 @@ static bool rtl92c_bt_state_change(struct ieee80211_hw *hw)  		return false;  	bt_state = rtl_read_byte(rtlpriv, 0x4fd); -	bt_tx = rtl_read_dword(rtlpriv, 0x488); -	bt_tx = bt_tx & 0x00ffffff; -	bt_pri = rtl_read_dword(rtlpriv, 0x48c); -	bt_pri = bt_pri & 0x00ffffff; +	bt_tx = rtl_read_dword(rtlpriv, 0x488) & BT_MASK; +	bt_pri = rtl_read_dword(rtlpriv, 0x48c) & BT_MASK;  	polling = rtl_read_dword(rtlpriv, 0x490); -	if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && +	if (bt_tx == BT_MASK && bt_pri == BT_MASK &&  	    polling == 0xffffffff && bt_state == 0xff)  		return false; diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 14b819ea8b71..43fcb25c885f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -221,7 +221,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); -	struct rtl92c_firmware_header *pfwheader; +	struct rtlwifi_firmware_header *pfwheader;  	u8 *pfwdata;  	u32 fwsize;  	int err; @@ -230,19 +230,19 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)  	if (!rtlhal->pfirmware)  		return 1; -	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; +	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;  	pfwdata = (u8 *)rtlhal->pfirmware;  	fwsize = rtlhal->fwsize;  	if (IS_FW_HEADER_EXIST(pfwheader)) {  		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,  			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",  			  pfwheader->version, pfwheader->signature, -			  (int)sizeof(struct rtl92c_firmware_header)); +			  (int)sizeof(struct rtlwifi_firmware_header)); -		rtlhal->fw_version = pfwheader->version; +		rtlhal->fw_version = le16_to_cpu(pfwheader->version);  		rtlhal->fw_subversion = pfwheader->subversion; -		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); -		fwsize = fwsize - sizeof(struct rtl92c_firmware_header); +		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); +		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);  	}  	_rtl92c_enable_fw_download(hw, true); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index e9f4281f5067..864806c19ca7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -69,25 +69,6 @@  	((GET_CVID_CUT_VERSION(version) == \  		CHIP_VENDOR_UMC_B_CUT) ? true : false) : false) -struct rtl92c_firmware_header { -	__le16 signature; -	u8 category; -	u8 function; -	__le16 version; -	u8 subversion; -	u8 rsvd1; -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	__le16 ramcodeSize; -	__le16 rsvd2; -	__le32 svnindex; -	__le32 rsvd3; -	__le32 rsvd4; -	__le32 rsvd5; -}; -  #define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))  #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h index c940a87175ca..74a479ac323d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -32,24 +32,15 @@  /*-------------------------------------------------------------------------   *	Chip specific   *-------------------------------------------------------------------------*/ -#define CHIP_8723			BIT(2) /* RTL8723 With BT feature */ -#define CHIP_8723_DRV_REV		BIT(3) /* RTL8723 Driver Revised */  #define NORMAL_CHIP			BIT(4)  #define CHIP_VENDOR_UMC			BIT(5)  #define CHIP_VENDOR_UMC_B_CUT		BIT(6) -#define IS_8723_SERIES(version)		\ -	(((version) & CHIP_8723) ? true : false) -  #define IS_92C_1T2R(version)		\  	(((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R))  #define IS_VENDOR_UMC(version)		\  	(((version) & CHIP_VENDOR_UMC) ? true : false) -#define IS_VENDOR_8723_A_CUT(version)	\ -	(((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ -	false : true) : false) -  #define CHIP_BONDING_92C_1T2R	0x1  #define CHIP_BONDING_IDENTIFIER(_value)	(((_value) >> 22) & 0x3) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 767358a553fb..25db369b5d18 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -818,26 +818,29 @@ static void _rtl92cu_init_usb_aggregation(struct ieee80211_hw *hw)  static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw)  { -	u16			value16; - +	u16 value16; +	u32 value32;  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | -		      RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | -		      RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); -	rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); +	value32 = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | +		   RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | +		   RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&value32));  	/* Accept all multicast address */  	rtl_write_dword(rtlpriv,  REG_MAR, 0xFFFFFFFF);  	rtl_write_dword(rtlpriv,  REG_MAR + 4, 0xFFFFFFFF);  	/* Accept all management frames */  	value16 = 0xFFFF; -	rtl92c_set_mgt_filter(hw, value16); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, +				      (u8 *)(&value16));  	/* Reject all control frame - default value is 0 */ -	rtl92c_set_ctrl_filter(hw, 0x0); +	value16 = 0x0; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, +				      (u8 *)(&value16));  	/* Accept all data frames */  	value16 = 0xFFFF; -	rtl92c_set_data_filter(hw, value16); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DATA_FILTER, +				      (u8 *)(&value16));  }  static void _rtl92cu_init_beacon_parameters(struct ieee80211_hw *hw) @@ -988,17 +991,6 @@ static void _InitPABias(struct ieee80211_hw *hw)  	}  } -static void _update_mac_setting(struct ieee80211_hw *hw) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); -	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - -	mac->rx_conf = rtl_read_dword(rtlpriv, REG_RCR); -	mac->rx_mgt_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP0); -	mac->rx_ctrl_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP1); -	mac->rx_data_filter = rtl_read_word(rtlpriv, REG_RXFLTMAP2); -} -  int rtl92cu_hw_init(struct ieee80211_hw *hw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1068,7 +1060,6 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)  	}  	_rtl92cu_hw_configure(hw);  	_InitPABias(hw); -	_update_mac_setting(hw);  	rtl92c_dm_init(hw);  exit:  	local_irq_restore(flags); @@ -1620,7 +1611,6 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));  	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));  	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); -	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));  	enum wireless_mode wirelessmode = mac->mode;  	u8 idx = 0; @@ -1829,63 +1819,10 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)  						u4b_ac_param);  				break;  			default: -				RT_ASSERT(false, -					  "SetHwReg8185(): invalid aci: %d !\n", +				RT_ASSERT(false, "invalid aci: %d !\n",  					  e_aci);  				break;  			} -			if (rtlusb->acm_method != EACMWAY2_SW) -				rtlpriv->cfg->ops->set_hw_reg(hw, -					 HW_VAR_ACM_CTRL, &e_aci); -			break; -		} -	case HW_VAR_ACM_CTRL:{ -			u8 e_aci = *val; -			union aci_aifsn *p_aci_aifsn = (union aci_aifsn *) -							(&(mac->ac[0].aifs)); -			u8 acm = p_aci_aifsn->f.acm; -			u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); - -			acm_ctrl = -			    acm_ctrl | ((rtlusb->acm_method == 2) ? 0x0 : 0x1); -			if (acm) { -				switch (e_aci) { -				case AC0_BE: -					acm_ctrl |= AcmHw_BeqEn; -					break; -				case AC2_VI: -					acm_ctrl |= AcmHw_ViqEn; -					break; -				case AC3_VO: -					acm_ctrl |= AcmHw_VoqEn; -					break; -				default: -					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, -						 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n", -						 acm); -					break; -				} -			} else { -				switch (e_aci) { -				case AC0_BE: -					acm_ctrl &= (~AcmHw_BeqEn); -					break; -				case AC2_VI: -					acm_ctrl &= (~AcmHw_ViqEn); -					break; -				case AC3_VO: -					acm_ctrl &= (~AcmHw_VoqEn); -					break; -				default: -					RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, -						 "switch case not processed\n"); -					break; -				} -			} -			RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, -				 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", -				 acm_ctrl); -			rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);  			break;  		}  	case HW_VAR_RCR:{ @@ -1999,12 +1936,15 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)  		}  	case HW_VAR_MGT_FILTER:  		rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *)val); +		mac->rx_mgt_filter = *(u16 *)val;  		break;  	case HW_VAR_CTRL_FILTER:  		rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *)val); +		mac->rx_ctrl_filter = *(u16 *)val;  		break;  	case HW_VAR_DATA_FILTER:  		rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *)val); +		mac->rx_data_filter = *(u16 *)val;  		break;  	default:  		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -2280,7 +2220,6 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); -	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));  	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;  	u8 u1tmp = 0;  	bool actuallyset = false; @@ -2357,20 +2296,7 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)  		if (ppsc->pwrdown_mode && e_rfpowerstate_toset == ERFOFF) {  			/* Enable register area 0x0-0xc. */  			rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); -			if (IS_HARDWARE_TYPE_8723U(rtlhal)) { -				/* -				 * We should configure HW PDn source for WiFi -				 * ONLY, and then our HW will be set in -				 * power-down mode if PDn source from all -				 * functions are configured. -				 */ -				u1tmp = rtl_read_byte(rtlpriv, -						      REG_MULTI_FUNC_CTRL); -				rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, -					       (u1tmp|WL_HWPDN_EN)); -			} else { -				rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); -			} +			rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812);  		}  		if (e_rfpowerstate_toset == ERFOFF) {  			if (ppsc->reg_rfps_level  & RT_RF_OFF_LEVL_ASPM) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 490a7cf7c702..035713311a4a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -69,8 +69,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)  		chip_version = NORMAL_CHIP;  		chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0);  		chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); -		/* RTL8723 with BT function. */ -		chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0);  		if (IS_VENDOR_UMC(chip_version))  			chip_version |= ((value32 & CHIP_VER_RTL_MASK) ?  					 CHIP_VENDOR_UMC_B_CUT : 0); @@ -78,10 +76,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)  			value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM);  			chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) ==  				 CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); -		} else if (IS_8723_SERIES(chip_version)) { -			value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); -			chip_version |= ((value32 & RF_RL_ID) ? -					  CHIP_8723_DRV_REV : 0);  		}  	}  	rtlhal->version  = (enum version_8192c)chip_version; @@ -114,12 +108,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)  	case VERSION_NORMAL_UMC_CHIP_88C_B_CUT:  		versionid = "NORMAL_UMC_CHIP_88C_B_CUT";  		break; -	case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: -		versionid = "NORMAL_UMC_CHIP_8723_1T1R_A_CUT"; -		break; -	case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: -		versionid = "NORMAL_UMC_CHIP_8723_1T1R_B_CUT"; -		break;  	case VERSION_TEST_CHIP_92C:  		versionid = "TEST_CHIP_92C";  		break; @@ -405,59 +393,9 @@ void rtl92c_disable_interrupt(struct ieee80211_hw *hw)  void rtl92c_set_qos(struct ieee80211_hw *hw, int aci)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw); -	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); -	u32 u4b_ac_param;  	rtl92c_dm_init_edca_turbo(hw); -	u4b_ac_param = (u32) mac->ac[aci].aifs; -	u4b_ac_param |= -	    ((u32) le16_to_cpu(mac->ac[aci].cw_min) & 0xF) << -	    AC_PARAM_ECW_MIN_OFFSET; -	u4b_ac_param |= -	    ((u32) le16_to_cpu(mac->ac[aci].cw_max) & 0xF) << -	    AC_PARAM_ECW_MAX_OFFSET; -	u4b_ac_param |= (u32) le16_to_cpu(mac->ac[aci].tx_op) << -			 AC_PARAM_TXOP_OFFSET; -	RT_TRACE(rtlpriv, COMP_QOS, DBG_LOUD, "queue:%x, ac_param:%x\n", -		 aci, u4b_ac_param); -	switch (aci) { -	case AC1_BK: -		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); -		break; -	case AC0_BE: -		rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); -		break; -	case AC2_VI: -		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); -		break; -	case AC3_VO: -		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); -		break; -	default: -		RT_ASSERT(false, "invalid aci: %d !\n", aci); -		break; -	} -} - -/*------------------------------------------------------------------------- - * HW MAC Address - *-------------------------------------------------------------------------*/ -void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr) -{ -	u32 i; -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	for (i = 0 ; i < ETH_ALEN ; i++) -		rtl_write_byte(rtlpriv, (REG_MACID + i), *(addr+i)); - -	RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, -		 "MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n", -		 rtl_read_byte(rtlpriv, REG_MACID), -		 rtl_read_byte(rtlpriv, REG_MACID+1), -		 rtl_read_byte(rtlpriv, REG_MACID+2), -		 rtl_read_byte(rtlpriv, REG_MACID+3), -		 rtl_read_byte(rtlpriv, REG_MACID+4), -		 rtl_read_byte(rtlpriv, REG_MACID+5)); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, (u8 *)&aci);  }  void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size) @@ -656,47 +594,6 @@ void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T)  	rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, value);  } -u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	return rtl_read_word(rtlpriv, REG_RXFLTMAP0); -} - -void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	rtl_write_word(rtlpriv, REG_RXFLTMAP0, filter); -} - -u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	return rtl_read_word(rtlpriv, REG_RXFLTMAP1); -} - -void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	rtl_write_word(rtlpriv, REG_RXFLTMAP1, filter); -} - -u16 rtl92c_get_data_filter(struct ieee80211_hw *hw) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	return rtl_read_word(rtlpriv,  REG_RXFLTMAP2); -} - -void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter) -{ -	struct rtl_priv *rtlpriv = rtl_priv(hw); - -	rtl_write_word(rtlpriv, REG_RXFLTMAP2, filter); -}  /*==============================================================*/  static u8 _rtl92c_query_rxpwrpercentage(char antpower) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h index e34f0f14ccd7..553a4bfac668 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -48,7 +48,6 @@ void rtl92c_set_qos(struct ieee80211_hw *hw, int aci);  /*---------------------------------------------------------------   *	Hardware init functions   *---------------------------------------------------------------*/ -void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr);  void rtl92c_init_interrupt(struct ieee80211_hw *hw);  void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size); @@ -73,15 +72,6 @@ void rtl92c_init_retry_function(struct ieee80211_hw *hw);  void rtl92c_disable_fast_edca(struct ieee80211_hw *hw);  void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T); -/* For filter */ -u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw); -void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter); -u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw); -void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter); -u16 rtl92c_get_data_filter(struct ieee80211_hw *hw); -void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter); - -  u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw);  struct rx_fwinfo_92c { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 23806c243a53..fd4a5353d216 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -321,6 +321,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {  	{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/  	{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/  	{RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ +	{RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/  	{RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/  	{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/  	{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 587b8c505a76..7c1db7e7572d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -420,7 +420,7 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)  		 "dm_DIG() Before: Recover_cnt=%d, rx_gain_min=%x\n",  		 de_digtable->recover_cnt, de_digtable->rx_gain_min); -	/* deal with abnorally large false alarm */ +	/* deal with abnormally large false alarm */  	if (falsealm_cnt->cnt_all > 10000) {  		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,  			 "dm_DIG(): Abnormally false alarm case\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h index 1646e7c3d0f8..8a38daa316cb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -110,28 +110,6 @@  #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)	\  	SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) -struct rtl92d_firmware_header { -	u16 signature; -	u8 category; -	u8 function; -	u16 version; -	u8 subversion; -	u8 rsvd1; - -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	u16 ramcodeSize; -	u16 rsvd2; - -	u32 svnindex; -	u32 rsvd3; - -	u32 rsvd4; -	u32 rsvd5; -}; -  int rtl92d_download_fw(struct ieee80211_hw *hw);  void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,  			 u32 cmd_len, u8 *p_cmdbuffer); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 1961b8e28dc1..bb06fe836fe7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3515,14 +3515,14 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw)  	for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;  	     rfpath++) {  		if (rtlhal->current_bandtype == BAND_ON_2_4G) { -			/* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ +			/* MOD_AG for RF path_A 0x18 BIT8,BIT16 */  			rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) |  				      BIT(18), 0);  			/* RF0x0b[16:14] =3b'111 */  			rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B,  				      0x1c000, 0x07);  		} else { -			/* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ +			/* MOD_AG for RF path_A 0x18 BIT8,BIT16 */  			rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) |  				      BIT(16) | BIT(18),  				      (BIT(16) | BIT(8)) >> 8); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c index 232865cc3ffd..0708eedd9671 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c @@ -198,7 +198,7 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); -	struct rtl92c_firmware_header *pfwheader; +	struct rtlwifi_firmware_header *pfwheader;  	u8 *pfwdata;  	u32 fwsize;  	int err; @@ -207,8 +207,8 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  	if (!rtlhal->pfirmware)  		return 1; -	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; -	rtlhal->fw_version = pfwheader->version; +	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware; +	rtlhal->fw_version = le16_to_cpu(pfwheader->version);  	rtlhal->fw_subversion = pfwheader->subversion;  	pfwdata = (u8 *)rtlhal->pfirmware;  	fwsize = rtlhal->fwsize; @@ -219,10 +219,10 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,  			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",  			  pfwheader->version, pfwheader->signature, -			  (int)sizeof(struct rtl92c_firmware_header)); +			  (int)sizeof(struct rtlwifi_firmware_header)); -		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); -		fwsize = fwsize - sizeof(struct rtl92c_firmware_header); +		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); +		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);  	} else {  		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,  			 "Firmware no Header, Signature(%#x)\n", diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h index 3e2a48e5fb4d..069da1e7e80a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h @@ -33,7 +33,7 @@  #define FW_8192C_POLLING_TIMEOUT_COUNT		3000  #define IS_FW_HEADER_EXIST(_pfwhdr)	\ -	((_pfwhdr->signature&0xFFF0) == 0x92E0) +	((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x92E0)  #define USE_OLD_WOWLAN_DEBUG_FW 0  #define H2C_92E_RSVDPAGE_LOC_LEN		5 @@ -89,25 +89,6 @@  #define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))  #define	FW_PWR_STATE_RF_OFF	0 -struct rtl92c_firmware_header { -	u16 signature; -	u8 category; -	u8 function; -	u16 version; -	u8 subversion; -	u8 rsvd1; -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	u16 ramcodesize; -	u16 rsvd2; -	u32 svnindex; -	u32 rsvd3; -	u32 rsvd4; -	u32 rsvd5; -}; -  enum rtl8192e_h2c_cmd {  	H2C_92E_RSVDPAGE = 0,  	H2C_92E_MSRRPT = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c index a863a44f9e16..018340aedf09 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c @@ -449,7 +449,7 @@ static void _rtl92ee_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,  				 "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n",  				  rate_section, path, txnum);  			break; -		}; +		}  	} else {  		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,  			 "Invalid Band %d\n", band); @@ -489,7 +489,7 @@ static u8 _rtl92ee_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,  				 "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n",  				  rate_section, path, txnum);  			break; -		}; +		}  	} else {  		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,  			 "Invalid Band %d()\n", band); @@ -853,7 +853,7 @@ static u8 _rtl92ee_get_rate_section_index(u32 regaddr)  		else if (regaddr >= 0xE20 && regaddr <= 0xE4C)  			index = (u8)((regaddr - 0xE20) / 4);  		break; -	}; +	}  	return index;  } diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 8280bab43df4..3859b3e3d158 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -205,9 +205,9 @@ bool rtl8723e_get_btc_status(void)  	return true;  } -static bool is_fw_header(struct rtl8723e_firmware_header *hdr) +static bool is_fw_header(struct rtlwifi_firmware_header *hdr)  { -	return (hdr->signature & 0xfff0) == 0x2300; +	return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x2300;  }  static struct rtl_hal_ops rtl8723e_hal_ops = { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 1017f02d7bf7..d091f1d5f91e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -209,9 +209,9 @@ bool rtl8723be_get_btc_status(void)  	return true;  } -static bool is_fw_header(struct rtl8723e_firmware_header *hdr) +static bool is_fw_header(struct rtlwifi_firmware_header *hdr)  { -	return (hdr->signature & 0xfff0) == 0x5300; +	return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x5300;  }  static struct rtl_hal_ops rtl8723be_hal_ops = { @@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);  module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);  module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);  module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);  module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,  		   bool, 0444);  MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c index dd698e7e9ace..a2f5e89bedfe 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -253,7 +253,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); -	struct rtl8723e_firmware_header *pfwheader; +	struct rtlwifi_firmware_header *pfwheader;  	u8 *pfwdata;  	u32 fwsize;  	int err; @@ -263,7 +263,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,  	if (!rtlhal->pfirmware)  		return 1; -	pfwheader = (struct rtl8723e_firmware_header *)rtlhal->pfirmware; +	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;  	pfwdata = rtlhal->pfirmware;  	fwsize = rtlhal->fwsize; @@ -275,10 +275,10 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,  		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,  			 "Firmware Version(%d), Signature(%#x), Size(%d)\n",  			 pfwheader->version, pfwheader->signature, -			 (int)sizeof(struct rtl8723e_firmware_header)); +			 (int)sizeof(struct rtlwifi_firmware_header)); -		pfwdata = pfwdata + sizeof(struct rtl8723e_firmware_header); -		fwsize = fwsize - sizeof(struct rtl8723e_firmware_header); +		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); +		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);  	}  	if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h index 3ebafc80972f..8ea372d1626e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h @@ -50,25 +50,6 @@ enum version_8723e {  	VERSION_UNKNOWN = 0xFF,  }; -struct rtl8723e_firmware_header { -	u16 signature; -	u8 category; -	u8 function; -	u16 version; -	u8 subversion; -	u8 rsvd1; -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	u16 ramcodesize; -	u16 rsvd2; -	u32 svnindex; -	u32 rsvd3; -	u32 rsvd4; -	u32 rsvd5; -}; -  enum rtl8723be_cmd {  	H2C_8723BE_RSVDPAGE = 0,  	H2C_8723BE_JOINBSSRPT = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c index 95e95626b632..525eb234627c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c @@ -210,7 +210,7 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  {  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); -	struct rtl8821a_firmware_header *pfwheader; +	struct rtlwifi_firmware_header *pfwheader;  	u8 *pfwdata;  	u32 fwsize;  	int err; @@ -228,8 +228,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  			return 1;  		pfwheader = -		  (struct rtl8821a_firmware_header *)rtlhal->wowlan_firmware; -		rtlhal->fw_version = pfwheader->version; +		  (struct rtlwifi_firmware_header *)rtlhal->wowlan_firmware; +		rtlhal->fw_version = le16_to_cpu(pfwheader->version);  		rtlhal->fw_subversion = pfwheader->subversion;  		pfwdata = (u8 *)rtlhal->wowlan_firmware;  		fwsize = rtlhal->wowlan_fwsize; @@ -238,8 +238,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  			return 1;  		pfwheader = -		  (struct rtl8821a_firmware_header *)rtlhal->pfirmware; -		rtlhal->fw_version = pfwheader->version; +		  (struct rtlwifi_firmware_header *)rtlhal->pfirmware; +		rtlhal->fw_version = le16_to_cpu(pfwheader->version);  		rtlhal->fw_subversion = pfwheader->subversion;  		pfwdata = (u8 *)rtlhal->pfirmware;  		fwsize = rtlhal->fwsize; @@ -255,8 +255,8 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)  			 "Firmware Version(%d), Signature(%#x)\n",  			 pfwheader->version, pfwheader->signature); -		pfwdata = pfwdata + sizeof(struct rtl8821a_firmware_header); -		fwsize = fwsize - sizeof(struct rtl8821a_firmware_header); +		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header); +		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);  	}  	if (rtlhal->mac_func_enable) { diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h index 591c14c0b9b5..8f5b4aade3c9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h @@ -34,10 +34,10 @@  #define FW_8821AE_POLLING_TIMEOUT_COUNT	6000  #define IS_FW_HEADER_EXIST_8812(_pfwhdr)	\ -	((_pfwhdr->signature&0xFFF0) == 0x9500) +	((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x9500)  #define IS_FW_HEADER_EXIST_8821(_pfwhdr)	\ -	((_pfwhdr->signature&0xFFF0) == 0x2100) +	((le16_to_cpu(_pfwhdr->signature) & 0xFFF0) == 0x2100)  #define USE_OLD_WOWLAN_DEBUG_FW 0 @@ -137,25 +137,6 @@  #define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))  #define	FW_PWR_STATE_RF_OFF	0 -struct rtl8821a_firmware_header { -	u16 signature; -	u8 category; -	u8 function; -	u16 version; -	u8 subversion; -	u8 rsvd1; -	u8 month; -	u8 date; -	u8 hour; -	u8 minute; -	u16 ramcodeSize; -	u16 rsvd2; -	u32 svnindex; -	u32 rsvd3; -	u32 rsvd4; -	u32 rsvd5; -}; -  enum rtl8812_c2h_evt {  	C2H_8812_DBG = 0,  	C2H_8812_LB = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 3236d44b459d..b7f18e2155eb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c @@ -2180,7 +2180,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw,  	rtl_write_byte(rtlpriv, MSR, bt_msr);  	rtlpriv->cfg->ops->led_control(hw, ledaction); -	if ((bt_msr & 0xfc) == MSR_AP) +	if ((bt_msr & MSR_MASK) == MSR_AP)  		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);  	else  		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h index 53668fc8f23e..1d6110f9c1fb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h @@ -429,6 +429,7 @@  #define	MSR_ADHOC				0x01  #define	MSR_INFRA				0x02  #define	MSR_AP					0x03 +#define MSR_MASK				0x03  #define	RRSR_RSC_OFFSET				21  #define	RRSR_SHORT_OFFSET			23 diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 2b770b5e2620..b90ca618b123 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -222,6 +222,25 @@ enum rf_tx_num {  #define	WOL_REASON_REALWOW_V2_WAKEUPPKT	BIT(9)  #define	WOL_REASON_REALWOW_V2_ACKLOST	BIT(10) +struct rtlwifi_firmware_header { +	__le16 signature; +	u8 category; +	u8 function; +	__le16 version; +	u8 subversion; +	u8 rsvd1; +	u8 month; +	u8 date; +	u8 hour; +	u8 minute; +	__le16 ramcodeSize; +	__le16 rsvd2; +	__le32 svnindex; +	__le32 rsvd3; +	__le32 rsvd4; +	__le32 rsvd5; +}; +  struct txpower_info_2g {  	u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];  	u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; @@ -2064,16 +2083,12 @@ struct rtl_tcb_desc {  	bool tx_enable_sw_calc_duration;  }; -struct rtl92c_firmware_header; -  struct rtl_wow_pattern {  	u8 type;  	u16 crc;  	u32 mask[4];  }; -struct rtl8723e_firmware_header; -  struct rtl_hal_ops {  	int (*init_sw_vars) (struct ieee80211_hw *hw);  	void (*deinit_sw_vars) (struct ieee80211_hw *hw); @@ -2177,7 +2192,7 @@ struct rtl_hal_ops {  	void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,  			      u32 cmd_len, u8 *p_cmdbuffer);  	bool (*get_btc_status) (void); -	bool (*is_fw_header)(struct rtl8723e_firmware_header *hdr); +	bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr);  	u32 (*rx_command_packet)(struct ieee80211_hw *hw,  				 struct rtl_stats status, struct sk_buff *skb);  	void (*add_wowlan_pattern)(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 0c0d5cd98514..7c355fff2c5e 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -118,7 +118,11 @@ static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	if (passive)  		scan_options |= WL1271_SCAN_OPT_PASSIVE; -	cmd->params.role_id = wlvif->role_id; +	/* scan on the dev role if the regular one is not started */ +	if (wlcore_is_p2p_mgmt(wlvif)) +		cmd->params.role_id = wlvif->dev_role_id; +	else +		cmd->params.role_id = wlvif->role_id;  	if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {  		ret = -EINVAL; diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index 67f2a0eec854..4be0409308cb 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -282,3 +282,30 @@ out:  	kfree(acx);  	return ret;  } + +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl) +{ +	struct acx_dynamic_fw_traces_cfg *acx; +	int ret; + +	wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d", +		     wl->dynamic_fw_traces); + +	acx = kzalloc(sizeof(*acx), GFP_KERNEL); +	if (!acx) { +		ret = -ENOMEM; +		goto out; +	} + +	acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces); + +	ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG, +				   acx, sizeof(*acx)); +	if (ret < 0) { +		wl1271_warning("acx config dynamic fw traces failed: %d", ret); +		goto out; +	} +out: +	kfree(acx); +	return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 4afccd4b9467..342a2993ef98 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -35,7 +35,8 @@ enum {  	ACX_PEER_CAP			 = 0x0056,  	ACX_INTERRUPT_NOTIFY		 = 0x0057,  	ACX_RX_BA_FILTER		 = 0x0058, -	ACX_AP_SLEEP_CFG                 = 0x0059 +	ACX_AP_SLEEP_CFG                 = 0x0059, +	ACX_DYNAMIC_TRACES_CFG		 = 0x005A,  };  /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -92,27 +93,26 @@ struct wl18xx_acx_checksum_state {  struct wl18xx_acx_error_stats { -	u32 error_frame; -	u32 error_null_Frame_tx_start; -	u32 error_numll_frame_cts_start; -	u32 error_bar_retry; -	u32 error_frame_cts_nul_flid; -} __packed; - -struct wl18xx_acx_debug_stats { -	u32 debug1; -	u32 debug2; -	u32 debug3; -	u32 debug4; -	u32 debug5; -	u32 debug6; -} __packed; - -struct wl18xx_acx_ring_stats { -	u32 prepared_descs; -	u32 tx_cmplt; +	u32 error_frame_non_ctrl; +	u32 error_frame_ctrl; +	u32 error_frame_during_protection; +	u32 null_frame_tx_start; +	u32 null_frame_cts_start; +	u32 bar_retry; +	u32 num_frame_cts_nul_flid; +	u32 tx_abort_failure; +	u32 tx_resume_failure; +	u32 rx_cmplt_db_overflow_cnt; +	u32 elp_while_rx_exch; +	u32 elp_while_tx_exch; +	u32 elp_while_tx; +	u32 elp_while_nvic_pending; +	u32 rx_excessive_frame_len; +	u32 burst_mismatch; +	u32 tbc_exch_mismatch;  } __packed; +#define NUM_OF_RATES_INDEXES 30  struct wl18xx_acx_tx_stats {  	u32 tx_prepared_descs;  	u32 tx_cmplt; @@ -122,7 +122,7 @@ struct wl18xx_acx_tx_stats {  	u32 tx_data_programmed;  	u32 tx_burst_programmed;  	u32 tx_starts; -	u32 tx_imm_resp; +	u32 tx_stop;  	u32 tx_start_templates;  	u32 tx_start_int_templates;  	u32 tx_start_fw_gen; @@ -131,13 +131,14 @@ struct wl18xx_acx_tx_stats {  	u32 tx_exch;  	u32 tx_retry_template;  	u32 tx_retry_data; +	u32 tx_retry_per_rate[NUM_OF_RATES_INDEXES];  	u32 tx_exch_pending;  	u32 tx_exch_expiry;  	u32 tx_done_template;  	u32 tx_done_data;  	u32 tx_done_int_template; -	u32 tx_frame_checksum; -	u32 tx_checksum_result; +	u32 tx_cfe1; +	u32 tx_cfe2;  	u32 frag_called;  	u32 frag_mpdu_alloc_failed;  	u32 frag_init_called; @@ -165,11 +166,8 @@ struct wl18xx_acx_rx_stats {  	u32 rx_cmplt_task;  	u32 rx_phy_hdr;  	u32 rx_timeout; +	u32 rx_rts_timeout;  	u32 rx_timeout_wa; -	u32 rx_wa_density_dropped_frame; -	u32 rx_wa_ba_not_expected; -	u32 rx_frame_checksum; -	u32 rx_checksum_result;  	u32 defrag_called;  	u32 defrag_init_called;  	u32 defrag_in_process_called; @@ -179,6 +177,7 @@ struct wl18xx_acx_rx_stats {  	u32 decrypt_key_not_found;  	u32 defrag_need_decrypt;  	u32 rx_tkip_replays; +	u32 rx_xfr;  } __packed;  struct wl18xx_acx_isr_stats { @@ -193,21 +192,13 @@ struct wl18xx_acx_pwr_stats {  	u32 connection_out_of_sync;  	u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD];  	u32 rcvd_awake_bcns_cnt; -} __packed; - -struct wl18xx_acx_event_stats { -	u32 calibration; -	u32 rx_mismatch; -	u32 rx_mem_empty; -} __packed; - -struct wl18xx_acx_ps_poll_stats { -	u32 ps_poll_timeouts; -	u32 upsd_timeouts; -	u32 upsd_max_ap_turn; -	u32 ps_poll_max_ap_turn; -	u32 ps_poll_utilization; -	u32 upsd_utilization; +	u32 sleep_time_count; +	u32 sleep_time_avg; +	u32 sleep_cycle_avg; +	u32 sleep_percent; +	u32 ap_sleep_active_conf; +	u32 ap_sleep_user_conf; +	u32 ap_sleep_counter;  } __packed;  struct wl18xx_acx_rx_filter_stats { @@ -227,11 +218,11 @@ struct wl18xx_acx_rx_rate_stats {  } __packed;  #define AGGR_STATS_TX_AGG	16 -#define AGGR_STATS_TX_RATE	16  #define AGGR_STATS_RX_SIZE_LEN	16  struct wl18xx_acx_aggr_stats { -	u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE]; +	u32 tx_agg_rate[AGGR_STATS_TX_AGG]; +	u32 tx_agg_len[AGGR_STATS_TX_AGG];  	u32 rx_size[AGGR_STATS_RX_SIZE_LEN];  } __packed; @@ -240,8 +231,6 @@ struct wl18xx_acx_aggr_stats {  struct wl18xx_acx_pipeline_stats {  	u32 hs_tx_stat_fifo_int;  	u32 hs_rx_stat_fifo_int; -	u32 tcp_tx_stat_fifo_int; -	u32 tcp_rx_stat_fifo_int;  	u32 enc_tx_stat_fifo_int;  	u32 enc_rx_stat_fifo_int;  	u32 rx_complete_stat_fifo_int; @@ -249,38 +238,61 @@ struct wl18xx_acx_pipeline_stats {  	u32 post_proc_swi;  	u32 sec_frag_swi;  	u32 pre_to_defrag_swi; -	u32 defrag_to_csum_swi; -	u32 csum_to_rx_xfer_swi; +	u32 defrag_to_rx_xfer_swi;  	u32 dec_packet_in;  	u32 dec_packet_in_fifo_full;  	u32 dec_packet_out; -	u32 cs_rx_packet_in; -	u32 cs_rx_packet_out;  	u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO]; +	u16 padding; +} __packed; + +#define DIVERSITY_STATS_NUM_OF_ANT	2 + +struct wl18xx_acx_diversity_stats { +	u32 num_of_packets_per_ant[DIVERSITY_STATS_NUM_OF_ANT]; +	u32 total_num_of_toggles;  } __packed; -struct wl18xx_acx_mem_stats { -	u32 rx_free_mem_blks; -	u32 tx_free_mem_blks; -	u32 fwlog_free_mem_blks; -	u32 fw_gen_free_mem_blks; +struct wl18xx_acx_thermal_stats { +	u16 irq_thr_low; +	u16 irq_thr_high; +	u16 tx_stop; +	u16 tx_resume; +	u16 false_irq; +	u16 adc_source_unexpected; +} __packed; + +#define WL18XX_NUM_OF_CALIBRATIONS_ERRORS 18 +struct wl18xx_acx_calib_failure_stats { +	u16 fail_count[WL18XX_NUM_OF_CALIBRATIONS_ERRORS]; +	u32 calib_count; +} __packed; + +struct wl18xx_roaming_stats { +	s32 rssi_level; +} __packed; + +struct wl18xx_dfs_stats { +	u32 num_of_radar_detections;  } __packed;  struct wl18xx_acx_statistics {  	struct acx_header header;  	struct wl18xx_acx_error_stats		error; -	struct wl18xx_acx_debug_stats		debug;  	struct wl18xx_acx_tx_stats		tx;  	struct wl18xx_acx_rx_stats		rx;  	struct wl18xx_acx_isr_stats		isr;  	struct wl18xx_acx_pwr_stats		pwr; -	struct wl18xx_acx_ps_poll_stats		ps_poll;  	struct wl18xx_acx_rx_filter_stats	rx_filter;  	struct wl18xx_acx_rx_rate_stats		rx_rate;  	struct wl18xx_acx_aggr_stats		aggr_size;  	struct wl18xx_acx_pipeline_stats	pipeline; -	struct wl18xx_acx_mem_stats		mem; +	struct wl18xx_acx_diversity_stats	diversity; +	struct wl18xx_acx_thermal_stats		thermal; +	struct wl18xx_acx_calib_failure_stats	calib; +	struct wl18xx_roaming_stats		roaming; +	struct wl18xx_dfs_stats			dfs;  } __packed;  struct wl18xx_acx_clear_statistics { @@ -367,6 +379,15 @@ struct acx_ap_sleep_cfg {  	u8 idle_conn_thresh;  } __packed; +/* + * ACX_DYNAMIC_TRACES_CFG + * configure the FW dynamic traces + */ +struct acx_dynamic_fw_traces_cfg { +	struct acx_header header; +	__le32 dynamic_fw_traces; +} __packed; +  int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,  				  u32 sdio_blk_size, u32 extra_mem_blks,  				  u32 len_field_size); @@ -380,5 +401,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,  int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);  int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);  int wl18xx_acx_ap_sleep(struct wl1271 *wl); +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl);  #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 5fbd2230f372..4edfe28395f0 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -36,18 +36,23 @@  	DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics) -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u"); - -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_non_ctrl, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_ctrl, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_during_protection, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, null_frame_tx_start, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, null_frame_cts_start, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, bar_retry, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, num_frame_cts_nul_flid, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tx_abort_failure, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tx_resume_failure, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, rx_cmplt_db_overflow_cnt, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_rx_exch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_tx_exch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_tx, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, elp_while_nvic_pending, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, rx_excessive_frame_len, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, burst_mismatch, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(error, tbc_exch_mismatch, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u"); @@ -57,7 +62,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_stop, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u"); @@ -66,13 +71,15 @@ WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(tx, tx_retry_per_rate, +				  NUM_OF_RATES_INDEXES);  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cfe1, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cfe2, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u"); @@ -97,11 +104,8 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_rts_timeout, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u"); @@ -111,6 +115,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_xfr, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); @@ -120,14 +125,13 @@ WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread,  				  PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD);  WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u"); - - -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_time_count, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_time_avg, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_cycle_avg, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, sleep_percent, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_active_conf, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_user_conf, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pwr, ap_sleep_counter, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u"); @@ -141,14 +145,14 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(rx_rate, rx_frames_per_rates, 50); -WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate, -				  AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_rate, +				  AGGR_STATS_TX_AGG); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_len, +				  AGGR_STATS_TX_AGG);  WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size,  				  AGGR_STATS_RX_SIZE_LEN);  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u"); @@ -156,21 +160,32 @@ WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_rx_xfer_swi, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u");  WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full,  				  PIPE_STATS_HW_FIFO); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(diversity, num_of_packets_per_ant, +				  DIVERSITY_STATS_NUM_OF_ANT); +WL18XX_DEBUGFS_FWSTATS_FILE(diversity, total_num_of_toggles, "%u"); + +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_low, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, irq_thr_high, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, tx_stop, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, tx_resume, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, false_irq, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE(thermal, adc_source_unexpected, "%u"); + +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(calib, fail_count, +				  WL18XX_NUM_OF_CALIBRATIONS_ERRORS); +WL18XX_DEBUGFS_FWSTATS_FILE(calib, calib_count, "%u"); + +WL18XX_DEBUGFS_FWSTATS_FILE(roaming, rssi_level, "%d"); + +WL18XX_DEBUGFS_FWSTATS_FILE(dfs, num_of_radar_detections, "%d");  static ssize_t conf_read(struct file *file, char __user *user_buf,  			 size_t count, loff_t *ppos) @@ -281,6 +296,55 @@ static const struct file_operations radar_detection_ops = {  	.llseek = default_llseek,  }; +static ssize_t dynamic_fw_traces_write(struct file *file, +					const char __user *user_buf, +					size_t count, loff_t *ppos) +{ +	struct wl1271 *wl = file->private_data; +	unsigned long value; +	int ret; + +	ret = kstrtoul_from_user(user_buf, count, 0, &value); +	if (ret < 0) +		return ret; + +	mutex_lock(&wl->mutex); + +	wl->dynamic_fw_traces = value; + +	if (unlikely(wl->state != WLCORE_STATE_ON)) +		goto out; + +	ret = wl1271_ps_elp_wakeup(wl); +	if (ret < 0) +		goto out; + +	ret = wl18xx_acx_dynamic_fw_traces(wl); +	if (ret < 0) +		count = ret; + +	wl1271_ps_elp_sleep(wl); +out: +	mutex_unlock(&wl->mutex); +	return count; +} + +static ssize_t dynamic_fw_traces_read(struct file *file, +					char __user *userbuf, +					size_t count, loff_t *ppos) +{ +	struct wl1271 *wl = file->private_data; +	return wl1271_format_buffer(userbuf, count, ppos, +				    "%d\n", wl->dynamic_fw_traces); +} + +static const struct file_operations dynamic_fw_traces_ops = { +	.read = dynamic_fw_traces_read, +	.write = dynamic_fw_traces_write, +	.open = simple_open, +	.llseek = default_llseek, +}; +  int wl18xx_debugfs_add_files(struct wl1271 *wl,  			     struct dentry *rootdir)  { @@ -301,18 +365,23 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_ADD(clear_fw_stats, stats); -	DEBUGFS_FWSTATS_ADD(debug, debug1); -	DEBUGFS_FWSTATS_ADD(debug, debug2); -	DEBUGFS_FWSTATS_ADD(debug, debug3); -	DEBUGFS_FWSTATS_ADD(debug, debug4); -	DEBUGFS_FWSTATS_ADD(debug, debug5); -	DEBUGFS_FWSTATS_ADD(debug, debug6); - -	DEBUGFS_FWSTATS_ADD(error, error_frame); -	DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start); -	DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start); -	DEBUGFS_FWSTATS_ADD(error, error_bar_retry); -	DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid); +	DEBUGFS_FWSTATS_ADD(error, error_frame_non_ctrl); +	DEBUGFS_FWSTATS_ADD(error, error_frame_ctrl); +	DEBUGFS_FWSTATS_ADD(error, error_frame_during_protection); +	DEBUGFS_FWSTATS_ADD(error, null_frame_tx_start); +	DEBUGFS_FWSTATS_ADD(error, null_frame_cts_start); +	DEBUGFS_FWSTATS_ADD(error, bar_retry); +	DEBUGFS_FWSTATS_ADD(error, num_frame_cts_nul_flid); +	DEBUGFS_FWSTATS_ADD(error, tx_abort_failure); +	DEBUGFS_FWSTATS_ADD(error, tx_resume_failure); +	DEBUGFS_FWSTATS_ADD(error, rx_cmplt_db_overflow_cnt); +	DEBUGFS_FWSTATS_ADD(error, elp_while_rx_exch); +	DEBUGFS_FWSTATS_ADD(error, elp_while_tx_exch); +	DEBUGFS_FWSTATS_ADD(error, elp_while_tx); +	DEBUGFS_FWSTATS_ADD(error, elp_while_nvic_pending); +	DEBUGFS_FWSTATS_ADD(error, rx_excessive_frame_len); +	DEBUGFS_FWSTATS_ADD(error, burst_mismatch); +	DEBUGFS_FWSTATS_ADD(error, tbc_exch_mismatch);  	DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs);  	DEBUGFS_FWSTATS_ADD(tx, tx_cmplt); @@ -322,7 +391,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed);  	DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed);  	DEBUGFS_FWSTATS_ADD(tx, tx_starts); -	DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp); +	DEBUGFS_FWSTATS_ADD(tx, tx_stop);  	DEBUGFS_FWSTATS_ADD(tx, tx_start_templates);  	DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates);  	DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen); @@ -331,13 +400,14 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(tx, tx_exch);  	DEBUGFS_FWSTATS_ADD(tx, tx_retry_template);  	DEBUGFS_FWSTATS_ADD(tx, tx_retry_data); +	DEBUGFS_FWSTATS_ADD(tx, tx_retry_per_rate);  	DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending);  	DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry);  	DEBUGFS_FWSTATS_ADD(tx, tx_done_template);  	DEBUGFS_FWSTATS_ADD(tx, tx_done_data);  	DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template); -	DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum); -	DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result); +	DEBUGFS_FWSTATS_ADD(tx, tx_cfe1); +	DEBUGFS_FWSTATS_ADD(tx, tx_cfe2);  	DEBUGFS_FWSTATS_ADD(tx, frag_called);  	DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed);  	DEBUGFS_FWSTATS_ADD(tx, frag_init_called); @@ -362,11 +432,8 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task);  	DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr);  	DEBUGFS_FWSTATS_ADD(rx, rx_timeout); +	DEBUGFS_FWSTATS_ADD(rx, rx_rts_timeout);  	DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa); -	DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame); -	DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected); -	DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum); -	DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result);  	DEBUGFS_FWSTATS_ADD(rx, defrag_called);  	DEBUGFS_FWSTATS_ADD(rx, defrag_init_called);  	DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called); @@ -376,6 +443,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found);  	DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt);  	DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays); +	DEBUGFS_FWSTATS_ADD(rx, rx_xfr);  	DEBUGFS_FWSTATS_ADD(isr, irqs); @@ -384,13 +452,13 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync);  	DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread);  	DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt); - -	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts); -	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts); -	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn); -	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn); -	DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization); -	DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization); +	DEBUGFS_FWSTATS_ADD(pwr, sleep_time_count); +	DEBUGFS_FWSTATS_ADD(pwr, sleep_time_avg); +	DEBUGFS_FWSTATS_ADD(pwr, sleep_cycle_avg); +	DEBUGFS_FWSTATS_ADD(pwr, sleep_percent); +	DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_active_conf); +	DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_user_conf); +	DEBUGFS_FWSTATS_ADD(pwr, ap_sleep_counter);  	DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter);  	DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter); @@ -404,12 +472,11 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates); -	DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate); +	DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_rate); +	DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_len);  	DEBUGFS_FWSTATS_ADD(aggr_size, rx_size);  	DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int); -	DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int); -	DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int);  	DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int);  	DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int);  	DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int); @@ -417,22 +484,33 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,  	DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi);  	DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi);  	DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi); -	DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi); -	DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi); +	DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_rx_xfer_swi);  	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in);  	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full);  	DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out); -	DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in); -	DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out);  	DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full); -	DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks); -	DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks); -	DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks); -	DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks); +	DEBUGFS_FWSTATS_ADD(diversity, num_of_packets_per_ant); +	DEBUGFS_FWSTATS_ADD(diversity, total_num_of_toggles); + +	DEBUGFS_FWSTATS_ADD(thermal, irq_thr_low); +	DEBUGFS_FWSTATS_ADD(thermal, irq_thr_high); +	DEBUGFS_FWSTATS_ADD(thermal, tx_stop); +	DEBUGFS_FWSTATS_ADD(thermal, tx_resume); +	DEBUGFS_FWSTATS_ADD(thermal, false_irq); +	DEBUGFS_FWSTATS_ADD(thermal, adc_source_unexpected); + +	DEBUGFS_FWSTATS_ADD(calib, fail_count); + +	DEBUGFS_FWSTATS_ADD(calib, calib_count); + +	DEBUGFS_FWSTATS_ADD(roaming, rssi_level); + +	DEBUGFS_FWSTATS_ADD(dfs, num_of_radar_detections);  	DEBUGFS_ADD(conf, moddir);  	DEBUGFS_ADD(radar_detection, moddir); +	DEBUGFS_ADD(dynamic_fw_traces, moddir);  	return 0; diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index 548bb9e7e91e..09c7e098f460 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -112,6 +112,14 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl,  	return 0;  } +static void wlcore_event_time_sync(struct wl1271 *wl, u16 tsf_msb, u16 tsf_lsb) +{ +	u32 clock; +	/* convert the MSB+LSB to a u32 TSF value */ +	clock = (tsf_msb << 16) | tsf_lsb; +	wl1271_info("TIME_SYNC_EVENT_ID: clock %u", clock); +} +  int wl18xx_process_mailbox_events(struct wl1271 *wl)  {  	struct wl18xx_event_mailbox *mbox = wl->mbox; @@ -128,6 +136,11 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)  			wl18xx_scan_completed(wl, wl->scan_wlvif);  	} +	if (vector & TIME_SYNC_EVENT_ID) +		wlcore_event_time_sync(wl, +				mbox->time_sync_tsf_msb, +				mbox->time_sync_tsf_lsb); +  	if (vector & RADAR_DETECTED_EVENT_ID) {  		wl1271_info("radar event: channel %d type %s",  			    mbox->radar_channel, diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 266ee87834e4..f3d4f13379cb 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -38,8 +38,9 @@ enum {  	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID      = BIT(18),  	DFS_CHANNELS_CONFIG_COMPLETE_EVENT       = BIT(19),  	PERIODIC_SCAN_REPORT_EVENT_ID            = BIT(20), -	SMART_CONFIG_SYNC_EVENT_ID		 = BIT(22), -	SMART_CONFIG_DECODE_EVENT_ID		 = BIT(23), +	SMART_CONFIG_SYNC_EVENT_ID               = BIT(22), +	SMART_CONFIG_DECODE_EVENT_ID             = BIT(23), +	TIME_SYNC_EVENT_ID                       = BIT(24),  };  enum wl18xx_radar_types { @@ -95,13 +96,16 @@ struct wl18xx_event_mailbox {  	/* smart config sync channel */  	u8 sc_sync_channel;  	u8 sc_sync_band; -	u8 padding2[2]; +	/* time sync msb*/ +	u16 time_sync_tsf_msb;  	/* radar detect */  	u8 radar_channel;  	u8 radar_type; -	u8 padding3[2]; +	/* time sync lsb*/ +	u16 time_sync_tsf_lsb; +  } __packed;  int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 49aca2cf7605..abbf054fb6da 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -422,6 +422,8 @@ static struct wlcore_conf wl18xx_conf = {  		.num_probe_reqs			= 2,  		.rssi_threshold			= -90,  		.snr_threshold			= 0, +		.num_short_intervals		= SCAN_MAX_SHORT_INTERVALS, +		.long_interval			= 30000,  	},  	.ht = {  		.rx_ba_win_size = 32, @@ -1026,8 +1028,8 @@ static int wl18xx_boot(struct wl1271 *wl)  		CHANNEL_SWITCH_COMPLETE_EVENT_ID |  		DFS_CHANNELS_CONFIG_COMPLETE_EVENT |  		SMART_CONFIG_SYNC_EVENT_ID | -		SMART_CONFIG_DECODE_EVENT_ID; -; +		SMART_CONFIG_DECODE_EVENT_ID | +		TIME_SYNC_EVENT_ID;  	wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; @@ -1159,6 +1161,11 @@ static int wl18xx_hw_init(struct wl1271 *wl)  	if (ret < 0)  		return ret; +	/* set the dynamic fw traces bitmap */ +	ret = wl18xx_acx_dynamic_fw_traces(wl); +	if (ret < 0) +		return ret; +  	if (checksum_param) {  		ret = wl18xx_acx_set_checksum_state(wl);  		if (ret != 0) @@ -1797,7 +1804,7 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {  static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {  	{ -		.max = 3, +		.max = 2,  		.types = BIT(NL80211_IFTYPE_STATION),  	},  	{ @@ -1806,6 +1813,10 @@ static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {  			 BIT(NL80211_IFTYPE_P2P_GO) |  			 BIT(NL80211_IFTYPE_P2P_CLIENT),  	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_DEVICE), +	},  };  static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { @@ -1813,6 +1824,48 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {  		.max = 2,  		.types = BIT(NL80211_IFTYPE_AP),  	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_DEVICE), +	}, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_cl_limits[] = { +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_STATION), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_AP), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_CLIENT), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_DEVICE), +	}, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_go_limits[] = { +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_STATION), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_AP), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_GO), +	}, +	{ +		.max = 1, +		.types = BIT(NL80211_IFTYPE_P2P_DEVICE), +	},  };  static const struct ieee80211_iface_combination diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 98666f235a12..c938c494c785 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -51,7 +51,11 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		goto out;  	} -	cmd->role_id = wlvif->role_id; +	/* scan on the dev role if the regular one is not started */ +	if (wlcore_is_p2p_mgmt(wlvif)) +		cmd->role_id = wlvif->dev_role_id; +	else +		cmd->role_id = wlvif->role_id;  	if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {  		ret = -EINVAL; @@ -223,9 +227,20 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,  				    SCAN_TYPE_PERIODIC);  	wl18xx_adjust_channels(cmd, cmd_channels); -	cmd->short_cycles_sec = 0; -	cmd->long_cycles_sec = cpu_to_le16(req->interval); -	cmd->short_cycles_count = 0; +	if (c->num_short_intervals && c->long_interval && +	    c->long_interval > req->interval) { +		cmd->short_cycles_msec = cpu_to_le16(req->interval); +		cmd->long_cycles_msec = cpu_to_le16(c->long_interval); +		cmd->short_cycles_count = c->num_short_intervals; +	} else { +		cmd->short_cycles_msec = 0; +		cmd->long_cycles_msec = cpu_to_le16(req->interval); +		cmd->short_cycles_count = 0; +	} +	wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", +		     le16_to_cpu(cmd->short_cycles_msec), +		     le16_to_cpu(cmd->long_cycles_msec), +		     cmd->short_cycles_count);  	cmd->total_cycles = 0; diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h index 2e636aa5dba9..66a763f644d2 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.h +++ b/drivers/net/wireless/ti/wl18xx/scan.h @@ -74,8 +74,8 @@ struct wl18xx_cmd_scan_params {  	u8 dfs;		   /* number of dfs channels in 5ghz */  	u8 passive_active; /* number of passive before active channels 2.4ghz */ -	__le16 short_cycles_sec; -	__le16 long_cycles_sec; +	__le16 short_cycles_msec; +	__le16 long_cycles_msec;  	u8 short_cycles_count;  	u8 total_cycles; /* 0 - infinite */  	u8 padding[2]; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 68919f8d4310..f01d24baff7c 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -2003,12 +2003,15 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		      wlvif->bss_type == BSS_TYPE_IBSS)))  		return -EINVAL; -	ret = wl12xx_cmd_role_enable(wl, -				     wl12xx_wlvif_to_vif(wlvif)->addr, -				     WL1271_ROLE_DEVICE, -				     &wlvif->dev_role_id); -	if (ret < 0) -		goto out; +	/* the dev role is already started for p2p mgmt interfaces */ +	if (!wlcore_is_p2p_mgmt(wlvif)) { +		ret = wl12xx_cmd_role_enable(wl, +					     wl12xx_wlvif_to_vif(wlvif)->addr, +					     WL1271_ROLE_DEVICE, +					     &wlvif->dev_role_id); +		if (ret < 0) +			goto out; +	}  	ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel);  	if (ret < 0) @@ -2023,7 +2026,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,  out_stop:  	wl12xx_cmd_role_stop_dev(wl, wlvif);  out_disable: -	wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); +	if (!wlcore_is_p2p_mgmt(wlvif)) +		wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);  out:  	return ret;  } @@ -2052,10 +2056,42 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)  	if (ret < 0)  		goto out; -	ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); -	if (ret < 0) -		goto out; +	if (!wlcore_is_p2p_mgmt(wlvif)) { +		ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); +		if (ret < 0) +			goto out; +	}  out:  	return ret;  } + +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			   u8 feature, u8 enable, u8 value) +{ +	struct wlcore_cmd_generic_cfg *cmd; +	int ret; + +	wl1271_debug(DEBUG_CMD, +		     "cmd generic cfg (role %d feature %d enable %d value %d)", +		     wlvif->role_id, feature, enable, value); + +	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); +	if (!cmd) +		return -ENOMEM; + +	cmd->role_id = wlvif->role_id; +	cmd->feature = feature; +	cmd->enable = enable; +	cmd->value = value; + +	ret = wl1271_cmd_send(wl, CMD_GENERIC_CFG, cmd, sizeof(*cmd), 0); +	if (ret < 0) { +		wl1271_error("failed to send generic cfg command"); +		goto out_free; +	} +out_free: +	kfree(cmd); +	return ret; +} +EXPORT_SYMBOL_GPL(wlcore_cmd_generic_cfg); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index e14cd407a6ae..8dc46c0a489a 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -92,6 +92,8 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,  void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,  				     enum ieee80211_band band);  int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			   u8 feature, u8 enable, u8 value);  int wl12xx_cmd_config_fwlog(struct wl1271 *wl);  int wl12xx_cmd_start_fwlog(struct wl1271 *wl);  int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); @@ -652,6 +654,19 @@ struct wl12xx_cmd_regdomain_dfs_config {  	u8 padding[3];  } __packed; +enum wlcore_generic_cfg_feature { +	WLCORE_CFG_FEATURE_RADAR_DEBUG = 2, +}; + +struct wlcore_cmd_generic_cfg { +	struct wl1271_cmd_header header; + +	u8 role_id; +	u8 feature; +	u8 enable; +	u8 value; +} __packed; +  struct wl12xx_cmd_config_fwlog {  	struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 166add00b50f..52a9d1b14020 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -1186,6 +1186,15 @@ struct conf_sched_scan_settings {  	/* SNR threshold to be used for filtering */  	s8 snr_threshold; + +	/* +	 * number of short intervals scheduled scan cycles before +	 * switching to long intervals +	 */ +	u8 num_short_intervals; + +	/* interval between each long scheduled scan cycle (in ms) */ +	u16 long_interval;  } __packed;  struct conf_ht_setting { @@ -1352,7 +1361,7 @@ struct conf_recovery_settings {   * version, the two LSB are the lower driver's private conf   * version.   */ -#define WLCORE_CONF_VERSION	(0x0006 << 16) +#define WLCORE_CONF_VERSION	(0x0007 << 16)  #define WLCORE_CONF_MASK	0xffff0000  #define WLCORE_CONF_SIZE	(sizeof(struct wlcore_conf_header) +	\  				 sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 5ca1fb161a50..e92f2639af2c 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -348,7 +348,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)  }  /* generic sta initialization (non vif-specific) */ -static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)  {  	int ret; diff --git a/drivers/net/wireless/ti/wlcore/init.h b/drivers/net/wireless/ti/wlcore/init.h index a45fbfddec19..fd1cdb6bc3e4 100644 --- a/drivers/net/wireless/ti/wlcore/init.h +++ b/drivers/net/wireless/ti/wlcore/init.h @@ -35,5 +35,6 @@ int wl1271_hw_init(struct wl1271 *wl);  int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif);  int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif);  int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif);  #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 337223b9f6f8..e819369d8f8f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1792,6 +1792,9 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,  	wl->wow_enabled = true;  	wl12xx_for_each_wlvif(wl, wlvif) { +		if (wlcore_is_p2p_mgmt(wlvif)) +			continue; +  		ret = wl1271_configure_suspend(wl, wlvif, wow);  		if (ret < 0) {  			mutex_unlock(&wl->mutex); @@ -1901,6 +1904,9 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)  		goto out;  	wl12xx_for_each_wlvif(wl, wlvif) { +		if (wlcore_is_p2p_mgmt(wlvif)) +			continue; +  		wl1271_configure_resume(wl, wlvif);  	} @@ -2256,6 +2262,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)  		wlvif->p2p = 1;  		/* fall-through */  	case NL80211_IFTYPE_STATION: +	case NL80211_IFTYPE_P2P_DEVICE:  		wlvif->bss_type = BSS_TYPE_STA_BSS;  		break;  	case NL80211_IFTYPE_ADHOC: @@ -2477,7 +2484,8 @@ static void wlcore_hw_queue_iter(void *data, u8 *mac,  {  	struct wlcore_hw_queue_iter_data *iter_data = data; -	if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) +	if (vif->type == NL80211_IFTYPE_P2P_DEVICE || +	    WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))  		return;  	if (iter_data->cur_running || vif == iter_data->vif) { @@ -2495,6 +2503,11 @@ static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,  	struct wlcore_hw_queue_iter_data iter_data = {};  	int i, q_base; +	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { +		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; +		return 0; +	} +  	iter_data.vif = vif;  	/* mark all bits taken by active interfaces */ @@ -2618,14 +2631,27 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  			goto out;  	} -	ret = wl12xx_cmd_role_enable(wl, vif->addr, -				     role_type, &wlvif->role_id); -	if (ret < 0) -		goto out; +	if (!wlcore_is_p2p_mgmt(wlvif)) { +		ret = wl12xx_cmd_role_enable(wl, vif->addr, +					     role_type, &wlvif->role_id); +		if (ret < 0) +			goto out; -	ret = wl1271_init_vif_specific(wl, vif); -	if (ret < 0) -		goto out; +		ret = wl1271_init_vif_specific(wl, vif); +		if (ret < 0) +			goto out; + +	} else { +		ret = wl12xx_cmd_role_enable(wl, vif->addr, WL1271_ROLE_DEVICE, +					     &wlvif->dev_role_id); +		if (ret < 0) +			goto out; + +		/* needed mainly for configuring rate policies */ +		ret = wl1271_sta_hw_init(wl, wlvif); +		if (ret < 0) +			goto out; +	}  	list_add(&wlvif->list, &wl->wlvif_list);  	set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); @@ -2696,9 +2722,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,  				wl12xx_stop_dev(wl, wlvif);  		} -		ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); -		if (ret < 0) -			goto deinit; +		if (!wlcore_is_p2p_mgmt(wlvif)) { +			ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); +			if (ret < 0) +				goto deinit; +		} else { +			ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); +			if (ret < 0) +				goto deinit; +		}  		wl1271_ps_elp_sleep(wl);  	} @@ -3088,6 +3120,9 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,  {  	int ret; +	if (wlcore_is_p2p_mgmt(wlvif)) +		return 0; +  	if (conf->power_level != wlvif->power_level) {  		ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);  		if (ret < 0) @@ -3207,6 +3242,9 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,  		goto out;  	wl12xx_for_each_wlvif(wl, wlvif) { +		if (wlcore_is_p2p_mgmt(wlvif)) +			continue; +  		if (wlvif->bss_type != BSS_TYPE_AP_BSS) {  			if (*total & FIF_ALLMULTI)  				ret = wl1271_acx_group_address_tbl(wl, wlvif, @@ -4837,6 +4875,9 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw,  	u8 ps_scheme;  	int ret = 0; +	if (wlcore_is_p2p_mgmt(wlvif)) +		return 0; +  	mutex_lock(&wl->mutex);  	wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); @@ -6078,8 +6119,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);  	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | -		BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); +					 BIT(NL80211_IFTYPE_AP) | +					 BIT(NL80211_IFTYPE_P2P_DEVICE) | +					 BIT(NL80211_IFTYPE_P2P_CLIENT) | +					 BIT(NL80211_IFTYPE_P2P_GO);  	wl->hw->wiphy->max_scan_ssids = 1;  	wl->hw->wiphy->max_sched_scan_ssids = 16;  	wl->hw->wiphy->max_match_sets = 16; diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index e125974285cc..5b2927391d1c 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,7 +74,14 @@ static void wl1271_rx_status(struct wl1271 *wl,  	if (desc->rate <= wl->hw_min_ht_rate)  		status->flag |= RX_FLAG_HT; -	status->signal = desc->rssi; +	/* +	* Read the signal level and antenna diversity indication. +	* The msb in the signal level is always set as it is a +	* negative number. +	* The antenna indication is the msb of the rssi. +	*/ +	status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); +	status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7);  	/*  	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index a3b1618db27c..f5a7087cfb97 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -30,6 +30,9 @@  #define WL1271_RX_MAX_RSSI -30  #define WL1271_RX_MIN_RSSI -95 +#define RSSI_LEVEL_BITMASK	0x7F +#define ANT_DIVERSITY_BITMASK	BIT(7) +  #define SHORT_PREAMBLE_BIT   BIT(0)  #define OFDM_RATE_BIT        BIT(6)  #define PBCC_RATE_BIT        BIT(7) diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index 4dadd0c62cde..782eb297c196 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h @@ -83,6 +83,12 @@ struct wl1271_cmd_trigger_scan_to {  #define MAX_CHANNELS_5GHZ	42  #define SCAN_MAX_CYCLE_INTERVALS 16 + +/* The FW intervals can take up to 16 entries. + * The 1st entry isn't used (scan is immediate). The last + * entry should be used for the long_interval + */ +#define SCAN_MAX_SHORT_INTERVALS (SCAN_MAX_CYCLE_INTERVALS - 2)  #define SCAN_MAX_BANDS 3  enum { diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index ea7e07abca4e..c172da56b550 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -293,7 +293,8 @@ static int wl1271_probe(struct sdio_func *func,  	/* Use block mode for transferring over one block size of data */  	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; -	if (wlcore_probe_of(&func->dev, &irq, &pdev_data)) +	ret = wlcore_probe_of(&func->dev, &irq, &pdev_data); +	if (ret)  		goto out_free_glue;  	/* if sdio can keep power while host is suspended, enable wow */ diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 7f363fa566a3..a1b6040e6491 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -500,6 +500,9 @@ struct wl1271 {  	/* interface combinations supported by the hw */  	const struct ieee80211_iface_combination *iface_combinations;  	u8 n_iface_combinations; + +	/* dynamic fw traces */ +	u32 dynamic_fw_traces;  };  int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 39efc6d78b10..27c56876b2c1 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -503,6 +503,11 @@ struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)  	return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);  } +static inline bool wlcore_is_p2p_mgmt(struct wl12xx_vif *wlvif) +{ +	return wl12xx_wlvif_to_vif(wlvif)->type == NL80211_IFTYPE_P2P_DEVICE; +} +  #define wl12xx_for_each_wlvif(wl, wlvif) \  		list_for_each_entry(wlvif, &wl->wlvif_list, list)  |