Merge branch 'for-linville' of git://github.com/kvalo/ath
This commit is contained in:
		
						commit
						a72e25f781
					
				| @ -283,7 +283,7 @@ static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, | ||||
| 
 | ||||
| 	if (unlikely(CE_RING_DELTA(nentries_mask, | ||||
| 				   write_index, sw_index - 1) <= 0)) { | ||||
| 		ret = -EIO; | ||||
| 		ret = -ENOSR; | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| @ -338,38 +338,19 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, | ||||
| 			    void *per_transfer_context, | ||||
| 			    unsigned int transfer_id, | ||||
| 			    u32 paddr, unsigned int nbytes, | ||||
| 			    u32 flags) | ||||
| int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) | ||||
| { | ||||
| 	struct ath10k_ce_ring *src_ring = ce_state->src_ring; | ||||
| 	struct ath10k *ar = ce_state->ar; | ||||
| 	struct ath10k *ar = pipe->ar; | ||||
| 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||||
| 	unsigned int nentries_mask = src_ring->nentries_mask; | ||||
| 	unsigned int sw_index; | ||||
| 	unsigned int write_index; | ||||
| 	int delta, ret = -ENOMEM; | ||||
| 	int delta; | ||||
| 
 | ||||
| 	spin_lock_bh(&ar_pci->ce_lock); | ||||
| 
 | ||||
| 	sw_index = src_ring->sw_index; | ||||
| 	write_index = src_ring->write_index; | ||||
| 
 | ||||
| 	delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); | ||||
| 
 | ||||
| 	if (delta >= 1) { | ||||
| 		ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, | ||||
| 					    paddr, nbytes, | ||||
| 					    transfer_id, flags); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("CE send failed: %d\n", ret); | ||||
| 	} | ||||
| 
 | ||||
| 	delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, | ||||
| 			      pipe->src_ring->write_index, | ||||
| 			      pipe->src_ring->sw_index - 1); | ||||
| 	spin_unlock_bh(&ar_pci->ce_lock); | ||||
| 
 | ||||
| 	return ret; | ||||
| 	return delta; | ||||
| } | ||||
| 
 | ||||
| int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, | ||||
|  | ||||
| @ -156,21 +156,7 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, | ||||
| 				void (*send_cb)(struct ath10k_ce_pipe *), | ||||
| 				int disable_interrupts); | ||||
| 
 | ||||
| /*
 | ||||
|  * Queue a "sendlist" of buffers to be sent using gather to a single | ||||
|  * anonymous destination buffer | ||||
|  *   ce         - which copy engine to use | ||||
|  *   sendlist        - list of simple buffers to send using gather | ||||
|  *   transfer_id     - arbitrary ID; reflected to destination | ||||
|  * Returns 0 on success; otherwise an error status. | ||||
|  * | ||||
|  * Implemenation note: Pushes multiple buffers with Gather to Source ring. | ||||
|  */ | ||||
| int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, | ||||
| 			    void *per_transfer_context, | ||||
| 			    unsigned int transfer_id, | ||||
| 			    u32 paddr, unsigned int nbytes, | ||||
| 			    u32 flags); | ||||
| int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); | ||||
| 
 | ||||
| /*==================Recv=======================*/ | ||||
| 
 | ||||
|  | ||||
| @ -59,27 +59,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) | ||||
| 	wake_up(&ar->event_queue); | ||||
| } | ||||
| 
 | ||||
| static int ath10k_check_fw_version(struct ath10k *ar) | ||||
| { | ||||
| 	char version[32]; | ||||
| 
 | ||||
| 	if (ar->fw_version_major >= SUPPORTED_FW_MAJOR && | ||||
| 	    ar->fw_version_minor >= SUPPORTED_FW_MINOR && | ||||
| 	    ar->fw_version_release >= SUPPORTED_FW_RELEASE && | ||||
| 	    ar->fw_version_build >= SUPPORTED_FW_BUILD) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	snprintf(version, sizeof(version), "%u.%u.%u.%u", | ||||
| 		 SUPPORTED_FW_MAJOR, SUPPORTED_FW_MINOR, | ||||
| 		 SUPPORTED_FW_RELEASE, SUPPORTED_FW_BUILD); | ||||
| 
 | ||||
| 	ath10k_warn("WARNING: Firmware version %s is not officially supported.\n", | ||||
| 		    ar->hw->wiphy->fw_version); | ||||
| 	ath10k_warn("Please upgrade to version %s (or newer)\n", version); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_init_connect_htc(struct ath10k *ar) | ||||
| { | ||||
| 	int status; | ||||
| @ -189,8 +168,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, | ||||
| 	return fw; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_push_board_ext_data(struct ath10k *ar, | ||||
| 				      const struct firmware *fw) | ||||
| static int ath10k_push_board_ext_data(struct ath10k *ar) | ||||
| { | ||||
| 	u32 board_data_size = QCA988X_BOARD_DATA_SZ; | ||||
| 	u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; | ||||
| @ -210,14 +188,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, | ||||
| 	if (board_ext_data_addr == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (fw->size != (board_data_size + board_ext_data_size)) { | ||||
| 	if (ar->board_len != (board_data_size + board_ext_data_size)) { | ||||
| 		ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n", | ||||
| 			   fw->size, board_data_size, board_ext_data_size); | ||||
| 			   ar->board_len, board_data_size, board_ext_data_size); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, | ||||
| 				      fw->data + board_data_size, | ||||
| 				      ar->board_data + board_data_size, | ||||
| 				      board_ext_data_size); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not write board ext data (%d)\n", ret); | ||||
| @ -236,12 +214,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, | ||||
| 
 | ||||
| static int ath10k_download_board_data(struct ath10k *ar) | ||||
| { | ||||
| 	const struct firmware *fw = ar->board_data; | ||||
| 	u32 board_data_size = QCA988X_BOARD_DATA_SZ; | ||||
| 	u32 address; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath10k_push_board_ext_data(ar, fw); | ||||
| 	ret = ath10k_push_board_ext_data(ar); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not push board ext data (%d)\n", ret); | ||||
| 		goto exit; | ||||
| @ -253,8 +230,9 @@ static int ath10k_download_board_data(struct ath10k *ar) | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_bmi_write_memory(ar, address, fw->data, | ||||
| 				      min_t(u32, board_data_size, fw->size)); | ||||
| 	ret = ath10k_bmi_write_memory(ar, address, ar->board_data, | ||||
| 				      min_t(u32, board_data_size, | ||||
| 					    ar->board_len)); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not write board data (%d)\n", ret); | ||||
| 		goto exit; | ||||
| @ -272,17 +250,16 @@ exit: | ||||
| 
 | ||||
| static int ath10k_download_and_run_otp(struct ath10k *ar) | ||||
| { | ||||
| 	const struct firmware *fw = ar->otp; | ||||
| 	u32 address = ar->hw_params.patch_load_addr; | ||||
| 	u32 exec_param; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* OTP is optional */ | ||||
| 
 | ||||
| 	if (!ar->otp) | ||||
| 	if (!ar->otp_data || !ar->otp_len) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); | ||||
| 	ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not write otp (%d)\n", ret); | ||||
| 		goto exit; | ||||
| @ -301,13 +278,13 @@ exit: | ||||
| 
 | ||||
| static int ath10k_download_fw(struct ath10k *ar) | ||||
| { | ||||
| 	const struct firmware *fw = ar->firmware; | ||||
| 	u32 address; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	address = ar->hw_params.patch_load_addr; | ||||
| 
 | ||||
| 	ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); | ||||
| 	ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, | ||||
| 				       ar->firmware_len); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not write fw (%d)\n", ret); | ||||
| 		goto exit; | ||||
| @ -319,8 +296,8 @@ exit: | ||||
| 
 | ||||
| static void ath10k_core_free_firmware_files(struct ath10k *ar) | ||||
| { | ||||
| 	if (ar->board_data && !IS_ERR(ar->board_data)) | ||||
| 		release_firmware(ar->board_data); | ||||
| 	if (ar->board && !IS_ERR(ar->board)) | ||||
| 		release_firmware(ar->board); | ||||
| 
 | ||||
| 	if (ar->otp && !IS_ERR(ar->otp)) | ||||
| 		release_firmware(ar->otp); | ||||
| @ -328,12 +305,20 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) | ||||
| 	if (ar->firmware && !IS_ERR(ar->firmware)) | ||||
| 		release_firmware(ar->firmware); | ||||
| 
 | ||||
| 	ar->board = NULL; | ||||
| 	ar->board_data = NULL; | ||||
| 	ar->board_len = 0; | ||||
| 
 | ||||
| 	ar->otp = NULL; | ||||
| 	ar->otp_data = NULL; | ||||
| 	ar->otp_len = 0; | ||||
| 
 | ||||
| 	ar->firmware = NULL; | ||||
| 	ar->firmware_data = NULL; | ||||
| 	ar->firmware_len = 0; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | ||||
| static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| @ -347,15 +332,18 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->board_data = ath10k_fetch_fw_file(ar, | ||||
| 					      ar->hw_params.fw.dir, | ||||
| 					      ar->hw_params.fw.board); | ||||
| 	if (IS_ERR(ar->board_data)) { | ||||
| 		ret = PTR_ERR(ar->board_data); | ||||
| 	ar->board = ath10k_fetch_fw_file(ar, | ||||
| 					 ar->hw_params.fw.dir, | ||||
| 					 ar->hw_params.fw.board); | ||||
| 	if (IS_ERR(ar->board)) { | ||||
| 		ret = PTR_ERR(ar->board); | ||||
| 		ath10k_err("could not fetch board data (%d)\n", ret); | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->board_data = ar->board->data; | ||||
| 	ar->board_len = ar->board->size; | ||||
| 
 | ||||
| 	ar->firmware = ath10k_fetch_fw_file(ar, | ||||
| 					    ar->hw_params.fw.dir, | ||||
| 					    ar->hw_params.fw.fw); | ||||
| @ -365,6 +353,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->firmware_data = ar->firmware->data; | ||||
| 	ar->firmware_len = ar->firmware->size; | ||||
| 
 | ||||
| 	/* OTP may be undefined. If so, don't fetch it at all */ | ||||
| 	if (ar->hw_params.fw.otp == NULL) | ||||
| 		return 0; | ||||
| @ -378,6 +369,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->otp_data = ar->otp->data; | ||||
| 	ar->otp_len = ar->otp->size; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| @ -385,6 +379,191 @@ err: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) | ||||
| { | ||||
| 	size_t magic_len, len, ie_len; | ||||
| 	int ie_id, i, index, bit, ret; | ||||
| 	struct ath10k_fw_ie *hdr; | ||||
| 	const u8 *data; | ||||
| 	__le32 *timestamp; | ||||
| 
 | ||||
| 	/* first fetch the firmware file (firmware-*.bin) */ | ||||
| 	ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); | ||||
| 	if (IS_ERR(ar->firmware)) { | ||||
| 		ath10k_err("Could not fetch firmware file '%s': %ld\n", | ||||
| 			   name, PTR_ERR(ar->firmware)); | ||||
| 		return PTR_ERR(ar->firmware); | ||||
| 	} | ||||
| 
 | ||||
| 	data = ar->firmware->data; | ||||
| 	len = ar->firmware->size; | ||||
| 
 | ||||
| 	/* magic also includes the null byte, check that as well */ | ||||
| 	magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; | ||||
| 
 | ||||
| 	if (len < magic_len) { | ||||
| 		ath10k_err("firmware image too small to contain magic: %zu\n", | ||||
| 			   len); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { | ||||
| 		ath10k_err("Invalid firmware magic\n"); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* jump over the padding */ | ||||
| 	magic_len = ALIGN(magic_len, 4); | ||||
| 
 | ||||
| 	len -= magic_len; | ||||
| 	data += magic_len; | ||||
| 
 | ||||
| 	/* loop elements */ | ||||
| 	while (len > sizeof(struct ath10k_fw_ie)) { | ||||
| 		hdr = (struct ath10k_fw_ie *)data; | ||||
| 
 | ||||
| 		ie_id = le32_to_cpu(hdr->id); | ||||
| 		ie_len = le32_to_cpu(hdr->len); | ||||
| 
 | ||||
| 		len -= sizeof(*hdr); | ||||
| 		data += sizeof(*hdr); | ||||
| 
 | ||||
| 		if (len < ie_len) { | ||||
| 			ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n", | ||||
| 				   ie_id, len, ie_len); | ||||
| 			ret = -EINVAL; | ||||
| 			goto err; | ||||
| 		} | ||||
| 
 | ||||
| 		switch (ie_id) { | ||||
| 		case ATH10K_FW_IE_FW_VERSION: | ||||
| 			if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1) | ||||
| 				break; | ||||
| 
 | ||||
| 			memcpy(ar->hw->wiphy->fw_version, data, ie_len); | ||||
| 			ar->hw->wiphy->fw_version[ie_len] = '\0'; | ||||
| 
 | ||||
| 			ath10k_dbg(ATH10K_DBG_BOOT, | ||||
| 				   "found fw version %s\n", | ||||
| 				    ar->hw->wiphy->fw_version); | ||||
| 			break; | ||||
| 		case ATH10K_FW_IE_TIMESTAMP: | ||||
| 			if (ie_len != sizeof(u32)) | ||||
| 				break; | ||||
| 
 | ||||
| 			timestamp = (__le32 *)data; | ||||
| 
 | ||||
| 			ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", | ||||
| 				   le32_to_cpup(timestamp)); | ||||
| 			break; | ||||
| 		case ATH10K_FW_IE_FEATURES: | ||||
| 			ath10k_dbg(ATH10K_DBG_BOOT, | ||||
| 				   "found firmware features ie (%zd B)\n", | ||||
| 				   ie_len); | ||||
| 
 | ||||
| 			for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { | ||||
| 				index = i / 8; | ||||
| 				bit = i % 8; | ||||
| 
 | ||||
| 				if (index == ie_len) | ||||
| 					break; | ||||
| 
 | ||||
| 				if (data[index] & (1 << bit)) | ||||
| 					__set_bit(i, ar->fw_features); | ||||
| 			} | ||||
| 
 | ||||
| 			ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", | ||||
| 					ar->fw_features, | ||||
| 					sizeof(ar->fw_features)); | ||||
| 			break; | ||||
| 		case ATH10K_FW_IE_FW_IMAGE: | ||||
| 			ath10k_dbg(ATH10K_DBG_BOOT, | ||||
| 				   "found fw image ie (%zd B)\n", | ||||
| 				   ie_len); | ||||
| 
 | ||||
| 			ar->firmware_data = data; | ||||
| 			ar->firmware_len = ie_len; | ||||
| 
 | ||||
| 			break; | ||||
| 		case ATH10K_FW_IE_OTP_IMAGE: | ||||
| 			ath10k_dbg(ATH10K_DBG_BOOT, | ||||
| 				   "found otp image ie (%zd B)\n", | ||||
| 				   ie_len); | ||||
| 
 | ||||
| 			ar->otp_data = data; | ||||
| 			ar->otp_len = ie_len; | ||||
| 
 | ||||
| 			break; | ||||
| 		default: | ||||
| 			ath10k_warn("Unknown FW IE: %u\n", | ||||
| 				    le32_to_cpu(hdr->id)); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		/* jump over the padding */ | ||||
| 		ie_len = ALIGN(ie_len, 4); | ||||
| 
 | ||||
| 		len -= ie_len; | ||||
| 		data += ie_len; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ar->firmware_data || !ar->firmware_len) { | ||||
| 		ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n", | ||||
| 			    name); | ||||
| 		ret = -ENOMEDIUM; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* now fetch the board file */ | ||||
| 	if (ar->hw_params.fw.board == NULL) { | ||||
| 		ath10k_err("board data file not defined"); | ||||
| 		ret = -EINVAL; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->board = ath10k_fetch_fw_file(ar, | ||||
| 					 ar->hw_params.fw.dir, | ||||
| 					 ar->hw_params.fw.board); | ||||
| 	if (IS_ERR(ar->board)) { | ||||
| 		ret = PTR_ERR(ar->board); | ||||
| 		ath10k_err("could not fetch board data (%d)\n", ret); | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->board_data = ar->board->data; | ||||
| 	ar->board_len = ar->board->size; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	ath10k_core_free_firmware_files(ar); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); | ||||
| 	if (ret == 0) { | ||||
| 		ar->fw_api = 2; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_core_fetch_firmware_api_1(ar); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ar->fw_api = 1; | ||||
| 
 | ||||
| out: | ||||
| 	ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_init_download_firmware(struct ath10k *ar) | ||||
| { | ||||
| 	int ret; | ||||
| @ -541,6 +720,9 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, | ||||
| 	INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); | ||||
| 	skb_queue_head_init(&ar->offchan_tx_queue); | ||||
| 
 | ||||
| 	INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); | ||||
| 	skb_queue_head_init(&ar->wmi_mgmt_tx_queue); | ||||
| 
 | ||||
| 	init_waitqueue_head(&ar->event_queue); | ||||
| 
 | ||||
| 	INIT_WORK(&ar->restart_work, ath10k_core_restart); | ||||
| @ -555,6 +737,8 @@ EXPORT_SYMBOL(ath10k_core_create); | ||||
| 
 | ||||
| void ath10k_core_destroy(struct ath10k *ar) | ||||
| { | ||||
| 	ath10k_debug_destroy(ar); | ||||
| 
 | ||||
| 	flush_workqueue(ar->workqueue); | ||||
| 	destroy_workqueue(ar->workqueue); | ||||
| 
 | ||||
| @ -566,6 +750,8 @@ int ath10k_core_start(struct ath10k *ar) | ||||
| { | ||||
| 	int status; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ath10k_bmi_start(ar); | ||||
| 
 | ||||
| 	if (ath10k_init_configure_target(ar)) { | ||||
| @ -616,10 +802,6 @@ int ath10k_core_start(struct ath10k *ar) | ||||
| 
 | ||||
| 	ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version); | ||||
| 
 | ||||
| 	status = ath10k_check_fw_version(ar); | ||||
| 	if (status) | ||||
| 		goto err_disconnect_htc; | ||||
| 
 | ||||
| 	status = ath10k_wmi_cmd_init(ar); | ||||
| 	if (status) { | ||||
| 		ath10k_err("could not send WMI init command (%d)\n", status); | ||||
| @ -642,6 +824,7 @@ int ath10k_core_start(struct ath10k *ar) | ||||
| 		goto err_disconnect_htc; | ||||
| 
 | ||||
| 	ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; | ||||
| 	INIT_LIST_HEAD(&ar->arvifs); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| @ -658,6 +841,8 @@ EXPORT_SYMBOL(ath10k_core_start); | ||||
| 
 | ||||
| void ath10k_core_stop(struct ath10k *ar) | ||||
| { | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ath10k_debug_stop(ar); | ||||
| 	ath10k_htc_stop(&ar->htc); | ||||
| 	ath10k_htt_detach(&ar->htt); | ||||
| @ -705,15 +890,21 @@ static int ath10k_core_probe_fw(struct ath10k *ar) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ret = ath10k_core_start(ar); | ||||
| 	if (ret) { | ||||
| 		ath10k_err("could not init core (%d)\n", ret); | ||||
| 		ath10k_core_free_firmware_files(ar); | ||||
| 		ath10k_hif_power_down(ar); | ||||
| 		mutex_unlock(&ar->conf_mutex); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ath10k_core_stop(ar); | ||||
| 
 | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ath10k_hif_power_down(ar); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -43,15 +43,17 @@ | ||||
| /* Antenna noise floor */ | ||||
| #define ATH10K_DEFAULT_NOISE_FLOOR -95 | ||||
| 
 | ||||
| #define ATH10K_MAX_NUM_MGMT_PENDING 16 | ||||
| 
 | ||||
| struct ath10k; | ||||
| 
 | ||||
| struct ath10k_skb_cb { | ||||
| 	dma_addr_t paddr; | ||||
| 	bool is_mapped; | ||||
| 	bool is_aborted; | ||||
| 	u8 vdev_id; | ||||
| 
 | ||||
| 	struct { | ||||
| 		u8 vdev_id; | ||||
| 		u8 tid; | ||||
| 		bool is_offchan; | ||||
| 
 | ||||
| @ -102,11 +104,26 @@ struct ath10k_bmi { | ||||
| 	bool done_sent; | ||||
| }; | ||||
| 
 | ||||
| #define ATH10K_MAX_MEM_REQS 16 | ||||
| 
 | ||||
| struct ath10k_mem_chunk { | ||||
| 	void *vaddr; | ||||
| 	dma_addr_t paddr; | ||||
| 	u32 len; | ||||
| 	u32 req_id; | ||||
| }; | ||||
| 
 | ||||
| struct ath10k_wmi { | ||||
| 	enum ath10k_htc_ep_id eid; | ||||
| 	struct completion service_ready; | ||||
| 	struct completion unified_ready; | ||||
| 	wait_queue_head_t tx_credits_wq; | ||||
| 	struct wmi_cmd_map *cmd; | ||||
| 	struct wmi_vdev_param_map *vdev_param; | ||||
| 	struct wmi_pdev_param_map *pdev_param; | ||||
| 
 | ||||
| 	u32 num_mem_chunks; | ||||
| 	struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS]; | ||||
| }; | ||||
| 
 | ||||
| struct ath10k_peer_stat { | ||||
| @ -188,6 +205,8 @@ struct ath10k_peer { | ||||
| #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) | ||||
| 
 | ||||
| struct ath10k_vif { | ||||
| 	struct list_head list; | ||||
| 
 | ||||
| 	u32 vdev_id; | ||||
| 	enum wmi_vdev_type vdev_type; | ||||
| 	enum wmi_vdev_subtype vdev_subtype; | ||||
| @ -198,8 +217,10 @@ struct ath10k_vif { | ||||
| 	struct ath10k *ar; | ||||
| 	struct ieee80211_vif *vif; | ||||
| 
 | ||||
| 	struct work_struct wep_key_work; | ||||
| 	struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; | ||||
| 	u8 def_wep_key_index; | ||||
| 	u8 def_wep_key_idx; | ||||
| 	u8 def_wep_key_newidx; | ||||
| 
 | ||||
| 	u16 tx_seq_no; | ||||
| 
 | ||||
| @ -268,6 +289,12 @@ enum ath10k_fw_features { | ||||
| 	/* wmi_mgmt_rx_hdr contains extra RSSI information */ | ||||
| 	ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, | ||||
| 
 | ||||
| 	/* firmware from 10X branch */ | ||||
| 	ATH10K_FW_FEATURE_WMI_10X = 1, | ||||
| 
 | ||||
| 	/* firmware support tx frame management over WMI, otherwise it's HTT */ | ||||
| 	ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2, | ||||
| 
 | ||||
| 	/* keep last */ | ||||
| 	ATH10K_FW_FEATURE_COUNT, | ||||
| }; | ||||
| @ -324,9 +351,19 @@ struct ath10k { | ||||
| 		} fw; | ||||
| 	} hw_params; | ||||
| 
 | ||||
| 	const struct firmware *board_data; | ||||
| 	const struct firmware *board; | ||||
| 	const void *board_data; | ||||
| 	size_t board_len; | ||||
| 
 | ||||
| 	const struct firmware *otp; | ||||
| 	const void *otp_data; | ||||
| 	size_t otp_len; | ||||
| 
 | ||||
| 	const struct firmware *firmware; | ||||
| 	const void *firmware_data; | ||||
| 	size_t firmware_len; | ||||
| 
 | ||||
| 	int fw_api; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct completion started; | ||||
| @ -369,6 +406,7 @@ struct ath10k { | ||||
| 	/* protects shared structure data */ | ||||
| 	spinlock_t data_lock; | ||||
| 
 | ||||
| 	struct list_head arvifs; | ||||
| 	struct list_head peers; | ||||
| 	wait_queue_head_t peer_mapping_wq; | ||||
| 
 | ||||
| @ -377,6 +415,9 @@ struct ath10k { | ||||
| 	struct completion offchan_tx_completed; | ||||
| 	struct sk_buff *offchan_tx_skb; | ||||
| 
 | ||||
| 	struct work_struct wmi_mgmt_tx_work; | ||||
| 	struct sk_buff_head wmi_mgmt_tx_queue; | ||||
| 
 | ||||
| 	enum ath10k_state state; | ||||
| 
 | ||||
| 	struct work_struct restart_work; | ||||
|  | ||||
| @ -618,6 +618,8 @@ int ath10k_debug_start(struct ath10k *ar) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ret = ath10k_debug_htt_stats_req(ar); | ||||
| 	if (ret) | ||||
| 		/* continue normally anyway, this isn't serious */ | ||||
| @ -628,7 +630,13 @@ int ath10k_debug_start(struct ath10k *ar) | ||||
| 
 | ||||
| void ath10k_debug_stop(struct ath10k *ar) | ||||
| { | ||||
| 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	/* Must not use _sync to avoid deadlock, we do that in
 | ||||
| 	 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid | ||||
| 	 * warning from del_timer(). */ | ||||
| 	if (ar->debug.htt_stats_mask != 0) | ||||
| 		cancel_delayed_work(&ar->debug.htt_stats_dwork); | ||||
| } | ||||
| 
 | ||||
| int ath10k_debug_create(struct ath10k *ar) | ||||
| @ -662,6 +670,11 @@ int ath10k_debug_create(struct ath10k *ar) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ath10k_debug_destroy(struct ath10k *ar) | ||||
| { | ||||
| 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); | ||||
| } | ||||
| 
 | ||||
| #endif /* CONFIG_ATH10K_DEBUGFS */ | ||||
| 
 | ||||
| #ifdef CONFIG_ATH10K_DEBUG | ||||
|  | ||||
| @ -46,6 +46,7 @@ extern __printf(1, 2) int ath10k_warn(const char *fmt, ...); | ||||
| int ath10k_debug_start(struct ath10k *ar); | ||||
| void ath10k_debug_stop(struct ath10k *ar); | ||||
| int ath10k_debug_create(struct ath10k *ar); | ||||
| void ath10k_debug_destroy(struct ath10k *ar); | ||||
| void ath10k_debug_read_service_map(struct ath10k *ar, | ||||
| 				   void *service_map, | ||||
| 				   size_t map_size); | ||||
| @ -67,6 +68,10 @@ static inline int ath10k_debug_create(struct ath10k *ar) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline void ath10k_debug_destroy(struct ath10k *ar) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline void ath10k_debug_read_service_map(struct ath10k *ar, | ||||
| 						 void *service_map, | ||||
| 						 size_t map_size) | ||||
|  | ||||
| @ -308,7 +308,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | ||||
| 	struct sk_buff *txdesc = NULL; | ||||
| 	struct htt_cmd *cmd; | ||||
| 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); | ||||
| 	u8 vdev_id = skb_cb->htt.vdev_id; | ||||
| 	u8 vdev_id = skb_cb->vdev_id; | ||||
| 	int len = 0; | ||||
| 	int msdu_id = -1; | ||||
| 	int res; | ||||
| @ -384,7 +384,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | ||||
| 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); | ||||
| 	struct sk_buff *txdesc = NULL; | ||||
| 	bool use_frags; | ||||
| 	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id; | ||||
| 	u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id; | ||||
| 	u8 tid; | ||||
| 	int prefetch_len, desc_len; | ||||
| 	int msdu_id = -1; | ||||
|  | ||||
| @ -20,12 +20,6 @@ | ||||
| 
 | ||||
| #include "targaddrs.h" | ||||
| 
 | ||||
| /* Supported FW version */ | ||||
| #define SUPPORTED_FW_MAJOR	1 | ||||
| #define SUPPORTED_FW_MINOR	0 | ||||
| #define SUPPORTED_FW_RELEASE	0 | ||||
| #define SUPPORTED_FW_BUILD	636 | ||||
| 
 | ||||
| /* QCA988X 1.0 definitions (unsupported) */ | ||||
| #define QCA988X_HW_1_0_CHIP_ID_REV	0x0 | ||||
| 
 | ||||
| @ -38,6 +32,25 @@ | ||||
| #define QCA988X_HW_2_0_BOARD_DATA_FILE	"board.bin" | ||||
| #define QCA988X_HW_2_0_PATCH_LOAD_ADDR	0x1234 | ||||
| 
 | ||||
| #define ATH10K_FW_API2_FILE		"firmware-2.bin" | ||||
| 
 | ||||
| /* includes also the null byte */ | ||||
| #define ATH10K_FIRMWARE_MAGIC               "QCA-ATH10K" | ||||
| 
 | ||||
| struct ath10k_fw_ie { | ||||
| 	__le32 id; | ||||
| 	__le32 len; | ||||
| 	u8 data[0]; | ||||
| }; | ||||
| 
 | ||||
| enum ath10k_fw_ie_type { | ||||
| 	ATH10K_FW_IE_FW_VERSION = 0, | ||||
| 	ATH10K_FW_IE_TIMESTAMP = 1, | ||||
| 	ATH10K_FW_IE_FEATURES = 2, | ||||
| 	ATH10K_FW_IE_FW_IMAGE = 3, | ||||
| 	ATH10K_FW_IE_OTP_IMAGE = 4, | ||||
| }; | ||||
| 
 | ||||
| /* Known pecularities:
 | ||||
|  *  - current FW doesn't support raw rx mode (last tested v599) | ||||
|  *  - current FW dumps upon raw tx mode (last tested v599) | ||||
| @ -59,6 +72,7 @@ enum ath10k_mcast2ucast_mode { | ||||
| 	ATH10K_MCAST2UCAST_ENABLED = 1, | ||||
| }; | ||||
| 
 | ||||
| /* Target specific defines for MAIN firmware */ | ||||
| #define TARGET_NUM_VDEVS			8 | ||||
| #define TARGET_NUM_PEER_AST			2 | ||||
| #define TARGET_NUM_WDS_ENTRIES			32 | ||||
| @ -93,6 +107,36 @@ enum ath10k_mcast2ucast_mode { | ||||
| #define TARGET_NUM_MSDU_DESC			(1024 + 400) | ||||
| #define TARGET_MAX_FRAG_ENTRIES			0 | ||||
| 
 | ||||
| /* Target specific defines for 10.X firmware */ | ||||
| #define TARGET_10X_NUM_VDEVS			16 | ||||
| #define TARGET_10X_NUM_PEER_AST			2 | ||||
| #define TARGET_10X_NUM_WDS_ENTRIES		32 | ||||
| #define TARGET_10X_DMA_BURST_SIZE		0 | ||||
| #define TARGET_10X_MAC_AGGR_DELIM		0 | ||||
| #define TARGET_10X_AST_SKID_LIMIT		16 | ||||
| #define TARGET_10X_NUM_PEERS			(128 + (TARGET_10X_NUM_VDEVS)) | ||||
| #define TARGET_10X_NUM_OFFLOAD_PEERS		0 | ||||
| #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0 | ||||
| #define TARGET_10X_NUM_PEER_KEYS		2 | ||||
| #define TARGET_10X_NUM_TIDS			256 | ||||
| #define TARGET_10X_TX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2)) | ||||
| #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 | ||||
| #define TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES	8 | ||||
| #define TARGET_10X_GTK_OFFLOAD_MAX_VDEV		3 | ||||
| #define TARGET_10X_NUM_MCAST_GROUPS		0 | ||||
| #define TARGET_10X_NUM_MCAST_TABLE_ELEMS	0 | ||||
| #define TARGET_10X_MCAST2UCAST_MODE		ATH10K_MCAST2UCAST_DISABLED | ||||
| #define TARGET_10X_TX_DBG_LOG_SIZE		1024 | ||||
| #define TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 | ||||
| #define TARGET_10X_VOW_CONFIG			0 | ||||
| #define TARGET_10X_NUM_MSDU_DESC		(1024 + 400) | ||||
| #define TARGET_10X_MAX_FRAG_ENTRIES		0 | ||||
| 
 | ||||
| /* Number of Copy Engines supported */ | ||||
| #define CE_COUNT 8 | ||||
|  | ||||
| @ -334,25 +334,29 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) | ||||
| 
 | ||||
| static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) | ||||
| { | ||||
| 	struct ath10k *ar = arvif->ar; | ||||
| 	u32 vdev_param; | ||||
| 
 | ||||
| 	if (value != 0xFFFFFFFF) | ||||
| 		value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold, | ||||
| 			      ATH10K_RTS_MAX); | ||||
| 
 | ||||
| 	return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, | ||||
| 					 WMI_VDEV_PARAM_RTS_THRESHOLD, | ||||
| 					 value); | ||||
| 	vdev_param = ar->wmi.vdev_param->rts_threshold; | ||||
| 	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); | ||||
| 
 | ||||
| 	return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, | ||||
| 					 WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, | ||||
| 					 value); | ||||
| 	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) | ||||
| @ -562,12 +566,9 @@ static int ath10k_monitor_stop(struct ath10k *ar) | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	/* For some reasons, ath10k_wmi_vdev_down() here couse
 | ||||
| 	 * often ath10k_wmi_vdev_stop() to fail. Next we could | ||||
| 	 * not run monitor vdev and driver reload | ||||
| 	 * required. Don't see such problems we skip | ||||
| 	 * ath10k_wmi_vdev_down() here. | ||||
| 	 */ | ||||
| 	ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("Monitor vdev down failed: %d\n", ret); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); | ||||
| 	if (ret) | ||||
| @ -677,6 +678,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, | ||||
| 				struct ieee80211_bss_conf *info, | ||||
| 				const u8 self_peer[ETH_ALEN]) | ||||
| { | ||||
| 	u32 vdev_param; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	lockdep_assert_held(&arvif->ar->conf_mutex); | ||||
| @ -710,8 +712,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, | ||||
| 					WMI_VDEV_PARAM_ATIM_WINDOW, | ||||
| 	vdev_param = arvif->ar->wmi.vdev_param->atim_window; | ||||
| 	ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, | ||||
| 					ATH10K_DEFAULT_ATIM); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n", | ||||
| @ -721,35 +723,30 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, | ||||
| /*
 | ||||
|  * Review this when mac80211 gains per-interface powersave support. | ||||
|  */ | ||||
| static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||||
| static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) | ||||
| { | ||||
| 	struct ath10k_generic_iter *ar_iter = data; | ||||
| 	struct ieee80211_conf *conf = &ar_iter->ar->hw->conf; | ||||
| 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||||
| 	struct ath10k *ar = arvif->ar; | ||||
| 	struct ieee80211_conf *conf = &ar->hw->conf; | ||||
| 	enum wmi_sta_powersave_param param; | ||||
| 	enum wmi_sta_ps_mode psmode; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	lockdep_assert_held(&arvif->ar->conf_mutex); | ||||
| 
 | ||||
| 	if (vif->type != NL80211_IFTYPE_STATION) | ||||
| 		return; | ||||
| 	if (arvif->vif->type != NL80211_IFTYPE_STATION) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (conf->flags & IEEE80211_CONF_PS) { | ||||
| 		psmode = WMI_STA_PS_MODE_ENABLED; | ||||
| 		param = WMI_STA_PS_PARAM_INACTIVITY_TIME; | ||||
| 
 | ||||
| 		ret = ath10k_wmi_set_sta_ps_param(ar_iter->ar, | ||||
| 						  arvif->vdev_id, | ||||
| 						  param, | ||||
| 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, | ||||
| 						  conf->dynamic_ps_timeout); | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("Failed to set inactivity time for VDEV: %d\n", | ||||
| 				    arvif->vdev_id); | ||||
| 			return; | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		ar_iter->ret = ret; | ||||
| 	} else { | ||||
| 		psmode = WMI_STA_PS_MODE_DISABLED; | ||||
| 	} | ||||
| @ -757,11 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", | ||||
| 		   arvif->vdev_id, psmode ? "enable" : "disable"); | ||||
| 
 | ||||
| 	ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id, | ||||
| 					     psmode); | ||||
| 	if (ar_iter->ret) | ||||
| 	ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n", | ||||
| 			    psmode, arvif->vdev_id); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**********************/ | ||||
| @ -1031,14 +1031,27 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, | ||||
| 				    struct wmi_peer_assoc_complete_arg *arg) | ||||
| { | ||||
| 	const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||||
| 	u8 ampdu_factor; | ||||
| 
 | ||||
| 	if (!vht_cap->vht_supported) | ||||
| 		return; | ||||
| 
 | ||||
| 	arg->peer_flags |= WMI_PEER_VHT; | ||||
| 
 | ||||
| 	arg->peer_vht_caps = vht_cap->cap; | ||||
| 
 | ||||
| 
 | ||||
| 	ampdu_factor = (vht_cap->cap & | ||||
| 			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> | ||||
| 		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||||
| 
 | ||||
| 	/* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
 | ||||
| 	 * zero in VHT IE. Using it would result in degraded throughput. | ||||
| 	 * arg->peer_max_mpdu at this point contains HT max_mpdu so keep | ||||
| 	 * it if VHT max_mpdu is smaller. */ | ||||
| 	arg->peer_max_mpdu = max(arg->peer_max_mpdu, | ||||
| 				 (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + | ||||
| 					ampdu_factor)) - 1); | ||||
| 
 | ||||
| 	if (sta->bandwidth == IEEE80211_STA_RX_BW_80) | ||||
| 		arg->peer_flags |= WMI_PEER_80MHZ; | ||||
| 
 | ||||
| @ -1124,26 +1137,25 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, | ||||
| 	WARN_ON(phymode == MODE_UNKNOWN); | ||||
| } | ||||
| 
 | ||||
| static int ath10k_peer_assoc(struct ath10k *ar, | ||||
| 			     struct ath10k_vif *arvif, | ||||
| 			     struct ieee80211_sta *sta, | ||||
| 			     struct ieee80211_bss_conf *bss_conf) | ||||
| static int ath10k_peer_assoc_prepare(struct ath10k *ar, | ||||
| 				     struct ath10k_vif *arvif, | ||||
| 				     struct ieee80211_sta *sta, | ||||
| 				     struct ieee80211_bss_conf *bss_conf, | ||||
| 				     struct wmi_peer_assoc_complete_arg *arg) | ||||
| { | ||||
| 	struct wmi_peer_assoc_complete_arg arg; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg)); | ||||
| 	memset(arg, 0, sizeof(*arg)); | ||||
| 
 | ||||
| 	ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg); | ||||
| 	ath10k_peer_assoc_h_crypto(ar, arvif, &arg); | ||||
| 	ath10k_peer_assoc_h_rates(ar, sta, &arg); | ||||
| 	ath10k_peer_assoc_h_ht(ar, sta, &arg); | ||||
| 	ath10k_peer_assoc_h_vht(ar, sta, &arg); | ||||
| 	ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, &arg); | ||||
| 	ath10k_peer_assoc_h_phymode(ar, arvif, sta, &arg); | ||||
| 	ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg); | ||||
| 	ath10k_peer_assoc_h_crypto(ar, arvif, arg); | ||||
| 	ath10k_peer_assoc_h_rates(ar, sta, arg); | ||||
| 	ath10k_peer_assoc_h_ht(ar, sta, arg); | ||||
| 	ath10k_peer_assoc_h_vht(ar, sta, arg); | ||||
| 	ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg); | ||||
| 	ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg); | ||||
| 
 | ||||
| 	return ath10k_wmi_peer_assoc(ar, &arg); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* can be called only in mac80211 callbacks due to `key_count` usage */ | ||||
| @ -1153,6 +1165,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, | ||||
| { | ||||
| 	struct ath10k *ar = hw->priv; | ||||
| 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||||
| 	struct wmi_peer_assoc_complete_arg peer_arg; | ||||
| 	struct ieee80211_sta *ap_sta; | ||||
| 	int ret; | ||||
| 
 | ||||
| @ -1168,15 +1181,24 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_peer_assoc(ar, arvif, ap_sta, bss_conf); | ||||
| 	ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, | ||||
| 					bss_conf, &peer_arg); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("Peer assoc failed for %pM\n", bss_conf->bssid); | ||||
| 		ath10k_warn("Peer assoc prepare failed for %pM\n: %d", | ||||
| 			    bss_conf->bssid, ret); | ||||
| 		rcu_read_unlock(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	rcu_read_unlock(); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_peer_assoc(ar, &peer_arg); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("Peer assoc failed for %pM\n: %d", | ||||
| 			    bss_conf->bssid, ret); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, | ||||
| 		   "mac vdev %d up (associated) bssid %pM aid %d\n", | ||||
| 		   arvif->vdev_id, bss_conf->bssid, bss_conf->aid); | ||||
| @ -1224,19 +1246,28 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, | ||||
| 	/* FIXME: why don't we print error if wmi call fails? */ | ||||
| 	ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); | ||||
| 
 | ||||
| 	arvif->def_wep_key_index = 0; | ||||
| 	arvif->def_wep_key_idx = 0; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, | ||||
| 				struct ieee80211_sta *sta) | ||||
| { | ||||
| 	struct wmi_peer_assoc_complete_arg peer_arg; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ret = ath10k_peer_assoc(ar, arvif, sta, NULL); | ||||
| 	ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr); | ||||
| 		ath10k_warn("WMI peer assoc prepare failed for %pM\n", | ||||
| 			    sta->addr); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_wmi_peer_assoc(ar, &peer_arg); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("Peer assoc failed for STA %pM\n: %d", | ||||
| 			    sta->addr, ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| @ -1405,6 +1436,33 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, | ||||
| /* TX handlers */ | ||||
| /***************/ | ||||
| 
 | ||||
| static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr) | ||||
| { | ||||
| 	if (ieee80211_is_mgmt(hdr->frame_control)) | ||||
| 		return HTT_DATA_TX_EXT_TID_MGMT; | ||||
| 
 | ||||
| 	if (!ieee80211_is_data_qos(hdr->frame_control)) | ||||
| 		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; | ||||
| 
 | ||||
| 	if (!is_unicast_ether_addr(ieee80211_get_DA(hdr))) | ||||
| 		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; | ||||
| 
 | ||||
| 	return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; | ||||
| } | ||||
| 
 | ||||
| static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, | ||||
| 				  struct ieee80211_tx_info *info) | ||||
| { | ||||
| 	if (info->control.vif) | ||||
| 		return ath10k_vif_to_arvif(info->control.vif)->vdev_id; | ||||
| 
 | ||||
| 	if (ar->monitor_enabled) | ||||
| 		return ar->monitor_vdev_id; | ||||
| 
 | ||||
| 	ath10k_warn("could not resolve vdev id\n"); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Frames sent to the FW have to be in "Native Wifi" format. | ||||
|  * Strip the QoS field from the 802.11 header. | ||||
| @ -1425,6 +1483,30 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, | ||||
| 	skb_pull(skb, IEEE80211_QOS_CTL_LEN); | ||||
| } | ||||
| 
 | ||||
| static void ath10k_tx_wep_key_work(struct work_struct *work) | ||||
| { | ||||
| 	struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, | ||||
| 						wep_key_work); | ||||
| 	int ret, keyidx = arvif->def_wep_key_newidx; | ||||
| 
 | ||||
| 	if (arvif->def_wep_key_idx == keyidx) | ||||
| 		return; | ||||
| 
 | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", | ||||
| 		   arvif->vdev_id, keyidx); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_set_param(arvif->ar, | ||||
| 					arvif->vdev_id, | ||||
| 					arvif->ar->wmi.vdev_param->def_keyid, | ||||
| 					keyidx); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("could not update wep keyidx (%d)\n", ret); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	arvif->def_wep_key_idx = keyidx; | ||||
| } | ||||
| 
 | ||||
| static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) | ||||
| { | ||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| @ -1433,7 +1515,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) | ||||
| 	struct ath10k *ar = arvif->ar; | ||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 	struct ieee80211_key_conf *key = info->control.hw_key; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!ieee80211_has_protected(hdr->frame_control)) | ||||
| 		return; | ||||
| @ -1445,21 +1526,14 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) | ||||
| 	    key->cipher != WLAN_CIPHER_SUITE_WEP104) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (key->keyidx == arvif->def_wep_key_index) | ||||
| 	if (key->keyidx == arvif->def_wep_key_idx) | ||||
| 		return; | ||||
| 
 | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d keyidx %d\n", | ||||
| 		   arvif->vdev_id, key->keyidx); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 					WMI_VDEV_PARAM_DEF_KEYID, | ||||
| 					key->keyidx); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("could not update wep keyidx (%d)\n", ret); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	arvif->def_wep_key_index = key->keyidx; | ||||
| 	/* FIXME: Most likely a few frames will be TXed with an old key. Simply
 | ||||
| 	 * queueing frames until key index is updated is not an option because | ||||
| 	 * sk_buff may need more processing to be done, e.g. offchannel */ | ||||
| 	arvif->def_wep_key_newidx = key->keyidx; | ||||
| 	ieee80211_queue_work(ar->hw, &arvif->wep_key_work); | ||||
| } | ||||
| 
 | ||||
| static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) | ||||
| @ -1489,7 +1563,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) | ||||
| static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) | ||||
| { | ||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 	int ret; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	if (ar->htt.target_version_major >= 3) { | ||||
| 		/* Since HTT 3.0 there is no separate mgmt tx command */ | ||||
| @ -1497,16 +1571,32 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ieee80211_is_mgmt(hdr->frame_control)) | ||||
| 		ret = ath10k_htt_mgmt_tx(&ar->htt, skb); | ||||
| 	else if (ieee80211_is_nullfunc(hdr->frame_control)) | ||||
| 	if (ieee80211_is_mgmt(hdr->frame_control)) { | ||||
| 		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, | ||||
| 			     ar->fw_features)) { | ||||
| 			if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= | ||||
| 			    ATH10K_MAX_NUM_MGMT_PENDING) { | ||||
| 				ath10k_warn("wmi mgmt_tx queue limit reached\n"); | ||||
| 				ret = -EBUSY; | ||||
| 				goto exit; | ||||
| 			} | ||||
| 
 | ||||
| 			skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb); | ||||
| 			ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); | ||||
| 		} else { | ||||
| 			ret = ath10k_htt_mgmt_tx(&ar->htt, skb); | ||||
| 		} | ||||
| 	} else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, | ||||
| 			     ar->fw_features) && | ||||
| 		   ieee80211_is_nullfunc(hdr->frame_control)) { | ||||
| 		/* FW does not report tx status properly for NullFunc frames
 | ||||
| 		 * unless they are sent through mgmt tx path. mac80211 sends | ||||
| 		 * those frames when it detects link/beacon loss and depends on | ||||
| 		 * the tx status to be correct. */ | ||||
| 		 * those frames when it detects link/beacon loss and depends | ||||
| 		 * on the tx status to be correct. */ | ||||
| 		ret = ath10k_htt_mgmt_tx(&ar->htt, skb); | ||||
| 	else | ||||
| 	} else { | ||||
| 		ret = ath10k_htt_tx(&ar->htt, skb); | ||||
| 	} | ||||
| 
 | ||||
| exit: | ||||
| 	if (ret) { | ||||
| @ -1557,7 +1647,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) | ||||
| 
 | ||||
| 		hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 		peer_addr = ieee80211_get_DA(hdr); | ||||
| 		vdev_id = ATH10K_SKB_CB(skb)->htt.vdev_id; | ||||
| 		vdev_id = ATH10K_SKB_CB(skb)->vdev_id; | ||||
| 
 | ||||
| 		spin_lock_bh(&ar->data_lock); | ||||
| 		peer = ath10k_peer_find(ar, vdev_id, peer_addr); | ||||
| @ -1599,6 +1689,36 @@ void ath10k_offchan_tx_work(struct work_struct *work) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar) | ||||
| { | ||||
| 	struct sk_buff *skb; | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); | ||||
| 		if (!skb) | ||||
| 			break; | ||||
| 
 | ||||
| 		ieee80211_free_txskb(ar->hw, skb); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) | ||||
| { | ||||
| 	struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work); | ||||
| 	struct sk_buff *skb; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); | ||||
| 		if (!skb) | ||||
| 			break; | ||||
| 
 | ||||
| 		ret = ath10k_wmi_mgmt_tx(ar, skb); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("wmi mgmt_tx failed (%d)\n", ret); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /************/ | ||||
| /* Scanning */ | ||||
| /************/ | ||||
| @ -1722,16 +1842,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, | ||||
| 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||||
| 	struct ath10k *ar = hw->priv; | ||||
| 	struct ath10k_vif *arvif = NULL; | ||||
| 	u32 vdev_id = 0; | ||||
| 	u8 tid; | ||||
| 
 | ||||
| 	if (info->control.vif) { | ||||
| 		arvif = ath10k_vif_to_arvif(info->control.vif); | ||||
| 		vdev_id = arvif->vdev_id; | ||||
| 	} else if (ar->monitor_enabled) { | ||||
| 		vdev_id = ar->monitor_vdev_id; | ||||
| 	} | ||||
| 	u8 tid, vdev_id; | ||||
| 
 | ||||
| 	/* We should disable CCK RATE due to P2P */ | ||||
| 	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) | ||||
| @ -1739,14 +1850,8 @@ static void ath10k_tx(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	/* we must calculate tid before we apply qos workaround
 | ||||
| 	 * as we'd lose the qos control field */ | ||||
| 	tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; | ||||
| 	if (ieee80211_is_mgmt(hdr->frame_control)) { | ||||
| 		tid = HTT_DATA_TX_EXT_TID_MGMT; | ||||
| 	} else if (ieee80211_is_data_qos(hdr->frame_control) && | ||||
| 		   is_unicast_ether_addr(ieee80211_get_DA(hdr))) { | ||||
| 		u8 *qc = ieee80211_get_qos_ctl(hdr); | ||||
| 		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||||
| 	} | ||||
| 	tid = ath10k_tx_h_get_tid(hdr); | ||||
| 	vdev_id = ath10k_tx_h_get_vdev_id(ar, info); | ||||
| 
 | ||||
| 	/* it makes no sense to process injected frames like that */ | ||||
| 	if (info->control.vif && | ||||
| @ -1757,14 +1862,14 @@ static void ath10k_tx(struct ieee80211_hw *hw, | ||||
| 		ath10k_tx_h_seq_no(skb); | ||||
| 	} | ||||
| 
 | ||||
| 	ATH10K_SKB_CB(skb)->vdev_id = vdev_id; | ||||
| 	ATH10K_SKB_CB(skb)->htt.is_offchan = false; | ||||
| 	ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id; | ||||
| 	ATH10K_SKB_CB(skb)->htt.tid = tid; | ||||
| 
 | ||||
| 	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { | ||||
| 		spin_lock_bh(&ar->data_lock); | ||||
| 		ATH10K_SKB_CB(skb)->htt.is_offchan = true; | ||||
| 		ATH10K_SKB_CB(skb)->htt.vdev_id = ar->scan.vdev_id; | ||||
| 		ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id; | ||||
| 		spin_unlock_bh(&ar->data_lock); | ||||
| 
 | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb); | ||||
| @ -1786,6 +1891,7 @@ void ath10k_halt(struct ath10k *ar) | ||||
| 
 | ||||
| 	del_timer_sync(&ar->scan.timeout); | ||||
| 	ath10k_offchan_tx_purge(ar); | ||||
| 	ath10k_mgmt_over_wmi_tx_purge(ar); | ||||
| 	ath10k_peer_cleanup_all(ar); | ||||
| 	ath10k_core_stop(ar); | ||||
| 	ath10k_hif_power_down(ar); | ||||
| @ -1832,12 +1938,12 @@ static int ath10k_start(struct ieee80211_hw *hw) | ||||
| 	else if (ar->state == ATH10K_STATE_RESTARTING) | ||||
| 		ar->state = ATH10K_STATE_RESTARTED; | ||||
| 
 | ||||
| 	ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); | ||||
| 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", | ||||
| 			    ret); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 0); | ||||
| 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", | ||||
| 			    ret); | ||||
| @ -1862,32 +1968,29 @@ static void ath10k_stop(struct ieee80211_hw *hw) | ||||
| 	ar->state = ATH10K_STATE_OFF; | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	ath10k_mgmt_over_wmi_tx_purge(ar); | ||||
| 
 | ||||
| 	cancel_work_sync(&ar->offchan_tx_work); | ||||
| 	cancel_work_sync(&ar->wmi_mgmt_tx_work); | ||||
| 	cancel_work_sync(&ar->restart_work); | ||||
| } | ||||
| 
 | ||||
| static void ath10k_config_ps(struct ath10k *ar) | ||||
| static int ath10k_config_ps(struct ath10k *ar) | ||||
| { | ||||
| 	struct ath10k_generic_iter ar_iter; | ||||
| 	struct ath10k_vif *arvif; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	lockdep_assert_held(&ar->conf_mutex); | ||||
| 
 | ||||
| 	/* During HW reconfiguration mac80211 reports all interfaces that were
 | ||||
| 	 * running until reconfiguration was started. Since FW doesn't have any | ||||
| 	 * vdevs at this point we must not iterate over this interface list. | ||||
| 	 * This setting will be updated upon add_interface(). */ | ||||
| 	if (ar->state == ATH10K_STATE_RESTARTED) | ||||
| 		return; | ||||
| 	list_for_each_entry(arvif, &ar->arvifs, list) { | ||||
| 		ret = ath10k_mac_vif_setup_ps(arvif); | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("could not setup powersave (%d)\n", ret); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); | ||||
| 	ar_iter.ar = ar; | ||||
| 
 | ||||
| 	ieee80211_iterate_active_interfaces_atomic( | ||||
| 		ar->hw, IEEE80211_IFACE_ITER_NORMAL, | ||||
| 		ath10k_ps_iter, &ar_iter); | ||||
| 
 | ||||
| 	if (ar_iter.ret) | ||||
| 		ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_config(struct ieee80211_hw *hw, u32 changed) | ||||
| @ -1936,6 +2039,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, | ||||
| 	int ret = 0; | ||||
| 	u32 value; | ||||
| 	int bit; | ||||
| 	u32 vdev_param; | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 
 | ||||
| @ -1944,21 +2048,22 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, | ||||
| 	arvif->ar = ar; | ||||
| 	arvif->vif = vif; | ||||
| 
 | ||||
| 	INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); | ||||
| 
 | ||||
| 	if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { | ||||
| 		ath10k_warn("Only one monitor interface allowed\n"); | ||||
| 		ret = -EBUSY; | ||||
| 		goto exit; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	bit = ffs(ar->free_vdev_map); | ||||
| 	if (bit == 0) { | ||||
| 		ret = -EBUSY; | ||||
| 		goto exit; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	arvif->vdev_id = bit - 1; | ||||
| 	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; | ||||
| 	ar->free_vdev_map &= ~(1 << arvif->vdev_id); | ||||
| 
 | ||||
| 	if (ar->p2p) | ||||
| 		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; | ||||
| @ -1994,25 +2099,34 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, | ||||
| 				     arvif->vdev_subtype, vif->addr); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("WMI vdev create failed: ret %d\n", ret); | ||||
| 		goto exit; | ||||
| 		goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_set_param(ar, 0, WMI_VDEV_PARAM_DEF_KEYID, | ||||
| 					arvif->def_wep_key_index); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("Failed to set default keyid: %d\n", ret); | ||||
| 	ar->free_vdev_map &= ~BIT(arvif->vdev_id); | ||||
| 	list_add(&arvif->list, &ar->arvifs); | ||||
| 
 | ||||
| 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 					WMI_VDEV_PARAM_TX_ENCAP_TYPE, | ||||
| 	vdev_param = ar->wmi.vdev_param->def_keyid; | ||||
| 	ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, | ||||
| 					arvif->def_wep_key_idx); | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("Failed to set default keyid: %d\n", ret); | ||||
| 		goto err_vdev_delete; | ||||
| 	} | ||||
| 
 | ||||
| 	vdev_param = ar->wmi.vdev_param->tx_encap_type; | ||||
| 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 					ATH10K_HW_TXRX_NATIVE_WIFI); | ||||
| 	if (ret) | ||||
| 	/* 10.X firmware does not support this VDEV parameter. Do not warn */ | ||||
| 	if (ret && ret != -EOPNOTSUPP) { | ||||
| 		ath10k_warn("Failed to set TX encap: %d\n", ret); | ||||
| 		goto err_vdev_delete; | ||||
| 	} | ||||
| 
 | ||||
| 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { | ||||
| 		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("Failed to create peer for AP: %d\n", ret); | ||||
| 			goto exit; | ||||
| 			goto err_vdev_delete; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -2021,39 +2135,62 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, | ||||
| 		value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; | ||||
| 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, | ||||
| 						  param, value); | ||||
| 		if (ret) | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("Failed to set RX wake policy: %d\n", ret); | ||||
| 			goto err_peer_delete; | ||||
| 		} | ||||
| 
 | ||||
| 		param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; | ||||
| 		value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; | ||||
| 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, | ||||
| 						  param, value); | ||||
| 		if (ret) | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("Failed to set TX wake thresh: %d\n", ret); | ||||
| 			goto err_peer_delete; | ||||
| 		} | ||||
| 
 | ||||
| 		param = WMI_STA_PS_PARAM_PSPOLL_COUNT; | ||||
| 		value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; | ||||
| 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, | ||||
| 						  param, value); | ||||
| 		if (ret) | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("Failed to set PSPOLL count: %d\n", ret); | ||||
| 			goto err_peer_delete; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); | ||||
| 	if (ret) | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", | ||||
| 			    arvif->vdev_id, ret); | ||||
| 		goto err_peer_delete; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); | ||||
| 	if (ret) | ||||
| 	if (ret) { | ||||
| 		ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", | ||||
| 			    arvif->vdev_id, ret); | ||||
| 		goto err_peer_delete; | ||||
| 	} | ||||
| 
 | ||||
| 	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) | ||||
| 		ar->monitor_present = true; | ||||
| 
 | ||||
| exit: | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 	return 0; | ||||
| 
 | ||||
| err_peer_delete: | ||||
| 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) | ||||
| 		ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); | ||||
| 
 | ||||
| err_vdev_delete: | ||||
| 	ath10k_wmi_vdev_delete(ar, arvif->vdev_id); | ||||
| 	ar->free_vdev_map &= ~BIT(arvif->vdev_id); | ||||
| 	list_del(&arvif->list); | ||||
| 
 | ||||
| err: | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -2066,6 +2203,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	cancel_work_sync(&arvif->wep_key_work); | ||||
| 
 | ||||
| 	spin_lock_bh(&ar->data_lock); | ||||
| 	if (arvif->beacon) { | ||||
| 		dev_kfree_skb_any(arvif->beacon); | ||||
| @ -2074,6 +2213,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, | ||||
| 	spin_unlock_bh(&ar->data_lock); | ||||
| 
 | ||||
| 	ar->free_vdev_map |= 1 << (arvif->vdev_id); | ||||
| 	list_del(&arvif->list); | ||||
| 
 | ||||
| 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { | ||||
| 		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); | ||||
| @ -2154,6 +2294,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 	struct ath10k *ar = hw->priv; | ||||
| 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||||
| 	int ret = 0; | ||||
| 	u32 vdev_param, pdev_param; | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 
 | ||||
| @ -2162,8 +2303,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	if (changed & BSS_CHANGED_BEACON_INT) { | ||||
| 		arvif->beacon_interval = info->beacon_int; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 						WMI_VDEV_PARAM_BEACON_INTERVAL, | ||||
| 		vdev_param = ar->wmi.vdev_param->beacon_interval; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 						arvif->beacon_interval); | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, | ||||
| 			   "mac vdev %d beacon_interval %d\n", | ||||
| @ -2179,8 +2320,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 			   "vdev %d set beacon tx mode to staggered\n", | ||||
| 			   arvif->vdev_id); | ||||
| 
 | ||||
| 		ret = ath10k_wmi_pdev_set_param(ar, | ||||
| 						WMI_PDEV_PARAM_BEACON_TX_MODE, | ||||
| 		pdev_param = ar->wmi.pdev_param->beacon_tx_mode; | ||||
| 		ret = ath10k_wmi_pdev_set_param(ar, pdev_param, | ||||
| 						WMI_BEACON_STAGGERED_MODE); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("Failed to set beacon mode for VDEV: %d\n", | ||||
| @ -2194,8 +2335,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 			   "mac vdev %d dtim_period %d\n", | ||||
| 			   arvif->vdev_id, arvif->dtim_period); | ||||
| 
 | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 						WMI_VDEV_PARAM_DTIM_PERIOD, | ||||
| 		vdev_param = ar->wmi.vdev_param->dtim_period; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 						arvif->dtim_period); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("Failed to set dtim period for VDEV: %d\n", | ||||
| @ -2262,8 +2403,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", | ||||
| 			   arvif->vdev_id, cts_prot); | ||||
| 
 | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 						WMI_VDEV_PARAM_ENABLE_RTSCTS, | ||||
| 		vdev_param = ar->wmi.vdev_param->enable_rtscts; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 						cts_prot); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("Failed to set CTS prot for VDEV: %d\n", | ||||
| @ -2281,8 +2422,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", | ||||
| 			   arvif->vdev_id, slottime); | ||||
| 
 | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 						WMI_VDEV_PARAM_SLOT_TIME, | ||||
| 		vdev_param = ar->wmi.vdev_param->slot_time; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 						slottime); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("Failed to set erp slot for VDEV: %d\n", | ||||
| @ -2300,8 +2441,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 			   "mac vdev %d preamble %dn", | ||||
| 			   arvif->vdev_id, preamble); | ||||
| 
 | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, | ||||
| 						WMI_VDEV_PARAM_PREAMBLE, | ||||
| 		vdev_param = ar->wmi.vdev_param->preamble; | ||||
| 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, | ||||
| 						preamble); | ||||
| 		if (ret) | ||||
| 			ath10k_warn("Failed to set preamble for VDEV: %d\n", | ||||
| @ -2751,86 +2892,51 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) | ||||
|  * Both RTS and Fragmentation threshold are interface-specific | ||||
|  * in ath10k, but device-specific in mac80211. | ||||
|  */ | ||||
| static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath10k_generic_iter *ar_iter = data; | ||||
| 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||||
| 	u32 rts = ar_iter->ar->hw->wiphy->rts_threshold; | ||||
| 
 | ||||
| 	lockdep_assert_held(&arvif->ar->conf_mutex); | ||||
| 
 | ||||
| 	/* During HW reconfiguration mac80211 reports all interfaces that were
 | ||||
| 	 * running until reconfiguration was started. Since FW doesn't have any | ||||
| 	 * vdevs at this point we must not iterate over this interface list. | ||||
| 	 * This setting will be updated upon add_interface(). */ | ||||
| 	if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) | ||||
| 		return; | ||||
| 
 | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts_threshold %d\n", | ||||
| 		   arvif->vdev_id, rts); | ||||
| 
 | ||||
| 	ar_iter->ret = ath10k_mac_set_rts(arvif, rts); | ||||
| 	if (ar_iter->ret) | ||||
| 		ath10k_warn("Failed to set RTS threshold for VDEV: %d\n", | ||||
| 			    arvif->vdev_id); | ||||
| } | ||||
| 
 | ||||
| static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||||
| { | ||||
| 	struct ath10k_generic_iter ar_iter; | ||||
| 	struct ath10k *ar = hw->priv; | ||||
| 
 | ||||
| 	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); | ||||
| 	ar_iter.ar = ar; | ||||
| 	struct ath10k_vif *arvif; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 	ieee80211_iterate_active_interfaces_atomic( | ||||
| 		hw, IEEE80211_IFACE_ITER_NORMAL, | ||||
| 		ath10k_set_rts_iter, &ar_iter); | ||||
| 	list_for_each_entry(arvif, &ar->arvifs, list) { | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", | ||||
| 			   arvif->vdev_id, value); | ||||
| 
 | ||||
| 		ret = ath10k_mac_set_rts(arvif, value); | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("could not set rts threshold for vdev %d (%d)\n", | ||||
| 				    arvif->vdev_id, ret); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	return ar_iter.ret; | ||||
| } | ||||
| 
 | ||||
| static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath10k_generic_iter *ar_iter = data; | ||||
| 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); | ||||
| 	u32 frag = ar_iter->ar->hw->wiphy->frag_threshold; | ||||
| 
 | ||||
| 	lockdep_assert_held(&arvif->ar->conf_mutex); | ||||
| 
 | ||||
| 	/* During HW reconfiguration mac80211 reports all interfaces that were
 | ||||
| 	 * running until reconfiguration was started. Since FW doesn't have any | ||||
| 	 * vdevs at this point we must not iterate over this interface list. | ||||
| 	 * This setting will be updated upon add_interface(). */ | ||||
| 	if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) | ||||
| 		return; | ||||
| 
 | ||||
| 	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation_threshold %d\n", | ||||
| 		   arvif->vdev_id, frag); | ||||
| 
 | ||||
| 	ar_iter->ret = ath10k_mac_set_frag(arvif, frag); | ||||
| 	if (ar_iter->ret) | ||||
| 		ath10k_warn("Failed to set frag threshold for VDEV: %d\n", | ||||
| 			    arvif->vdev_id); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) | ||||
| { | ||||
| 	struct ath10k_generic_iter ar_iter; | ||||
| 	struct ath10k *ar = hw->priv; | ||||
| 
 | ||||
| 	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); | ||||
| 	ar_iter.ar = ar; | ||||
| 	struct ath10k_vif *arvif; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	mutex_lock(&ar->conf_mutex); | ||||
| 	ieee80211_iterate_active_interfaces_atomic( | ||||
| 		hw, IEEE80211_IFACE_ITER_NORMAL, | ||||
| 		ath10k_set_frag_iter, &ar_iter); | ||||
| 	list_for_each_entry(arvif, &ar->arvifs, list) { | ||||
| 		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", | ||||
| 			   arvif->vdev_id, value); | ||||
| 
 | ||||
| 		ret = ath10k_mac_set_rts(arvif, value); | ||||
| 		if (ret) { | ||||
| 			ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n", | ||||
| 				    arvif->vdev_id, ret); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&ar->conf_mutex); | ||||
| 
 | ||||
| 	return ar_iter.ret; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) | ||||
|  | ||||
| @ -34,6 +34,8 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id); | ||||
| void ath10k_reset_scan(unsigned long ptr); | ||||
| void ath10k_offchan_tx_purge(struct ath10k *ar); | ||||
| void ath10k_offchan_tx_work(struct work_struct *work); | ||||
| void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); | ||||
| void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); | ||||
| void ath10k_halt(struct ath10k *ar); | ||||
| 
 | ||||
| static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) | ||||
|  | ||||
| @ -720,18 +720,8 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, | ||||
| 			"ath10k tx: data: ", | ||||
| 			nbuf->data, nbuf->len); | ||||
| 
 | ||||
| 	/* Make sure we have resources to handle this request */ | ||||
| 	spin_lock_bh(&pipe_info->pipe_lock); | ||||
| 	if (!pipe_info->num_sends_allowed) { | ||||
| 		ath10k_warn("Pipe: %d is full\n", pipe_id); | ||||
| 		spin_unlock_bh(&pipe_info->pipe_lock); | ||||
| 		return -ENOSR; | ||||
| 	} | ||||
| 	pipe_info->num_sends_allowed--; | ||||
| 	spin_unlock_bh(&pipe_info->pipe_lock); | ||||
| 
 | ||||
| 	ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, transfer_id, | ||||
| 				      skb_cb->paddr, len, flags); | ||||
| 	ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id, | ||||
| 			     flags); | ||||
| 	if (ret) | ||||
| 		ath10k_warn("CE send failed: %p\n", nbuf); | ||||
| 
 | ||||
| @ -741,14 +731,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, | ||||
| static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) | ||||
| { | ||||
| 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | ||||
| 	struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe]); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	spin_lock_bh(&pipe_info->pipe_lock); | ||||
| 	ret = pipe_info->num_sends_allowed; | ||||
| 	spin_unlock_bh(&pipe_info->pipe_lock); | ||||
| 
 | ||||
| 	return ret; | ||||
| 	return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); | ||||
| } | ||||
| 
 | ||||
| static void ath10k_pci_hif_dump_area(struct ath10k *ar) | ||||
| @ -863,7 +846,6 @@ static int ath10k_pci_start_ce(struct ath10k *ar) | ||||
| 						   ath10k_pci_ce_send_done, | ||||
| 						   disable_interrupts); | ||||
| 			completions += attr->src_nentries; | ||||
| 			pipe_info->num_sends_allowed = attr->src_nentries - 1; | ||||
| 		} | ||||
| 
 | ||||
| 		if (attr->dest_nentries) { | ||||
| @ -1033,7 +1015,6 @@ static void ath10k_pci_process_ce(struct ath10k *ar) | ||||
| 		 */ | ||||
| 		spin_lock_bh(&compl->pipe_info->pipe_lock); | ||||
| 		list_add_tail(&compl->list, &compl->pipe_info->compl_free); | ||||
| 		compl->pipe_info->num_sends_allowed += send_done; | ||||
| 		spin_unlock_bh(&compl->pipe_info->pipe_lock); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -178,9 +178,6 @@ struct ath10k_pci_pipe { | ||||
| 	/* List of free CE completion slots */ | ||||
| 	struct list_head compl_free; | ||||
| 
 | ||||
| 	/* Limit the number of outstanding send requests. */ | ||||
| 	int num_sends_allowed; | ||||
| 
 | ||||
| 	struct ath10k_pci *ar_pci; | ||||
| 	struct tasklet_struct intr; | ||||
| }; | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -60,7 +60,7 @@ | ||||
| /* disable credit flow control on a specific service */ | ||||
| #define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL          (1 << 3) | ||||
| #define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT    8 | ||||
| #define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK     0xFF00 | ||||
| #define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK     0xFF00U | ||||
| 
 | ||||
| /* connect response status codes */ | ||||
| #define HTC_SERVICE_SUCCESS      0 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user