xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file mlan_usb.c
2  *
3  *  @brief This file contains USB specific code
4  *
5  *
6  *  Copyright 2008-2021 NXP
7  *
8  *  This software file (the File) is distributed by NXP
9  *  under the terms of the GNU General Public License Version 2, June 1991
10  *  (the License).  You may use, redistribute and/or modify the File in
11  *  accordance with the terms and conditions of the License, a copy of which
12  *  is available by writing to the Free Software Foundation, Inc.,
13  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  *  this warranty disclaimer.
20  *
21  */
22 
23 /********************************************************
24 Change log:
25     04/21/2009: initial version
26 ********************************************************/
27 
28 #include "mlan.h"
29 #ifdef STA_SUPPORT
30 #include "mlan_join.h"
31 #endif
32 #include "mlan_util.h"
33 #include "mlan_init.h"
34 #include "mlan_fw.h"
35 #include "mlan_main.h"
36 
37 /********************************************************
38 			Local Variables
39 ********************************************************/
40 #ifdef USB8801
41 static const struct _mlan_card_info mlan_card_info_usb8801 = {
42 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
43 	.v14_fw_api = 1,
44 	.v16_fw_api = 0,
45 	.supp_ps_handshake = 1,
46 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
47 };
48 #endif
49 #ifdef USB8897
50 static const struct _mlan_card_info mlan_card_info_usb8897 = {
51 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
52 	.v16_fw_api = 0,
53 	.supp_ps_handshake = 1,
54 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
55 };
56 #endif
57 
58 #ifdef USB8997
59 static const struct _mlan_card_info mlan_card_info_usb8997 = {
60 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
61 	.v16_fw_api = 1,
62 	.supp_ps_handshake = 1,
63 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
64 };
65 #endif
66 
67 #ifdef USB8978
68 static const struct _mlan_card_info mlan_card_info_usb8978 = {
69 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
70 	.v16_fw_api = 1,
71 	.supp_ps_handshake = 1,
72 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
73 };
74 #endif
75 
76 #ifdef USB9098
77 static const struct _mlan_card_info mlan_card_info_usb9098 = {
78 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
79 	.v16_fw_api = 1,
80 	.v17_fw_api = 1,
81 	.supp_ps_handshake = 1,
82 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
83 };
84 #endif
85 
86 #ifdef USB9097
87 static const struct _mlan_card_info mlan_card_info_usb9097 = {
88 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
89 	.v16_fw_api = 1,
90 	.v17_fw_api = 1,
91 	.supp_ps_handshake = 1,
92 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
93 };
94 #endif
95 
96 #ifdef USBNW62X
97 static const struct _mlan_card_info mlan_card_info_usbNW62X = {
98 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
99 	.v16_fw_api = 1,
100 	.v17_fw_api = 1,
101 	.supp_ps_handshake = 1,
102 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
103 };
104 #endif
105 
106 /********************************************************
107 			Global Variables
108 ********************************************************/
109 
110 /********************************************************
111 			Local Functions
112 ********************************************************/
113 #if defined(USB9098)
114 /**
115  *  @This function checks the chip revision id
116  *
117  *  @param pmadapter  A pointer to mlan_adapter structure
118  *  @param rev_id         A pointer to chip revision id
119  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
120  */
wlan_usb_check_revision(mlan_adapter * pmadapter,t_u32 * rev_id)121 static mlan_status wlan_usb_check_revision(mlan_adapter *pmadapter,
122 					   t_u32 *rev_id)
123 {
124 	mlan_status ret = MLAN_STATUS_SUCCESS;
125 	pmlan_callbacks pcb = &pmadapter->callbacks;
126 	mlan_buffer mbuf;
127 	t_u8 *tx_buff = MNULL;
128 	t_u8 *recv_buff = MNULL;
129 	t_u8 tx_size = 16;
130 	FWSyncPkt syncpkt;
131 
132 	ENTER();
133 	/* Allocate memory for transmit */
134 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_TX_BUF_SIZE,
135 			       MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&tx_buff);
136 	if ((ret != MLAN_STATUS_SUCCESS) || !tx_buff) {
137 		PRINTM(MERROR, "Could not allocate buffer for FW download\n");
138 		LEAVE();
139 		return MLAN_STATUS_FAILURE;
140 	}
141 	/* Allocate memory for receive */
142 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_RX_BUF_SIZE,
143 			       MLAN_MEM_DEF | MLAN_MEM_DMA, &recv_buff);
144 	if ((ret != MLAN_STATUS_SUCCESS) || !recv_buff) {
145 		PRINTM(MERROR,
146 		       "Could not allocate buffer for FW download response\n");
147 		goto cleanup;
148 	}
149 	memset(pmadapter, &syncpkt, 0, sizeof(FWSyncPkt));
150 	memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
151 	mbuf.pbuf = (t_u8 *)tx_buff;
152 	mbuf.data_len = tx_size;
153 	ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
154 					pmadapter->tx_cmd_ep,
155 					MLAN_USB_BULK_MSG_TIMEOUT);
156 	if (ret != MLAN_STATUS_SUCCESS) {
157 		PRINTM(MERROR, "check revision: write_data failed, ret %d\n",
158 		       ret);
159 		goto cleanup;
160 	}
161 	memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
162 	mbuf.pbuf = (t_u8 *)recv_buff;
163 	mbuf.data_len = 2048;
164 	ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
165 				       pmadapter->rx_cmd_ep,
166 				       MLAN_USB_BULK_MSG_TIMEOUT);
167 	if (ret != MLAN_STATUS_SUCCESS) {
168 		PRINTM(MERROR, "check revision: read_data failed, ret %d\n",
169 		       ret);
170 		goto cleanup;
171 	}
172 	memcpy_ext(pmadapter, &syncpkt, recv_buff, sizeof(syncpkt),
173 		   sizeof(syncpkt));
174 	syncpkt.chip_rev = wlan_le32_to_cpu(syncpkt.chip_rev);
175 	*rev_id = syncpkt.chip_rev & 0x000000ff;
176 	PRINTM(MERROR, "chip_revision_id = %d\n", syncpkt.chip_rev);
177 cleanup:
178 	if (recv_buff)
179 		pcb->moal_mfree(pmadapter->pmoal_handle, recv_buff);
180 	if (tx_buff)
181 		pcb->moal_mfree(pmadapter->pmoal_handle, tx_buff);
182 
183 	LEAVE();
184 	return ret;
185 }
186 #endif
187 
188 /**
189  *  @brief  This function downloads FW blocks to device
190  *
191  *  @param pmadapter	A pointer to mlan_adapter
192  *  @param pmfw			A pointer to firmware image
193  *
194  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
195  */
wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter,pmlan_fw_image pmfw)196 static mlan_status wlan_usb_prog_fw_w_helper(pmlan_adapter pmadapter,
197 					     pmlan_fw_image pmfw)
198 {
199 	mlan_status ret = MLAN_STATUS_SUCCESS;
200 	pmlan_callbacks pcb = &pmadapter->callbacks;
201 	t_u8 *firmware = pmfw->pfw_buf, *RecvBuff;
202 	t_u32 retries = MAX_FW_RETRY, DataLength;
203 	t_u32 FWSeqNum = 0, TotalBytes = 0, DnldCmd = 0;
204 	t_u8 *TxBuff = MNULL;
205 	FWData *fwdata = MNULL;
206 	FWSyncHeader SyncFWHeader;
207 	t_u8 check_winner = 1;
208 	t_u8 check_fw_status = MFALSE;
209 	t_u8 mic_retry = MAX_FW_RETRY;
210 #if defined(USB9098)
211 	t_u32 revision_id = 0;
212 #endif
213 
214 	ENTER();
215 
216 	if (!firmware && !pcb->moal_get_fw_data) {
217 		PRINTM(MMSG, "No firmware image found! Terminating download\n");
218 		ret = MLAN_STATUS_FAILURE;
219 		goto fw_exit;
220 	}
221 
222 	/* Allocate memory for transmit */
223 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_TX_BUF_SIZE,
224 			       MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&TxBuff);
225 	if ((ret != MLAN_STATUS_SUCCESS) || !TxBuff) {
226 		PRINTM(MERROR, "Could not allocate buffer for FW download\n");
227 		goto fw_exit;
228 	}
229 	fwdata = (FWData *)TxBuff;
230 
231 	/* Allocate memory for receive */
232 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, FW_DNLD_RX_BUF_SIZE,
233 			       MLAN_MEM_DEF | MLAN_MEM_DMA, &RecvBuff);
234 	if ((ret != MLAN_STATUS_SUCCESS) || !RecvBuff) {
235 		PRINTM(MERROR,
236 		       "Could not allocate buffer for FW download response\n");
237 		goto cleanup;
238 	}
239 
240 	if (!IS_USB_NEW_INIT(pmadapter->feature_control))
241 		check_winner = 0;
242 #if defined(USB9098)
243 	if (IS_USB9098(pmadapter->card_type)) {
244 		ret = wlan_usb_check_revision(pmadapter, &revision_id);
245 		if (ret != MLAN_STATUS_SUCCESS) {
246 			PRINTM(MERROR, "Failed to get USB chip revision ID\n");
247 			goto cleanup;
248 		}
249 		/* Skyhawk A0, need to check both CRC and MIC error */
250 		if (revision_id >= CHIP_9098_REV_A0)
251 			check_fw_status = MTRUE;
252 	}
253 #endif
254 #if defined(USB9097)
255 	if (IS_USB9097(pmadapter->card_type))
256 		check_fw_status = MTRUE;
257 #endif
258 #if defined(USBNW62X)
259 	if (IS_USBNW62X(pmadapter->card_type))
260 		check_fw_status = MTRUE;
261 #endif
262 
263 	do {
264 		/* Send pseudo data to check winner status first */
265 		if (check_winner) {
266 			memset(pmadapter, &fwdata->fw_header, 0,
267 			       sizeof(FWHeader));
268 			DataLength = 0;
269 		} else {
270 			/* Copy the header of the firmware data to get the
271 			 * length */
272 			if (firmware)
273 				memcpy_ext(pmadapter, &fwdata->fw_header,
274 					   &firmware[TotalBytes],
275 					   sizeof(FWHeader),
276 					   sizeof(fwdata->fw_header));
277 			else
278 				pcb->moal_get_fw_data(
279 					pmadapter->pmoal_handle, TotalBytes,
280 					sizeof(FWHeader),
281 					(t_u8 *)&fwdata->fw_header);
282 
283 			DataLength =
284 				wlan_le32_to_cpu(fwdata->fw_header.data_length);
285 			DnldCmd = wlan_le32_to_cpu(fwdata->fw_header.dnld_cmd);
286 			TotalBytes += sizeof(FWHeader);
287 
288 			/** CMD 7 don't have data_length field */
289 			if (DnldCmd == FW_CMD_4 || DnldCmd == FW_CMD_6 ||
290 			    DnldCmd == FW_CMD_7 || DnldCmd == FW_CMD_10)
291 				DataLength = 0;
292 
293 			if (DataLength >
294 			    (FW_DNLD_TX_BUF_SIZE - sizeof(FWHeader))) {
295 				PRINTM(MERROR,
296 				       "Invalid Data Legth read from FW\n");
297 				ret = MLAN_STATUS_FAILURE;
298 				break;
299 			}
300 
301 			/* Copy the firmware data */
302 			if (firmware)
303 				memcpy_ext(pmadapter, fwdata->data,
304 					   &firmware[TotalBytes], DataLength,
305 					   DataLength);
306 			else
307 				pcb->moal_get_fw_data(pmadapter->pmoal_handle,
308 						      TotalBytes, DataLength,
309 						      (t_u8 *)fwdata->data);
310 
311 			fwdata->seq_num = wlan_cpu_to_le32(FWSeqNum);
312 			TotalBytes += DataLength;
313 		}
314 		/* If the send/receive fails or CRC occurs then retry */
315 		while (retries) {
316 			mlan_buffer mbuf;
317 			int length = FW_DATA_XMIT_SIZE;
318 			retries--;
319 
320 			memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
321 			mbuf.pbuf = (t_u8 *)fwdata;
322 			mbuf.data_len = length;
323 			/* Send the firmware block */
324 			ret = pcb->moal_write_data_sync(
325 				pmadapter->pmoal_handle, &mbuf,
326 				pmadapter->tx_cmd_ep,
327 				MLAN_USB_BULK_MSG_TIMEOUT);
328 			if (ret != MLAN_STATUS_SUCCESS) {
329 				PRINTM(MERROR,
330 				       "fw_dnld: write_data failed, ret %d\n",
331 				       ret);
332 				continue;
333 			}
334 
335 			memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
336 			mbuf.pbuf = RecvBuff;
337 			mbuf.data_len = FW_DNLD_RX_BUF_SIZE;
338 
339 			/* Receive the firmware block response */
340 			ret = pcb->moal_read_data_sync(
341 				pmadapter->pmoal_handle, &mbuf,
342 				pmadapter->rx_cmd_ep,
343 				MLAN_USB_BULK_MSG_TIMEOUT);
344 			if (ret != MLAN_STATUS_SUCCESS) {
345 				PRINTM(MERROR,
346 				       "fw_dnld: read_data failed, ret %d\n",
347 				       ret);
348 				continue;
349 			}
350 			memcpy_ext(pmadapter, &SyncFWHeader, RecvBuff,
351 				   sizeof(FWSyncHeader), sizeof(SyncFWHeader));
352 			endian_convert_syncfwheader(&SyncFWHeader);
353 			/* Check the first firmware block response for highest
354 			 * bit set */
355 			if (check_winner) {
356 				if (SyncFWHeader.cmd & 0x80000000) {
357 					PRINTM(MMSG,
358 					       "USB is not the winner 0x%x, returning success\n",
359 					       SyncFWHeader.cmd);
360 					ret = MLAN_STATUS_SUCCESS;
361 					goto cleanup;
362 				}
363 				PRINTM(MINFO,
364 				       "USB is the winner, start to download FW\n");
365 				check_winner = 0;
366 				break;
367 			}
368 
369 			if (check_fw_status &&
370 			    (SyncFWHeader.status & MBIT(9))) {
371 				PRINTM(MERROR,
372 				       "FW received Blk with SE_BOOT error 0x%x\n",
373 				       SyncFWHeader.status);
374 				retries = 0;
375 				ret = MLAN_STATUS_FAILURE;
376 				break;
377 			}
378 
379 			/* Check the firmware block response for CRC errors */
380 			if (SyncFWHeader.cmd) {
381 				/* Check firmware block response for CRC and MIC
382 				 * errors */
383 				if (check_fw_status) {
384 					if (SyncFWHeader.status & MBIT(0)) {
385 						PRINTM(MERROR,
386 						       "FW received Blk with CRC error 0x%x offset=%d\n",
387 						       SyncFWHeader.status,
388 						       SyncFWHeader.offset);
389 						ret = MLAN_STATUS_FAILURE;
390 						continue;
391 					}
392 					if (SyncFWHeader.status &
393 					    (MBIT(6) | MBIT(7))) {
394 						PRINTM(MERROR,
395 						       "FW received Blk with MIC error 0x%x offset\n",
396 						       SyncFWHeader.status,
397 						       SyncFWHeader.offset);
398 						mic_retry--;
399 						FWSeqNum = 0;
400 						TotalBytes = 0;
401 						ret = MLAN_STATUS_FAILURE;
402 						continue;
403 					}
404 				} else {
405 					PRINTM(MERROR,
406 					       "FW received Blk with CRC error 0x%x\n",
407 					       SyncFWHeader.cmd);
408 					ret = MLAN_STATUS_FAILURE;
409 					continue;
410 				}
411 			}
412 
413 			retries = MAX_FW_RETRY;
414 			break;
415 		}
416 
417 		FWSeqNum++;
418 		PRINTM(MINFO, ".\n");
419 
420 	} while ((DnldCmd != FW_HAS_LAST_BLOCK) && retries && mic_retry);
421 
422 cleanup:
423 	PRINTM(MMSG, "fw_dnld: %d bytes downloaded\n", TotalBytes);
424 
425 	if (RecvBuff)
426 		pcb->moal_mfree(pmadapter->pmoal_handle, RecvBuff);
427 	if (TxBuff)
428 		pcb->moal_mfree(pmadapter->pmoal_handle, TxBuff);
429 	if (retries && mic_retry) {
430 		ret = MLAN_STATUS_SUCCESS;
431 	}
432 
433 fw_exit:
434 	LEAVE();
435 	return ret;
436 }
437 
438 /**
439  *  @brief Get number of packets when deaggregated
440  *
441  *  @param pmadapter		A pointer to mlan_adapter
442  *  @param pdata			A pointer to packet data
443  *  @param aggr_pkt_len		Aggregate packet length
444  *
445  *  @return			Number of packets
446  */
wlan_usb_deaggr_rx_num_pkts(pmlan_adapter pmadapter,t_u8 * pdata,int aggr_pkt_len)447 static int wlan_usb_deaggr_rx_num_pkts(pmlan_adapter pmadapter, t_u8 *pdata,
448 				       int aggr_pkt_len)
449 {
450 	int pkt_count = 0, pkt_len;
451 	RxPD *prx_pd;
452 
453 	ENTER();
454 	while (aggr_pkt_len >= (int)sizeof(RxPD)) {
455 		prx_pd = (RxPD *)pdata;
456 		pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
457 			  wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
458 		if (pkt_len == 0) /* blank RxPD can be at the end */
459 			break;
460 
461 		++pkt_count;
462 		if (aggr_pkt_len == pkt_len) /* last packet has no padding */
463 			break;
464 
465 		/* skip padding and goto next */
466 		if (pkt_len %
467 		    pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_align)
468 			pkt_len +=
469 				(pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl
470 					 .aggr_align -
471 				 (pkt_len % pmadapter->pcard_usb->usb_rx_deaggr
472 						    .aggr_ctrl.aggr_align));
473 		aggr_pkt_len -= pkt_len;
474 		pdata += pkt_len;
475 	}
476 	LEAVE();
477 	return pkt_count;
478 }
479 
usb_tx_aggr_pad_len(t_u32 len,usb_tx_aggr_params * pusb_tx_aggr)480 static inline t_u32 usb_tx_aggr_pad_len(t_u32 len,
481 					usb_tx_aggr_params *pusb_tx_aggr)
482 {
483 	return (len % pusb_tx_aggr->aggr_ctrl.aggr_align) ?
484 		       (len + (pusb_tx_aggr->aggr_ctrl.aggr_align -
485 			       (len % pusb_tx_aggr->aggr_ctrl.aggr_align))) :
486 		       len;
487 }
488 
489 /**
490  *  @brief Copy pmbuf to aggregation buffer
491  *
492  *  @param pmadapter	Pointer to mlan_adapter structure
493  *  @param pmbuf_aggr	Pointer to aggregation buffer
494  *  @param pmbuf		Pointer to buffer to copy
495  *  @param pusb_tx_aggr Pointer to usb_tx_aggr_params
496  *
497  *  @return   N/A
498  */
499 static inline t_void
wlan_usb_tx_copy_buf_to_aggr(pmlan_adapter pmadapter,pmlan_buffer pmbuf_aggr,pmlan_buffer pmbuf,usb_tx_aggr_params * pusb_tx_aggr)500 wlan_usb_tx_copy_buf_to_aggr(pmlan_adapter pmadapter, pmlan_buffer pmbuf_aggr,
501 			     pmlan_buffer pmbuf,
502 			     usb_tx_aggr_params *pusb_tx_aggr)
503 {
504 	ENTER();
505 	pmbuf_aggr->data_len =
506 		usb_tx_aggr_pad_len(pmbuf_aggr->data_len, pusb_tx_aggr);
507 	memcpy_ext(pmadapter,
508 		   pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
509 			   pmbuf_aggr->data_len,
510 		   pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len,
511 		   pmbuf->data_len);
512 	pmbuf_aggr->data_len += pmbuf->data_len;
513 	LEAVE();
514 }
515 
516 #define MLAN_TYPE_AGGR_DATA_V2 11
517 /**
518  *  @brief Copy pmbuf to aggregation buffer
519  *
520  *  @param pmadapter	Pointer to mlan_adapter structure
521  *  @param pmbuf_aggr	Pointer to aggregation buffer
522  *  @param pmbuf		Pointer to buffer to copy
523  *	@param last 		last packet flag
524  *  @param pusb_tx_aggr Pointer to usb_tx_aggr_params
525  *
526  *  @return   N/A
527  */
528 static inline t_void
wlan_usb_tx_copy_buf_to_aggr_v2(pmlan_adapter pmadapter,pmlan_buffer pmbuf_aggr,pmlan_buffer pmbuf,t_u8 last,usb_tx_aggr_params * pusb_tx_aggr)529 wlan_usb_tx_copy_buf_to_aggr_v2(pmlan_adapter pmadapter,
530 				pmlan_buffer pmbuf_aggr, pmlan_buffer pmbuf,
531 				t_u8 last, usb_tx_aggr_params *pusb_tx_aggr)
532 {
533 	t_u8 *payload;
534 	t_u16 offset;
535 
536 	ENTER();
537 	pmbuf_aggr->data_len =
538 		usb_tx_aggr_pad_len(pmbuf_aggr->data_len, pusb_tx_aggr);
539 	memcpy_ext(pmadapter,
540 		   pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
541 			   pmbuf_aggr->data_len,
542 		   pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len,
543 		   pmbuf->data_len);
544 	payload = pmbuf_aggr->pbuf + pmbuf_aggr->data_offset +
545 		  pmbuf_aggr->data_len;
546 	if (last) {
547 		offset = pmbuf->data_len;
548 		*(t_u16 *)&payload[2] =
549 			wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2 | 0x80);
550 	} else {
551 		offset = usb_tx_aggr_pad_len(pmbuf->data_len, pusb_tx_aggr);
552 		*(t_u16 *)&payload[2] =
553 			wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2);
554 	}
555 	*(t_u16 *)&payload[0] = wlan_cpu_to_le16(offset);
556 	pmbuf_aggr->data_len += pmbuf->data_len;
557 	PRINTM(MIF_D, "offset=%d len=%d\n", offset, pmbuf->data_len);
558 	LEAVE();
559 }
560 
561 /**
562  *  @brief Allocate Aggregation buffer and copy pending buffers to it.
563  *
564  *  @param pmadapter	Pointer to mlan_adapter structure
565  *  @param pusb_tx_aggr Pointer to usb_tx_aggr_params
566  *
567  *  @return			Aggregation buffer
568  */
569 static inline pmlan_buffer
wlan_usb_copy_buf_to_aggr(pmlan_adapter pmadapter,usb_tx_aggr_params * pusb_tx_aggr)570 wlan_usb_copy_buf_to_aggr(pmlan_adapter pmadapter,
571 			  usb_tx_aggr_params *pusb_tx_aggr)
572 {
573 	pmlan_buffer pmbuf_aggr = MNULL;
574 	t_u8 i, use_count;
575 	pmlan_buffer pmbuf_curr, pmbuf_next;
576 	pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pusb_tx_aggr->aggr_len,
577 					    0, MOAL_MALLOC_BUFFER);
578 	if (pmbuf_aggr) {
579 		pmbuf_curr = pusb_tx_aggr->pmbuf_aggr;
580 		pmbuf_aggr->bss_index = pmbuf_curr->bss_index;
581 		pmbuf_aggr->buf_type = pmbuf_curr->buf_type;
582 		pmbuf_aggr->priority = pmbuf_curr->priority;
583 		pmbuf_aggr->data_len = 0;
584 		PRINTM(MIF_D, "use_count=%d,aggr_len=%d\n",
585 		       pmbuf_curr->use_count, pusb_tx_aggr->aggr_len);
586 		use_count = pmbuf_curr->use_count;
587 		for (i = 0; i <= use_count; i++) {
588 			pmbuf_next = pmbuf_curr->pnext;
589 			if (pusb_tx_aggr->aggr_ctrl.aggr_mode ==
590 			    MLAN_USB_AGGR_MODE_LEN_V2) {
591 				if (i == use_count)
592 					wlan_usb_tx_copy_buf_to_aggr_v2(
593 						pmadapter, pmbuf_aggr,
594 						pmbuf_curr, MTRUE,
595 						pusb_tx_aggr);
596 				else
597 					wlan_usb_tx_copy_buf_to_aggr_v2(
598 						pmadapter, pmbuf_aggr,
599 						pmbuf_curr, MFALSE,
600 						pusb_tx_aggr);
601 			} else
602 				wlan_usb_tx_copy_buf_to_aggr(pmadapter,
603 							     pmbuf_aggr,
604 							     pmbuf_curr,
605 							     pusb_tx_aggr);
606 			pmbuf_curr = pmbuf_next;
607 		}
608 		DBG_HEXDUMP(MIF_D, "USB AggrTx",
609 			    pmbuf_aggr->pbuf + pmbuf_aggr->data_offset,
610 			    pmbuf_aggr->data_len);
611 	}
612 	return pmbuf_aggr;
613 }
614 
615 /**
616  *  @brief Link buffer into aggregate head buffer
617  *
618  *  @param pmbuf_aggr	Pointer to aggregation buffer
619  *  @param pmbuf		Pointer to buffer to add to the buffer list
620  *  @param pusb_tx_aggr Pointer to usb_tx_aggr_params
621  */
622 static inline t_void
wlan_usb_tx_link_buf_to_aggr(pmlan_buffer pmbuf_aggr,pmlan_buffer pmbuf,usb_tx_aggr_params * pusb_tx_aggr)623 wlan_usb_tx_link_buf_to_aggr(pmlan_buffer pmbuf_aggr, pmlan_buffer pmbuf,
624 			     usb_tx_aggr_params *pusb_tx_aggr)
625 {
626 	/* link new buf at end of list */
627 	pmbuf->pnext = pmbuf_aggr;
628 	pmbuf->pprev = pmbuf_aggr->pprev;
629 	pmbuf->pparent = pmbuf_aggr;
630 	pmbuf_aggr->pprev->pnext = pmbuf;
631 	pmbuf_aggr->pprev = pmbuf;
632 	pmbuf_aggr->use_count++;
633 	pusb_tx_aggr->aggr_len =
634 		usb_tx_aggr_pad_len(pusb_tx_aggr->aggr_len, pusb_tx_aggr);
635 	pusb_tx_aggr->aggr_len += pmbuf->data_len;
636 }
637 
638 /**
639  *  @brief Send aggregated buffer
640  *
641  *  @param pmadapter	Pointer to mlan_adapter structure
642  *  @param pusb_tx_aggr Pointer to usb_tx_aggr_params
643  */
wlan_usb_tx_send_aggr(pmlan_adapter pmadapter,usb_tx_aggr_params * pusb_tx_aggr)644 static inline t_void wlan_usb_tx_send_aggr(pmlan_adapter pmadapter,
645 					   usb_tx_aggr_params *pusb_tx_aggr)
646 {
647 	mlan_status ret;
648 	pmlan_buffer pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr;
649 	ENTER();
650 	if (!pusb_tx_aggr->pmbuf_aggr) {
651 		LEAVE();
652 		return;
653 	}
654 
655 	if (pusb_tx_aggr->pmbuf_aggr->use_count) {
656 		pmbuf_aggr = wlan_usb_copy_buf_to_aggr(pmadapter, pusb_tx_aggr);
657 		/* allocate new buffer for aggregation if not exist */
658 		if (!pmbuf_aggr) {
659 			PRINTM(MERROR,
660 			       "Error allocating [usb_tx] aggr mlan_buffer.\n");
661 			pmadapter->dbg.num_tx_host_to_card_failure +=
662 				pusb_tx_aggr->pmbuf_aggr->use_count;
663 			wlan_write_data_complete(pmadapter,
664 						 pusb_tx_aggr->pmbuf_aggr,
665 						 MLAN_STATUS_FAILURE);
666 			pusb_tx_aggr->pmbuf_aggr = MNULL;
667 			pusb_tx_aggr->aggr_len = 0;
668 			LEAVE();
669 			return;
670 		} else {
671 			wlan_write_data_complete(pmadapter,
672 						 pusb_tx_aggr->pmbuf_aggr,
673 						 MLAN_STATUS_SUCCESS);
674 			pusb_tx_aggr->pmbuf_aggr = MNULL;
675 			pusb_tx_aggr->aggr_len = 0;
676 		}
677 	} else if (pusb_tx_aggr->aggr_ctrl.aggr_mode ==
678 		   MLAN_USB_AGGR_MODE_LEN_V2) {
679 		t_u8 *payload = pmbuf_aggr->pbuf + pmbuf_aggr->data_offset;
680 		*(t_u16 *)&payload[0] = wlan_cpu_to_le16(pmbuf_aggr->data_len);
681 		*(t_u16 *)&payload[2] =
682 			wlan_cpu_to_le16(MLAN_TYPE_AGGR_DATA_V2 | 0x80);
683 		PRINTM(MIF_D, "USB Send single packet len=%d\n",
684 		       pmbuf_aggr->data_len);
685 		DBG_HEXDUMP(MIF_D, "USB Tx",
686 			    pmbuf_aggr->pbuf + pmbuf_aggr->data_offset,
687 			    pmbuf_aggr->data_len);
688 	}
689 
690 	if (pmbuf_aggr && pmbuf_aggr->data_len) {
691 		pmadapter->data_sent = MTRUE;
692 		ret = pmadapter->callbacks.moal_write_data_async(
693 			pmadapter->pmoal_handle, pmbuf_aggr,
694 			pusb_tx_aggr->port);
695 		switch (ret) {
696 		case MLAN_STATUS_PRESOURCE:
697 			PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
698 			break;
699 		case MLAN_STATUS_RESOURCE:
700 			/* Shouldn't reach here due to next condition. */
701 			/* TODO: (maybe) How to requeue the aggregate? */
702 			/* It may occur when the pending tx urbs reach the high
703 			 * mark */
704 			/* Thus, block further pkts for a bit */
705 			PRINTM(MERROR,
706 			       "Error: moal_write_data_async failed: 0x%X\n",
707 			       ret);
708 			pmadapter->dbg.num_tx_host_to_card_failure++;
709 			pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
710 			wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
711 			break;
712 		case MLAN_STATUS_FAILURE:
713 			pmadapter->data_sent = MFALSE;
714 			PRINTM(MERROR,
715 			       "Error: moal_write_data_async failed: 0x%X\n",
716 			       ret);
717 			pmadapter->dbg.num_tx_host_to_card_failure++;
718 			pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
719 			wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
720 			break;
721 		case MLAN_STATUS_PENDING:
722 			pmadapter->data_sent = MFALSE;
723 			break;
724 		case MLAN_STATUS_SUCCESS:
725 			wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
726 			break;
727 		default:
728 			break;
729 		}
730 
731 		/* aggr_buf now sent to bus, prevent others from using it */
732 		pusb_tx_aggr->pmbuf_aggr = MNULL;
733 		pusb_tx_aggr->aggr_len = 0;
734 	}
735 	LEAVE();
736 }
737 
738 /********************************************************
739 			Global Functions
740 ********************************************************/
741 
742 /**
743  *	@brief This function get pcie device from card type
744  *
745  *	@param pmadapter  A pointer to mlan_adapter structure
746  *	@return 		  MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
747  */
wlan_get_usb_device(pmlan_adapter pmadapter)748 mlan_status wlan_get_usb_device(pmlan_adapter pmadapter)
749 {
750 	mlan_status ret = MLAN_STATUS_SUCCESS;
751 	t_u16 card_type = pmadapter->card_type;
752 
753 	ENTER();
754 
755 	ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
756 					       sizeof(mlan_usb_card),
757 					       MLAN_MEM_DEF,
758 					       (t_u8 **)&pmadapter->pcard_usb);
759 	if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_usb) {
760 		PRINTM(MERROR, "Failed to allocate pcard_usb\n");
761 		LEAVE();
762 		return MLAN_STATUS_FAILURE;
763 	}
764 
765 	switch (card_type) {
766 #ifdef USB8801
767 	case CARD_TYPE_USB8801:
768 		pmadapter->pcard_info = &mlan_card_info_usb8801;
769 		break;
770 #endif
771 #ifdef USB8897
772 	case CARD_TYPE_USB8897:
773 		pmadapter->pcard_info = &mlan_card_info_usb8897;
774 		break;
775 #endif
776 #ifdef USB8997
777 	case CARD_TYPE_USB8997:
778 		pmadapter->pcard_info = &mlan_card_info_usb8997;
779 		break;
780 #endif
781 #ifdef USB8978
782 	case CARD_TYPE_USB8978:
783 		pmadapter->pcard_info = &mlan_card_info_usb8978;
784 		break;
785 #endif
786 #ifdef USB9098
787 	case CARD_TYPE_USB9098:
788 		pmadapter->pcard_info = &mlan_card_info_usb9098;
789 		break;
790 #endif
791 #ifdef USB9097
792 	case CARD_TYPE_USB9097:
793 		pmadapter->pcard_info = &mlan_card_info_usb9097;
794 		break;
795 #endif
796 #ifdef USBNW62X
797 	case CARD_TYPE_USBNW62X:
798 		pmadapter->pcard_info = &mlan_card_info_usbNW62X;
799 		break;
800 #endif
801 	default:
802 		PRINTM(MERROR, "can't get right USB card type \n");
803 		ret = MLAN_STATUS_FAILURE;
804 		break;
805 	}
806 
807 	LEAVE();
808 	return ret;
809 }
810 
811 /**
812  *  @brief  This function downloads firmware to card
813  *
814  *  @param pmadapter	A pointer to mlan_adapter
815  *  @param pmfw			A pointer to firmware image
816  *
817  *  @return		MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
818  */
wlan_usb_dnld_fw(pmlan_adapter pmadapter,pmlan_fw_image pmfw)819 static mlan_status wlan_usb_dnld_fw(pmlan_adapter pmadapter,
820 				    pmlan_fw_image pmfw)
821 {
822 	mlan_status ret = MLAN_STATUS_SUCCESS;
823 
824 	ENTER();
825 
826 	ret = wlan_usb_prog_fw_w_helper(pmadapter, pmfw);
827 	if (ret != MLAN_STATUS_SUCCESS) {
828 		LEAVE();
829 		return MLAN_STATUS_FAILURE;
830 	}
831 
832 	LEAVE();
833 	return ret;
834 }
835 
836 /**
837  *  @brief  This function deaggregates USB RX Data Packet from device
838  *
839  *  @param pmadapter	A pointer to mlan_adapter
840  *  @param pmbuf		A pointer to the received buffer
841  *
842  *  @return		MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
843  */
wlan_usb_deaggr_rx_pkt(pmlan_adapter pmadapter,pmlan_buffer pmbuf)844 mlan_status wlan_usb_deaggr_rx_pkt(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
845 {
846 	const t_u8 zero_rx_pd[sizeof(RxPD)] = {0};
847 	mlan_status ret = MLAN_STATUS_SUCCESS;
848 	t_u32 curr_pkt_len;
849 	RxPD *prx_pd;
850 	t_u8 *pdata;
851 	t_s32 aggr_len;
852 	pmlan_buffer pdeaggr_buf;
853 
854 	ENTER();
855 
856 	pdata = pmbuf->pbuf + pmbuf->data_offset;
857 	prx_pd = (RxPD *)pdata;
858 	curr_pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
859 		       wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
860 	/* if non-aggregate, just send through, don’t process here */
861 	aggr_len = pmbuf->data_len;
862 	if ((aggr_len == (t_s32)curr_pkt_len) ||
863 	    (wlan_usb_deaggr_rx_num_pkts(pmadapter, pdata, aggr_len) == 1) ||
864 	    (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable != MTRUE)) {
865 		ret = wlan_handle_rx_packet(pmadapter, pmbuf);
866 		LEAVE();
867 		return ret;
868 	}
869 
870 	while (aggr_len >= (t_s32)sizeof(RxPD)) {
871 		/* check for (all-zeroes) termination RxPD */
872 		if (!memcmp(pmadapter, pdata, zero_rx_pd, sizeof(RxPD))) {
873 			break;
874 		}
875 
876 		/* make new buffer and copy packet to it (including RxPD).
877 		 * Also, reserve headroom so that there must have space
878 		 * to change RxPD to TxPD for bridge packet in uAP mode */
879 		pdeaggr_buf = wlan_alloc_mlan_buffer(pmadapter, curr_pkt_len,
880 						     MLAN_RX_HEADER_LEN,
881 						     MOAL_ALLOC_MLAN_BUFFER);
882 		if (pdeaggr_buf == MNULL) {
883 			PRINTM(MERROR,
884 			       "Error allocating [usb_rx] deaggr mlan_buffer\n");
885 			ret = MLAN_STATUS_FAILURE;
886 			break;
887 		}
888 		pdeaggr_buf->bss_index = pmbuf->bss_index;
889 		pdeaggr_buf->buf_type = pmbuf->buf_type;
890 		pdeaggr_buf->data_len = curr_pkt_len;
891 		pdeaggr_buf->in_ts_sec = pmbuf->in_ts_sec;
892 		pdeaggr_buf->in_ts_usec = pmbuf->in_ts_usec;
893 		pdeaggr_buf->priority = pmbuf->priority;
894 		memcpy_ext(pmadapter,
895 			   pdeaggr_buf->pbuf + pdeaggr_buf->data_offset, pdata,
896 			   curr_pkt_len, pdeaggr_buf->data_len);
897 
898 		/* send new packet to processing */
899 		ret = wlan_handle_rx_packet(pmadapter, pdeaggr_buf);
900 		if (ret == MLAN_STATUS_FAILURE) {
901 			break;
902 		}
903 		/* last block has no padding bytes */
904 		if (aggr_len == (t_s32)curr_pkt_len) {
905 			break;
906 		}
907 
908 		/* round up to next block boundary */
909 		if (curr_pkt_len %
910 		    pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.aggr_align)
911 			curr_pkt_len += (pmadapter->pcard_usb->usb_rx_deaggr
912 						 .aggr_ctrl.aggr_align -
913 					 (curr_pkt_len %
914 					  pmadapter->pcard_usb->usb_rx_deaggr
915 						  .aggr_ctrl.aggr_align));
916 		/* point to next packet */
917 		aggr_len -= curr_pkt_len;
918 		pdata += curr_pkt_len;
919 		prx_pd = (RxPD *)pdata;
920 		curr_pkt_len = wlan_le16_to_cpu(prx_pd->rx_pkt_length) +
921 			       wlan_le16_to_cpu(prx_pd->rx_pkt_offset);
922 	}
923 
924 	/* free original pmbuf (since not sent for processing) */
925 	pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
926 						pmadapter->rx_data_ep, ret);
927 	LEAVE();
928 	return ret;
929 }
930 
931 /**
932  *  @brief This function restore tx_pause flag
933  *
934  *  @param pmadapter    A pointer to mlan_adapter structure
935  *  @param pusb_tx_aggr A pointer to usb_tx_aggr_params
936  *
937  *  @return             MTRUE/MFALSE
938  */
wlan_is_port_tx_paused(pmlan_adapter pmadapter,usb_tx_aggr_params * pusb_tx_aggr)939 static t_u8 wlan_is_port_tx_paused(pmlan_adapter pmadapter,
940 				   usb_tx_aggr_params *pusb_tx_aggr)
941 {
942 	mlan_private *pmpriv = MNULL;
943 	t_u8 i;
944 	t_u8 ret = MFALSE;
945 	for (i = 0; i < pmadapter->priv_num; i++) {
946 		pmpriv = pmadapter->priv[i];
947 		if (pmpriv && pmpriv->tx_pause &&
948 		    (pmpriv->port == pusb_tx_aggr->port)) {
949 			ret = MTRUE;
950 			break;
951 		}
952 	}
953 	return ret;
954 }
955 
956 /**
957  *  @brief This function handles the timeout of usb tx aggregation.
958  *  It will send the aggregate buffer being held.
959  *
960  *  @param function_context   A pointer to function_context
961  *  @return 	   N/A
962  */
wlan_usb_tx_aggr_timeout_func(t_void * function_context)963 t_void wlan_usb_tx_aggr_timeout_func(t_void *function_context)
964 {
965 	usb_tx_aggr_params *pusb_tx_aggr =
966 		(usb_tx_aggr_params *)function_context;
967 	pmlan_adapter pmadapter = (mlan_adapter *)pusb_tx_aggr->phandle;
968 	pmlan_callbacks pcb = &pmadapter->callbacks;
969 
970 	ENTER();
971 	pcb->moal_spin_lock(pmadapter->pmoal_handle, pusb_tx_aggr->paggr_lock);
972 	pusb_tx_aggr->aggr_hold_timer_is_set = MFALSE;
973 	if (pusb_tx_aggr->pmbuf_aggr && !pmadapter->data_sent &&
974 	    !wlan_is_port_tx_paused(pmadapter, pusb_tx_aggr))
975 		wlan_usb_tx_send_aggr(pmadapter, pusb_tx_aggr);
976 	pcb->moal_spin_unlock(pmadapter->pmoal_handle,
977 			      pusb_tx_aggr->paggr_lock);
978 	LEAVE();
979 }
980 
981 /**
982  *  @brief  This function aggregates USB TX Data Packet to send to device
983  *
984  *  @param pmadapter	A pointer to mlan_adapter
985  *  @param pmbuf		A pointer to the transmit buffer
986  *  @param tx_param 	A pointer to mlan_tx_param
987  *  @param pusb_tx_aggr A pointer to usb_tx_aggr_params
988  *
989  *  @return		MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE
990  */
991 /*
992  *  Non Scatter-Gather code creates a new large buffer where each incoming
993  *     buffer's data contents are copied to (aligned to USB boundaries).
994  *  The individual buffers are ALSO linked to the large buffer,
995  *    in order to handle complete AFTER the aggregate is sent.
996  *  pmbuf_aggr->data_len is used to keep track of bytes aggregated so far.
997  */
wlan_usb_host_to_card_aggr(pmlan_adapter pmadapter,pmlan_buffer pmbuf,mlan_tx_param * tx_param,usb_tx_aggr_params * pusb_tx_aggr)998 mlan_status wlan_usb_host_to_card_aggr(pmlan_adapter pmadapter,
999 				       pmlan_buffer pmbuf,
1000 				       mlan_tx_param *tx_param,
1001 				       usb_tx_aggr_params *pusb_tx_aggr)
1002 {
1003 	pmlan_callbacks pcb = &pmadapter->callbacks;
1004 	pmlan_buffer pmbuf_aggr;
1005 	mlan_status ret = MLAN_STATUS_PENDING;
1006 	t_u32 next_pkt_len = (tx_param) ? tx_param->next_pkt_len : 0;
1007 	t_u32 aggr_len_counter = 0;
1008 	/* indicators */
1009 	t_u8 f_precopy_cur_buf = 0;
1010 	t_u8 f_send_aggr_buf = 0;
1011 	t_u8 f_postcopy_cur_buf = 0;
1012 	t_u32 max_aggr_size = 0, max_aggr_num = 0;
1013 
1014 	ENTER();
1015 
1016 	pcb->moal_spin_lock(pmadapter->pmoal_handle, pusb_tx_aggr->paggr_lock);
1017 
1018 	/* stop timer while we process */
1019 	if (pusb_tx_aggr->aggr_hold_timer_is_set) {
1020 		pcb->moal_stop_timer(pmadapter->pmoal_handle,
1021 				     pusb_tx_aggr->paggr_hold_timer);
1022 		pusb_tx_aggr->aggr_hold_timer_is_set = MFALSE;
1023 	}
1024 
1025 	pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr;
1026 
1027 	if (pusb_tx_aggr->aggr_ctrl.aggr_tmo == MLAN_USB_TX_AGGR_TIMEOUT_DYN) {
1028 		if (!pmbuf_aggr) {
1029 			/* Start aggr from min timeout value in micro sec */
1030 			pusb_tx_aggr->hold_timeout_msec =
1031 				MLAN_USB_TX_MIN_AGGR_TIMEOUT;
1032 		} else {
1033 			/* Increase timeout in milisecond if pkts are
1034 			 * consecutive */
1035 			if (pusb_tx_aggr->hold_timeout_msec <
1036 			    MLAN_USB_TX_MAX_AGGR_TIMEOUT)
1037 				pusb_tx_aggr->hold_timeout_msec++;
1038 		}
1039 	} else {
1040 		if (pusb_tx_aggr->aggr_ctrl.aggr_tmo)
1041 			pusb_tx_aggr->hold_timeout_msec =
1042 				pusb_tx_aggr->aggr_ctrl.aggr_tmo / 1000;
1043 	}
1044 
1045 	max_aggr_size = max_aggr_num = pusb_tx_aggr->aggr_ctrl.aggr_max;
1046 	if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_NUM) {
1047 		max_aggr_size *= MAX(MLAN_USB_MAX_PKT_SIZE,
1048 				     pusb_tx_aggr->aggr_ctrl.aggr_align);
1049 	}
1050 	if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_LEN)
1051 		max_aggr_num /= pusb_tx_aggr->aggr_ctrl.aggr_align;
1052 	else if (pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_LEN_V2)
1053 		max_aggr_num = MLAN_USB_TX_AGGR_MAX_NUM;
1054 	if (!pmbuf_aggr) {
1055 		/* use this buf to start linked list, that's it */
1056 		pmbuf->pnext = pmbuf->pprev = pmbuf;
1057 		pmbuf_aggr = pmbuf;
1058 		pusb_tx_aggr->pmbuf_aggr = pmbuf_aggr;
1059 		pusb_tx_aggr->aggr_len = pmbuf->data_len;
1060 		pmbuf->flags |= MLAN_BUF_FLAG_USB_TX_AGGR;
1061 
1062 	} else {
1063 		/* DECIDE what to do */
1064 		aggr_len_counter = usb_tx_aggr_pad_len(pusb_tx_aggr->aggr_len,
1065 						       pusb_tx_aggr);
1066 
1067 		if ((aggr_len_counter + pmbuf->data_len) < max_aggr_size) {
1068 			f_precopy_cur_buf = 1; /* can fit current packet in aggr
1069 						*/
1070 			if (next_pkt_len) {
1071 				aggr_len_counter += usb_tx_aggr_pad_len(
1072 					pmbuf->data_len, pusb_tx_aggr);
1073 				if ((aggr_len_counter + next_pkt_len) >=
1074 				    max_aggr_size)
1075 					f_send_aggr_buf = 1; /* can't fit next
1076 								packet, send now
1077 							      */
1078 			}
1079 		} else {
1080 			/* can't fit current packet */
1081 			if (pusb_tx_aggr->aggr_len)
1082 				f_send_aggr_buf = 1; /* send aggr first */
1083 			f_postcopy_cur_buf = 1; /* then copy into new aggr_buf
1084 						 */
1085 		}
1086 	}
1087 
1088 	/* For zero timeout and zero next packet length send pkt now */
1089 	if (!pusb_tx_aggr->aggr_ctrl.aggr_tmo && !next_pkt_len)
1090 		f_send_aggr_buf = 1;
1091 
1092 	/* PERFORM ACTIONS as decided */
1093 	if (f_precopy_cur_buf) {
1094 		PRINTM(MIF_D, "%s: Precopy current buffer.\n", __FUNCTION__);
1095 		wlan_usb_tx_link_buf_to_aggr(pmbuf_aggr, pmbuf, pusb_tx_aggr);
1096 	}
1097 	if (pmbuf_aggr->use_count + 1 >= max_aggr_num)
1098 		f_send_aggr_buf = 1;
1099 
1100 	if (pmbuf->flags & MLAN_BUF_FLAG_NULL_PKT ||
1101 	    pmbuf->flags & MLAN_BUF_FLAG_TCP_ACK)
1102 		f_send_aggr_buf = 1;
1103 
1104 	if (f_send_aggr_buf) {
1105 		PRINTM(MIF_D, "%s: Send aggregate buffer.\n", __FUNCTION__);
1106 		wlan_usb_tx_send_aggr(pmadapter, pusb_tx_aggr);
1107 		pmbuf_aggr = pusb_tx_aggr->pmbuf_aggr; /* update ptr */
1108 	}
1109 
1110 	if (f_postcopy_cur_buf) {
1111 		PRINTM(MIF_D, "%s: Postcopy current buffer.\n", __FUNCTION__);
1112 		if (!pmbuf_aggr) { /* this is possible if just sent (above) */
1113 			/* use this buf to start linked list */
1114 			pmbuf->pnext = pmbuf->pprev = pmbuf;
1115 			pmbuf_aggr = pmbuf;
1116 			pusb_tx_aggr->pmbuf_aggr = pmbuf_aggr;
1117 			pusb_tx_aggr->aggr_len = pmbuf->data_len;
1118 			pmbuf->flags |= MLAN_BUF_FLAG_USB_TX_AGGR;
1119 		}
1120 	}
1121 	/* (re)start timer if there is something in the aggregation buffer */
1122 	if (pmbuf_aggr && pmbuf_aggr->data_len) {
1123 		if (pusb_tx_aggr->aggr_ctrl.aggr_tmo) {
1124 			pcb->moal_start_timer(pmadapter->pmoal_handle,
1125 					      pusb_tx_aggr->paggr_hold_timer,
1126 					      MFALSE,
1127 					      pusb_tx_aggr->hold_timeout_msec);
1128 			pusb_tx_aggr->aggr_hold_timer_is_set = MTRUE;
1129 		}
1130 	}
1131 
1132 	pcb->moal_spin_unlock(pmadapter->pmoal_handle,
1133 			      pusb_tx_aggr->paggr_lock);
1134 	LEAVE();
1135 	return ret;
1136 }
1137 
1138 /**
1139  *  @brief This function wakes up the card.
1140  *
1141  *  @param pmadapter		A pointer to mlan_adapter structure
1142  *  @param timeout          set timeout flag
1143  *
1144  *  @return			MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1145  */
wlan_pm_usb_wakeup_card(pmlan_adapter pmadapter,t_u8 timeout)1146 static mlan_status wlan_pm_usb_wakeup_card(pmlan_adapter pmadapter,
1147 					   t_u8 timeout)
1148 {
1149 	mlan_status ret = MLAN_STATUS_SUCCESS;
1150 	t_u32 age_ts_usec;
1151 
1152 	ENTER();
1153 	PRINTM(MEVENT, "Wakeup device...\n");
1154 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
1155 						  &pmadapter->pm_wakeup_in_secs,
1156 						  &age_ts_usec);
1157 
1158 	/* Simulation of HS_AWAKE event */
1159 	pmadapter->pm_wakeup_fw_try = MFALSE;
1160 	pmadapter->pm_wakeup_card_req = MFALSE;
1161 	/* TODO USB suspend/resume */
1162 	pmadapter->ps_state = PS_STATE_AWAKE;
1163 	LEAVE();
1164 	return ret;
1165 }
1166 
1167 /**
1168  *  @brief This function downloads data from driver to card.
1169  *
1170  *  Both commands and data packets are transferred to the card
1171  *  by this function. This function adds the PCIE specific header
1172  *  to the front of the buffer before transferring. The header
1173  *  contains the length of the packet and the type. The firmware
1174  *  handles the packets based upon this set type.
1175  *
1176  *  @param pmpriv    A pointer to pmlan_private structure
1177  *  @param type      data or command
1178  *  @param pmbuf     A pointer to mlan_buffer (pmbuf->data_len should include
1179  * PCIE header)
1180  *  @param tx_param  A pointer to mlan_tx_param (can be MNULL if type is
1181  * command)
1182  *
1183  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1184  */
wlan_usb_host_to_card(pmlan_private pmpriv,t_u8 type,mlan_buffer * pmbuf,mlan_tx_param * tx_param)1185 static mlan_status wlan_usb_host_to_card(pmlan_private pmpriv, t_u8 type,
1186 					 mlan_buffer *pmbuf,
1187 					 mlan_tx_param *tx_param)
1188 {
1189 	mlan_status ret = MLAN_STATUS_SUCCESS;
1190 	usb_tx_aggr_params *pusb_tx_aggr = MNULL;
1191 	pmlan_adapter pmadapter = pmpriv->adapter;
1192 
1193 	ENTER();
1194 
1195 	if (!pmbuf) {
1196 		PRINTM(MERROR, "Passed NULL pmbuf to %s\n", __FUNCTION__);
1197 		return MLAN_STATUS_FAILURE;
1198 	}
1199 	if (type == MLAN_TYPE_CMD
1200 #if (defined(USB9098) || defined(USB9097) || defined(USBNW62X))
1201 	    || type == MLAN_TYPE_VDLL
1202 #endif
1203 	) {
1204 		pmadapter->cmd_sent = MTRUE;
1205 		ret = pmadapter->callbacks.moal_write_data_async(
1206 			pmadapter->pmoal_handle, pmbuf, pmadapter->tx_cmd_ep);
1207 		if (ret == MLAN_STATUS_FAILURE)
1208 			pmadapter->cmd_sent = MFALSE;
1209 		LEAVE();
1210 		return ret;
1211 	}
1212 	pusb_tx_aggr = wlan_get_usb_tx_aggr_params(pmadapter, pmpriv->port);
1213 	if (pusb_tx_aggr) {
1214 		ret = wlan_usb_host_to_card_aggr(pmadapter, pmbuf, tx_param,
1215 						 pusb_tx_aggr);
1216 	} else {
1217 		pmadapter->data_sent = MTRUE;
1218 		ret = pmadapter->callbacks.moal_write_data_async(
1219 			pmadapter->pmoal_handle, pmbuf, pmpriv->port);
1220 		switch (ret) {
1221 		case MLAN_STATUS_PRESOURCE:
1222 			PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
1223 			break;
1224 		case MLAN_STATUS_RESOURCE:
1225 
1226 			break;
1227 		case MLAN_STATUS_FAILURE:
1228 			pmadapter->data_sent = MFALSE;
1229 			break;
1230 		case MLAN_STATUS_PENDING:
1231 			pmadapter->data_sent = MFALSE;
1232 			break;
1233 		case MLAN_STATUS_SUCCESS:
1234 			break;
1235 		default:
1236 			break;
1237 		}
1238 	}
1239 
1240 	LEAVE();
1241 	return ret;
1242 }
1243 
1244 /**
1245  *  @brief This function handle event/cmd complete
1246  *
1247  *  @param pmadapter A pointer to mlan_adapter structure
1248  *  @param pmbuf     A pointer to the mlan_buffer
1249  *  @return          N/A
1250  */
wlan_usb_cmdevt_complete(pmlan_adapter pmadapter,mlan_buffer * pmbuf,mlan_status status)1251 static mlan_status wlan_usb_cmdevt_complete(pmlan_adapter pmadapter,
1252 					    mlan_buffer *pmbuf,
1253 					    mlan_status status)
1254 {
1255 	ENTER();
1256 
1257 	pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
1258 						pmadapter->rx_cmd_ep, status);
1259 
1260 	LEAVE();
1261 	return MLAN_STATUS_SUCCESS;
1262 }
1263 
1264 /**
1265  *  @brief This function handle data complete
1266  *
1267  *  @param pmadapter A pointer to mlan_adapter structure
1268  *  @param pmbuf     A pointer to the mlan_buffer
1269  *  @return          N/A
1270  */
wlan_usb_data_complete(pmlan_adapter pmadapter,mlan_buffer * pmbuf,mlan_status status)1271 static mlan_status wlan_usb_data_complete(pmlan_adapter pmadapter,
1272 					  mlan_buffer *pmbuf,
1273 					  mlan_status status)
1274 {
1275 	ENTER();
1276 
1277 	pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
1278 						pmadapter->rx_data_ep, status);
1279 
1280 	LEAVE();
1281 	return MLAN_STATUS_SUCCESS;
1282 }
1283 
1284 /**
1285  *  @brief This function handle receive packet
1286  *
1287  *  @param pmadapter A pointer to mlan_adapter structure
1288  *  @param pmbuf     A pointer to the mlan_buffer
1289  *  @return
1290  */
wlan_usb_handle_rx_packet(mlan_adapter * pmadapter,pmlan_buffer pmbuf)1291 static mlan_status wlan_usb_handle_rx_packet(mlan_adapter *pmadapter,
1292 					     pmlan_buffer pmbuf)
1293 {
1294 	ENTER();
1295 
1296 	if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable == MTRUE)
1297 		return wlan_usb_deaggr_rx_pkt(pmadapter, pmbuf);
1298 	else
1299 		return wlan_handle_rx_packet(pmadapter, pmbuf);
1300 
1301 	LEAVE();
1302 }
1303 
1304 mlan_adapter_operations mlan_usb_ops = {
1305 	.dnld_fw = wlan_usb_dnld_fw,
1306 	.host_to_card = wlan_usb_host_to_card,
1307 	.wakeup_card = wlan_pm_usb_wakeup_card,
1308 	.event_complete = wlan_usb_cmdevt_complete,
1309 	.data_complete = wlan_usb_data_complete,
1310 	.cmdrsp_complete = wlan_usb_cmdevt_complete,
1311 	.handle_rx_packet = wlan_usb_handle_rx_packet,
1312 
1313 	.intf_header_len = USB_INTF_HEADER_LEN,
1314 };
1315