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