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