1 /** @file mlan_sdio.c
2 *
3 * @brief This file contains SDIO specific code
4 *
5 * Copyright (C) 2008-2017, Marvell International Ltd.
6 *
7 * This software file (the "File") is distributed by Marvell International
8 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9 * (the "License"). You may use, redistribute and/or modify this File in
10 * accordance with the terms and conditions of the License, a copy of which
11 * is available by writing to the Free Software Foundation, Inc.,
12 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 */
20
21 /********************************************************
22 Change log:
23 10/27/2008: initial version
24 ********************************************************/
25
26 #include "mlan.h"
27 #ifdef STA_SUPPORT
28 #include "mlan_join.h"
29 #endif
30 #include "mlan_util.h"
31 #include "mlan_fw.h"
32 #include "mlan_main.h"
33 #include "mlan_init.h"
34 #include "mlan_wmm.h"
35 #include "mlan_11n.h"
36 #include "mlan_sdio.h"
37
38 /********************************************************
39 Local Variables
40 ********************************************************/
41
42 /********************************************************
43 Global Variables
44 ********************************************************/
45
46 /********************************************************
47 Local Functions
48 ********************************************************/
49
50 /**
51 * @brief This function initialize the SDIO port
52 *
53 * @param pmadapter A pointer to mlan_adapter structure
54 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
55 */
56 static mlan_status
wlan_sdio_init_ioport(mlan_adapter * pmadapter)57 wlan_sdio_init_ioport(mlan_adapter *pmadapter)
58 {
59 t_u32 reg;
60 pmlan_callbacks pcb = &pmadapter->callbacks;
61
62 t_u8 host_int_rsr_reg = HOST_INT_RSR_REG;
63 t_u8 host_int_rsr_mask = HOST_INT_RSR_MASK;
64 t_u8 card_misc_cfg_reg = CARD_MISC_CFG_REG;
65 t_u8 card_config_2_1_reg = CARD_CONFIG_2_1_REG;
66 t_u8 cmd_config_0 = CMD_CONFIG_0;
67 t_u8 cmd_config_1 = CMD_CONFIG_1;
68
69 ENTER();
70 pmadapter->ioport = 0;
71
72 pmadapter->ioport = MEM_PORT;
73
74 PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n", pmadapter->ioport);
75
76 /* enable sdio cmd53 new mode */
77 if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
78 card_config_2_1_reg,
79 ®)) {
80 pcb->moal_write_reg(pmadapter->pmoal_handle,
81 card_config_2_1_reg, reg | CMD53_NEW_MODE);
82 } else {
83 LEAVE();
84 return MLAN_STATUS_FAILURE;
85 }
86
87 /* configure cmd port */
88 /* enable reading rx length from the register */
89 if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
90 cmd_config_0, ®)) {
91 pcb->moal_write_reg(pmadapter->pmoal_handle,
92 cmd_config_0, reg | CMD_PORT_RD_LEN_EN);
93 } else {
94 LEAVE();
95 return MLAN_STATUS_FAILURE;
96 }
97 /* enable Dnld/Upld ready auto reset for cmd port
98 * after cmd53 is completed */
99 if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
100 cmd_config_1, ®)) {
101 pcb->moal_write_reg(pmadapter->pmoal_handle,
102 cmd_config_1, reg | CMD_PORT_AUTO_EN);
103 } else {
104 LEAVE();
105 return MLAN_STATUS_FAILURE;
106 }
107 if ((pmadapter->init_para.int_mode == INT_MODE_GPIO) &&
108 (pmadapter->init_para.gpio_pin == GPIO_INT_NEW_MODE)) {
109 PRINTM(MMSG, "Enable GPIO-1 int mode\n");
110 pcb->moal_write_reg(pmadapter->pmoal_handle, SCRATCH_REG_32,
111 ENABLE_GPIO_1_INT_MODE);
112 }
113 /* Set Host interrupt reset to read to clear */
114 if (MLAN_STATUS_SUCCESS ==
115 pcb->moal_read_reg(pmadapter->pmoal_handle, host_int_rsr_reg,
116 ®)) {
117 pcb->moal_write_reg(pmadapter->pmoal_handle, host_int_rsr_reg,
118 reg | host_int_rsr_mask);
119 } else {
120 LEAVE();
121 return MLAN_STATUS_FAILURE;
122 }
123
124 /* Dnld/Upld ready set to auto reset */
125 if (MLAN_STATUS_SUCCESS ==
126 pcb->moal_read_reg(pmadapter->pmoal_handle, card_misc_cfg_reg,
127 ®)) {
128 pcb->moal_write_reg(pmadapter->pmoal_handle, card_misc_cfg_reg,
129 reg | AUTO_RE_ENABLE_INT);
130 } else {
131 LEAVE();
132 return MLAN_STATUS_FAILURE;
133 }
134 LEAVE();
135 return MLAN_STATUS_SUCCESS;
136 }
137
138 /**
139 * @brief This function sends data to the card.
140 *
141 * @param pmadapter A pointer to mlan_adapter structure
142 * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
143 * @param port Port
144 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
145 */
146 static mlan_status
wlan_write_data_sync(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u32 port)147 wlan_write_data_sync(mlan_adapter *pmadapter, mlan_buffer *pmbuf, t_u32 port)
148 {
149 t_u32 i = 0;
150 pmlan_callbacks pcb = &pmadapter->callbacks;
151 mlan_status ret = MLAN_STATUS_SUCCESS;
152
153 ENTER();
154
155 do {
156 ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf,
157 port, 0);
158 if (ret != MLAN_STATUS_SUCCESS) {
159 i++;
160 PRINTM(MERROR,
161 "host_to_card, write iomem (%d) failed: %d\n", i,
162 ret);
163 if (MLAN_STATUS_SUCCESS !=
164 pcb->moal_write_reg(pmadapter->pmoal_handle,
165 HOST_TO_CARD_EVENT_REG,
166 HOST_TERM_CMD53)) {
167 PRINTM(MERROR, "write CFG reg failed\n");
168 }
169 ret = MLAN_STATUS_FAILURE;
170 if (i > MAX_WRITE_IOMEM_RETRY) {
171 pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
172 goto exit;
173 }
174 }
175 } while (ret == MLAN_STATUS_FAILURE);
176 exit:
177 LEAVE();
178 return ret;
179 }
180
181 /**
182 * @brief This function gets available SDIO port for reading cmd/data
183 *
184 * @param pmadapter A pointer to mlan_adapter structure
185 * @param pport A pointer to port number
186 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
187 */
188 static mlan_status
wlan_get_rd_port(mlan_adapter * pmadapter,t_u8 * pport)189 wlan_get_rd_port(mlan_adapter *pmadapter, t_u8 *pport)
190 {
191 t_u32 rd_bitmap = pmadapter->mp_rd_bitmap;
192 t_u8 max_ports = MAX_PORT;
193
194 ENTER();
195
196 PRINTM(MIF_D, "wlan_get_rd_port: mp_rd_bitmap=0x%08x\n", rd_bitmap);
197
198 if (!(rd_bitmap & (DATA_PORT_MASK))) {
199 LEAVE();
200 return MLAN_STATUS_FAILURE;
201 }
202
203 if (pmadapter->mp_rd_bitmap & (1 << pmadapter->curr_rd_port)) {
204 pmadapter->mp_rd_bitmap &=
205 (t_u32)(~(1 << pmadapter->curr_rd_port));
206 *pport = pmadapter->curr_rd_port;
207
208 /* hw rx wraps round only after port (MAX_PORT-1) */
209 if (++pmadapter->curr_rd_port == max_ports)
210 /* port 0 is not reserved for cmd port */
211 pmadapter->curr_rd_port = 0;
212 } else {
213 LEAVE();
214 return MLAN_STATUS_FAILURE;
215 }
216
217 PRINTM(MIF_D, "port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
218 *pport, rd_bitmap, pmadapter->mp_rd_bitmap);
219 LEAVE();
220 return MLAN_STATUS_SUCCESS;
221 }
222
223 /**
224 * @brief This function gets available SDIO port for writing data
225 *
226 * @param pmadapter A pointer to mlan_adapter structure
227 * @param pport A pointer to port number
228 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
229 */
230 static mlan_status
wlan_get_wr_port_data(mlan_adapter * pmadapter,t_u8 * pport)231 wlan_get_wr_port_data(mlan_adapter *pmadapter, t_u8 *pport)
232 {
233 t_u32 wr_bitmap = pmadapter->mp_wr_bitmap;
234
235 ENTER();
236
237 PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n",
238 wr_bitmap);
239
240 if (!(wr_bitmap & pmadapter->mp_data_port_mask)) {
241 pmadapter->data_sent = MTRUE;
242 LEAVE();
243 return MLAN_STATUS_RESOURCE;
244 }
245
246 if (pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)) {
247 pmadapter->mp_wr_bitmap &=
248 (t_u32)(~(1 << pmadapter->curr_wr_port));
249 *pport = pmadapter->curr_wr_port;
250 if (++pmadapter->curr_wr_port == pmadapter->mp_end_port)
251 pmadapter->curr_wr_port = 0;
252 } else {
253 pmadapter->data_sent = MTRUE;
254 LEAVE();
255 return MLAN_STATUS_RESOURCE;
256 }
257
258 PRINTM(MIF_D, "port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
259 *pport, wr_bitmap, pmadapter->mp_wr_bitmap);
260 LEAVE();
261 return MLAN_STATUS_SUCCESS;
262 }
263
264 /**
265 * @brief This function polls the card status register.
266 *
267 * @param pmadapter A pointer to mlan_adapter structure
268 * @param bits the bit mask
269 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
270 */
271 static mlan_status
wlan_sdio_poll_card_status(mlan_adapter * pmadapter,t_u8 bits)272 wlan_sdio_poll_card_status(mlan_adapter *pmadapter, t_u8 bits)
273 {
274 pmlan_callbacks pcb = &pmadapter->callbacks;
275 t_u32 tries;
276 t_u32 cs = 0;
277
278 ENTER();
279
280 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
281 if (pcb->moal_read_reg(pmadapter->pmoal_handle,
282 CARD_TO_HOST_EVENT_REG,
283 &cs) != MLAN_STATUS_SUCCESS)
284 break;
285 else if ((cs & bits) == bits) {
286 LEAVE();
287 return MLAN_STATUS_SUCCESS;
288 }
289 wlan_udelay(pmadapter, 10);
290 }
291
292 PRINTM(MERROR,
293 "wlan_sdio_poll_card_status failed, tries = %d, cs = 0x%x\n",
294 tries, cs);
295 LEAVE();
296 return MLAN_STATUS_FAILURE;
297 }
298
299 /**
300 * @brief This function reads firmware status registers
301 *
302 * @param pmadapter A pointer to mlan_adapter structure
303 * @param dat A pointer to keep returned data
304 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
305 */
306 static mlan_status
wlan_sdio_read_fw_status(mlan_adapter * pmadapter,t_u16 * dat)307 wlan_sdio_read_fw_status(mlan_adapter *pmadapter, t_u16 *dat)
308 {
309 pmlan_callbacks pcb = &pmadapter->callbacks;
310 t_u32 fws0 = 0, fws1 = 0;
311
312 ENTER();
313 if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
314 CARD_FW_STATUS0_REG,
315 &fws0)) {
316 LEAVE();
317 return MLAN_STATUS_FAILURE;
318 }
319
320 if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
321 CARD_FW_STATUS1_REG,
322 &fws1)) {
323 LEAVE();
324 return MLAN_STATUS_FAILURE;
325 }
326
327 *dat = (t_u16)((fws1 << 8) | fws0);
328 LEAVE();
329 return MLAN_STATUS_SUCCESS;
330 }
331
332 /** @brief This function disables the host interrupts mask.
333 *
334 * @param pmadapter A pointer to mlan_adapter structure
335 * @param mask the interrupt mask
336 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
337 */
338 static mlan_status
wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter,t_u8 mask)339 wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
340 {
341 t_u32 host_int_mask = 0;
342 pmlan_callbacks pcb = &pmadapter->callbacks;
343
344 ENTER();
345
346 /* Read back the host_int_mask register */
347 if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
348 HOST_INT_MASK_REG,
349 &host_int_mask)) {
350 LEAVE();
351 return MLAN_STATUS_FAILURE;
352 }
353
354 /* Update with the mask and write back to the register */
355 host_int_mask &= ~mask;
356
357 if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
358 HOST_INT_MASK_REG,
359 host_int_mask)) {
360 PRINTM(MWARN, "Disable host interrupt failed\n");
361 LEAVE();
362 return MLAN_STATUS_FAILURE;
363 }
364
365 LEAVE();
366 return MLAN_STATUS_SUCCESS;
367 }
368
369 /**
370 * @brief This function enables the host interrupts mask
371 *
372 * @param pmadapter A pointer to mlan_adapter structure
373 * @param mask the interrupt mask
374 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
375 */
376 static mlan_status
wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter,t_u8 mask)377 wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter, t_u8 mask)
378 {
379 pmlan_callbacks pcb = &pmadapter->callbacks;
380
381 ENTER();
382
383 /* Simply write the mask to the register */
384 if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
385 HOST_INT_MASK_REG,
386 mask)) {
387 PRINTM(MWARN, "Enable host interrupt failed\n");
388 LEAVE();
389 return MLAN_STATUS_FAILURE;
390 }
391
392 LEAVE();
393 return MLAN_STATUS_SUCCESS;
394 }
395
396 /**
397 * @brief This function reads data from the card.
398 *
399 * @param pmadapter A pointer to mlan_adapter structure
400 * @param type A pointer to keep type as data or command
401 * @param nb A pointer to keep the data/cmd length returned in buffer
402 * @param pmbuf A pointer to the SDIO data/cmd buffer
403 * @param npayload the length of data/cmd buffer
404 * @param ioport the SDIO ioport
405 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
406 */
407 static mlan_status
wlan_sdio_card_to_host(mlan_adapter * pmadapter,t_u32 * type,t_u32 * nb,pmlan_buffer pmbuf,t_u32 npayload,t_u32 ioport)408 wlan_sdio_card_to_host(mlan_adapter *pmadapter,
409 t_u32 *type, t_u32 *nb, pmlan_buffer pmbuf,
410 t_u32 npayload, t_u32 ioport)
411 {
412 mlan_status ret = MLAN_STATUS_SUCCESS;
413 pmlan_callbacks pcb = &pmadapter->callbacks;
414 t_u32 i = 0;
415
416 ENTER();
417
418 if (!pmbuf) {
419 PRINTM(MWARN, "pmbuf is NULL!\n");
420 ret = MLAN_STATUS_FAILURE;
421 goto exit;
422 }
423 do {
424 ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf,
425 ioport, 0);
426
427 if (ret != MLAN_STATUS_SUCCESS) {
428 PRINTM(MERROR,
429 "wlan: cmd53 read failed: %d ioport=0x%x retry=%d\n",
430 ret, ioport, i);
431 i++;
432 if (MLAN_STATUS_SUCCESS !=
433 pcb->moal_write_reg(pmadapter->pmoal_handle,
434 HOST_TO_CARD_EVENT_REG,
435 HOST_TERM_CMD53)) {
436 PRINTM(MERROR, "Set Term cmd53 failed\n");
437 }
438 if (i > MAX_WRITE_IOMEM_RETRY) {
439 pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
440 ret = MLAN_STATUS_FAILURE;
441 goto exit;
442 }
443 }
444 } while (ret == MLAN_STATUS_FAILURE);
445 *nb = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
446 if (*nb > npayload) {
447 PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb,
448 npayload);
449 pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
450 ret = MLAN_STATUS_FAILURE;
451 goto exit;
452 }
453
454 DBG_HEXDUMP(MIF_D, "SDIO Blk Rd", pmbuf->pbuf + pmbuf->data_offset,
455 MIN(*nb, MAX_DATA_DUMP_LEN));
456
457 *type = wlan_le16_to_cpu(*(t_u16 *)
458 (pmbuf->pbuf + pmbuf->data_offset + 2));
459
460 exit:
461 LEAVE();
462 return ret;
463 }
464
465 /**
466 * @brief This function downloads FW blocks to device
467 *
468 * @param pmadapter A pointer to mlan_adapter
469 * @param firmware A pointer to firmware image
470 * @param firmwarelen firmware len
471 *
472 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
473 */
474 static mlan_status
wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter,t_u8 * fw,t_u32 fw_len)475 wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter, t_u8 *fw, t_u32 fw_len)
476 {
477 mlan_status ret = MLAN_STATUS_SUCCESS;
478 pmlan_callbacks pcb = &pmadapter->callbacks;
479 t_u8 *firmware = fw;
480 t_u32 firmwarelen = fw_len;
481 t_u32 offset = 0;
482 t_u32 base0, base1;
483 t_void *tmpfwbuf = MNULL;
484 t_u32 tmpfwbufsz;
485 t_u8 *fwbuf;
486 mlan_buffer mbuf;
487 t_u16 len = 0;
488 t_u32 txlen = 0, tx_blocks = 0, tries = 0;
489 t_u32 i = 0;
490 t_u32 read_base_0_reg = READ_BASE_0_REG;
491 t_u32 read_base_1_reg = READ_BASE_1_REG;
492
493 ENTER();
494
495 if (!firmware && !pcb->moal_get_fw_data) {
496 PRINTM(MMSG, "No firmware image found! Terminating download\n");
497 LEAVE();
498 return MLAN_STATUS_FAILURE;
499 }
500
501 PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen);
502
503 tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT);
504 ret = pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz,
505 MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&tmpfwbuf);
506 if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
507 PRINTM(MERROR,
508 "Unable to allocate buffer for firmware. Terminating download\n");
509 ret = MLAN_STATUS_FAILURE;
510 goto done;
511 }
512 memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz);
513 /* Ensure 8-byte aligned firmware buffer */
514 fwbuf = (t_u8 *)ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);
515
516 /* Perform firmware data transfer */
517 do {
518 /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
519 ret = wlan_sdio_poll_card_status(pmadapter,
520 CARD_IO_READY |
521 DN_LD_CARD_RDY);
522 if (ret != MLAN_STATUS_SUCCESS) {
523 PRINTM(MFATAL,
524 "WLAN: FW download with helper poll status timeout @ %d\n",
525 offset);
526 goto done;
527 }
528
529 /* More data? */
530 if (firmwarelen && offset >= firmwarelen)
531 break;
532
533 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
534 ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
535 read_base_0_reg, &base0);
536 if (ret != MLAN_STATUS_SUCCESS) {
537 PRINTM(MERROR, "Dev BASE0 register read failed:"
538 " base0=0x%04X(%d). Terminating download\n",
539 base0, base0);
540 goto done;
541 }
542 ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
543 read_base_1_reg, &base1);
544 if (ret != MLAN_STATUS_SUCCESS) {
545 PRINTM(MERROR, "Dev BASE1 register read failed:"
546 " base1=0x%04X(%d). Terminating download\n",
547 base1, base1);
548 goto done;
549 }
550 len = (t_u16)(((base1 & 0xff) << 8) | (base0 & 0xff));
551
552 if (len)
553 break;
554 wlan_udelay(pmadapter, 10);
555 }
556
557 if (!len)
558 break;
559 else if (len > WLAN_UPLD_SIZE) {
560 PRINTM(MFATAL,
561 "WLAN: FW download failure @ %d, invalid length %d\n",
562 offset, len);
563 ret = MLAN_STATUS_FAILURE;
564 goto done;
565 }
566
567 /* Ignore CRC check before download the 1st packet */
568 if (offset == 0 && (len & MBIT(0))) {
569 len &= ~MBIT(0);
570 }
571
572 txlen = len;
573
574 if (len & MBIT(0)) {
575 i++;
576 if (i > MAX_WRITE_IOMEM_RETRY) {
577 PRINTM(MFATAL,
578 "WLAN: FW download failure @ %d, over max retry count\n",
579 offset);
580 ret = MLAN_STATUS_FAILURE;
581 goto done;
582 }
583 PRINTM(MERROR,
584 "WLAN: FW CRC error indicated by the helper:"
585 " len = 0x%04X, txlen = %d\n", len, txlen);
586 len &= ~MBIT(0);
587
588 PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i,
589 offset);
590 DBG_HEXDUMP(MERROR, "WLAN: FW block:", fwbuf, len);
591
592 /* Setting this to 0 to resend from same offset */
593 txlen = 0;
594 } else {
595 i = 0;
596
597 /* Set blocksize to transfer - checking
598 * for last block */
599 if (firmwarelen && firmwarelen - offset < txlen)
600 txlen = firmwarelen - offset;
601 PRINTM(MINFO, ".");
602
603 tx_blocks =
604 (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD -
605 1) / MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
606
607 /* Copy payload to buffer */
608 if (firmware)
609 memmove(pmadapter, fwbuf, &firmware[offset],
610 txlen);
611 else
612 pcb->moal_get_fw_data(pmadapter->pmoal_handle,
613 offset, txlen, fwbuf);
614 }
615
616 /* Send data */
617 memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
618 mbuf.pbuf = (t_u8 *)fwbuf;
619 mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
620
621 ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
622 pmadapter->ioport, 0);
623 if (ret != MLAN_STATUS_SUCCESS) {
624 PRINTM(MERROR,
625 "WLAN: FW download, write iomem (%d) failed @ %d\n",
626 i, offset);
627 if (pcb->
628 moal_write_reg(pmadapter->pmoal_handle,
629 HOST_TO_CARD_EVENT_REG,
630 HOST_TERM_CMD53) !=
631 MLAN_STATUS_SUCCESS) {
632 PRINTM(MERROR, "write CFG reg failed\n");
633 }
634 ret = MLAN_STATUS_FAILURE;
635 goto done;
636 }
637
638 offset += txlen;
639 } while (MTRUE);
640
641 PRINTM(MMSG, "Wlan: FW download over, firmwarelen=%d downloaded %d\n",
642 firmwarelen, offset);
643
644 ret = MLAN_STATUS_SUCCESS;
645 done:
646 if (tmpfwbuf)
647 pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tmpfwbuf);
648
649 LEAVE();
650 return ret;
651 }
652
653 /**
654 * @brief This function disables the host interrupts.
655 *
656 * @param pmadapter A pointer to mlan_adapter structure
657 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
658 */
659 static mlan_status
wlan_disable_host_int(pmlan_adapter pmadapter)660 wlan_disable_host_int(pmlan_adapter pmadapter)
661 {
662 mlan_status ret;
663
664 ENTER();
665 ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
666 LEAVE();
667 return ret;
668 }
669
670 /**
671 * @brief This function decodes the rx packet &
672 * calls corresponding handlers according to the packet type
673 *
674 * @param pmadapter A pointer to mlan_adapter structure
675 * @param pmbuf A pointer to the SDIO data/cmd buffer
676 * @param upld_typ Type of rx packet
677 * @param lock_flag flag for spin_lock.
678 * @return MLAN_STATUS_SUCCESS
679 */
680 static mlan_status
wlan_decode_rx_packet(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u32 upld_typ,t_u8 lock_flag)681 wlan_decode_rx_packet(mlan_adapter *pmadapter, mlan_buffer *pmbuf,
682 t_u32 upld_typ, t_u8 lock_flag)
683 {
684 t_u8 *cmd_buf;
685 t_u32 event;
686
687 ENTER();
688
689 switch (upld_typ) {
690 case MLAN_TYPE_SPA_DATA:
691 PRINTM(MINFO, "--- Rx: SPA Data packet ---\n");
692 pmbuf->data_len = pmadapter->upld_len;
693 if (pmadapter->rx_work_flag) {
694 pmbuf->buf_type = MLAN_BUF_TYPE_SPA_DATA;
695 if (lock_flag)
696 pmadapter->callbacks.moal_spin_lock(pmadapter->
697 pmoal_handle,
698 pmadapter->
699 rx_data_queue.
700 plock);
701 util_enqueue_list_tail(pmadapter->pmoal_handle,
702 &pmadapter->rx_data_queue,
703 (pmlan_linked_list)pmbuf, MNULL,
704 MNULL);
705 pmadapter->rx_pkts_queued++;
706 if (lock_flag)
707 pmadapter->callbacks.
708 moal_spin_unlock(pmadapter->
709 pmoal_handle,
710 pmadapter->
711 rx_data_queue.plock);
712 } else {
713 wlan_decode_spa_buffer(pmadapter,
714 pmbuf->pbuf + pmbuf->data_offset,
715 pmbuf->data_len);
716 wlan_free_mlan_buffer(pmadapter, pmbuf);
717 }
718 pmadapter->data_received = MTRUE;
719 break;
720 case MLAN_TYPE_DATA:
721 PRINTM(MINFO, "--- Rx: Data packet ---\n");
722 pmbuf->data_len = (pmadapter->upld_len - INTF_HEADER_LEN);
723 pmbuf->data_offset += INTF_HEADER_LEN;
724 if (pmadapter->rx_work_flag) {
725 if (lock_flag)
726 pmadapter->callbacks.moal_spin_lock(pmadapter->
727 pmoal_handle,
728 pmadapter->
729 rx_data_queue.
730 plock);
731 util_enqueue_list_tail(pmadapter->pmoal_handle,
732 &pmadapter->rx_data_queue,
733 (pmlan_linked_list)pmbuf, MNULL,
734 MNULL);
735 pmadapter->rx_pkts_queued++;
736 if (lock_flag)
737 pmadapter->callbacks.
738 moal_spin_unlock(pmadapter->
739 pmoal_handle,
740 pmadapter->
741 rx_data_queue.plock);
742 } else {
743 wlan_handle_rx_packet(pmadapter, pmbuf);
744 }
745 pmadapter->data_received = MTRUE;
746 break;
747
748 case MLAN_TYPE_CMD:
749 PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
750 /* take care of curr_cmd = NULL case */
751 if (!pmadapter->curr_cmd) {
752 cmd_buf = pmadapter->upld_buf;
753 if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
754 wlan_process_sleep_confirm_resp(pmadapter,
755 pmbuf->pbuf +
756 pmbuf->
757 data_offset +
758 INTF_HEADER_LEN,
759 pmadapter->
760 upld_len -
761 INTF_HEADER_LEN);
762 }
763 pmadapter->upld_len -= INTF_HEADER_LEN;
764 memcpy(pmadapter, cmd_buf,
765 pmbuf->pbuf + pmbuf->data_offset +
766 INTF_HEADER_LEN, MIN(MRVDRV_SIZE_OF_CMD_BUFFER,
767 pmadapter->upld_len -
768 INTF_HEADER_LEN));
769 wlan_free_mlan_buffer(pmadapter, pmbuf);
770 } else {
771 pmadapter->cmd_resp_received = MTRUE;
772 pmadapter->upld_len -= INTF_HEADER_LEN;
773 pmbuf->data_len = pmadapter->upld_len;
774 pmbuf->data_offset += INTF_HEADER_LEN;
775 pmadapter->curr_cmd->respbuf = pmbuf;
776 if (pmadapter->upld_len >= MRVDRV_SIZE_OF_CMD_BUFFER) {
777 PRINTM(MMSG, "Invalid CmdResp len=%d\n",
778 pmadapter->upld_len);
779 DBG_HEXDUMP(MERROR, "Invalid CmdResp",
780 pmbuf->pbuf + pmbuf->data_offset,
781 MAX_DATA_DUMP_LEN);
782 }
783 }
784 break;
785
786 case MLAN_TYPE_EVENT:
787 PRINTM(MINFO, "--- Rx: Event ---\n");
788 event = *(t_u32 *)&pmbuf->pbuf[pmbuf->data_offset +
789 INTF_HEADER_LEN];
790 pmadapter->event_cause = wlan_le32_to_cpu(event);
791 if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
792 ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) <
793 MAX_EVENT_SIZE)) {
794 memcpy(pmadapter, pmadapter->event_body,
795 pmbuf->pbuf + pmbuf->data_offset +
796 MLAN_EVENT_HEADER_LEN,
797 pmadapter->upld_len - MLAN_EVENT_HEADER_LEN);
798 }
799
800 /* event cause has been saved to adapter->event_cause */
801 pmadapter->event_received = MTRUE;
802 pmbuf->data_len = pmadapter->upld_len;
803 pmadapter->pmlan_buffer_event = pmbuf;
804
805 /* remove SDIO header */
806 pmbuf->data_offset += INTF_HEADER_LEN;
807 pmbuf->data_len -= INTF_HEADER_LEN;
808 break;
809
810 default:
811 PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
812 wlan_free_mlan_buffer(pmadapter, pmbuf);
813 break;
814 }
815
816 LEAVE();
817 return MLAN_STATUS_SUCCESS;
818 }
819
820 #ifdef SDIO_MULTI_PORT_RX_AGGR
821 /**
822 * @brief This function receives single packet
823 *
824 * @param pmadapter A pointer to mlan_adapter structure
825 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
826 */
827 mlan_status
wlan_receive_single_packet(mlan_adapter * pmadapter)828 wlan_receive_single_packet(mlan_adapter *pmadapter)
829 {
830 mlan_buffer *pmbuf;
831 t_u8 port;
832 t_u16 rx_len;
833 t_u32 pkt_type = 0;
834 mlan_status ret = MLAN_STATUS_SUCCESS;
835
836 ENTER();
837 pmbuf = pmadapter->mpa_rx.mbuf_arr[0];
838 port = pmadapter->mpa_rx.start_port;
839 rx_len = pmadapter->mpa_rx.len_arr[0];
840 if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type,
841 (t_u32 *)&pmadapter->
842 upld_len, pmbuf,
843 rx_len,
844 pmadapter->ioport +
845 port)) {
846 ret = MLAN_STATUS_FAILURE;
847 goto done;
848 }
849 if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
850 PRINTM(MERROR,
851 "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
852 pkt_type, pmbuf->data_len);
853 pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
854 ret = MLAN_STATUS_FAILURE;
855 goto done;
856 }
857 pmadapter->mpa_rx_count[0]++;
858 wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
859 done:
860 if (ret != MLAN_STATUS_SUCCESS)
861 wlan_free_mlan_buffer(pmadapter, pmbuf);
862 MP_RX_AGGR_BUF_RESET(pmadapter);
863 LEAVE();
864 return ret;
865 }
866
867 /**
868 * @brief This function receives data from the card in aggregate mode.
869 *
870 * @param pmadapter A pointer to mlan_adapter structure
871 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
872 */
873 mlan_status
wlan_receive_mp_aggr_buf(mlan_adapter * pmadapter)874 wlan_receive_mp_aggr_buf(mlan_adapter *pmadapter)
875 {
876 mlan_status ret = MLAN_STATUS_SUCCESS;
877 pmlan_callbacks pcb = &pmadapter->callbacks;
878 mlan_buffer mbuf_aggr;
879 mlan_buffer *mbuf_deaggr;
880 t_u32 pind = 0;
881 t_u32 pkt_len, pkt_type = 0;
882 t_u8 *curr_ptr;
883 t_u32 cmd53_port = 0;
884 t_u32 i = 0;
885 t_u32 port_count = 0;
886
887 /* do aggr RX now */
888 PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
889 pmadapter->mpa_rx.pkt_cnt);
890
891 memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
892
893 if (pmadapter->mpa_rx.pkt_cnt == 1)
894 return wlan_receive_single_packet(pmadapter);
895 if (!pmadapter->mpa_rx.buf) {
896 mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len;
897 mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
898 mbuf_aggr.use_count = 0;
899 for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
900 pmadapter->mpa_rx.mbuf_arr[pind]->data_len =
901 pmadapter->mpa_rx.len_arr[pind];
902 wlan_link_buf_to_aggr(&mbuf_aggr,
903 pmadapter->mpa_rx.mbuf_arr[pind]);
904 }
905 } else {
906 mbuf_aggr.pbuf = (t_u8 *)pmadapter->mpa_rx.buf;
907 mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len;
908 }
909
910 port_count = bitcount(pmadapter->mpa_rx.ports) - 1;
911 /* port_count = pmadapter->mpa_rx.pkt_cnt - 1; */
912 cmd53_port =
913 (pmadapter->ioport | SDIO_MPA_ADDR_BASE | (port_count << 8))
914 + pmadapter->mpa_rx.start_port;
915 do {
916 ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle,
917 &mbuf_aggr, cmd53_port, 0);
918 if (ret != MLAN_STATUS_SUCCESS) {
919 PRINTM(MERROR,
920 "wlan: sdio mp cmd53 read failed: %d ioport=0x%x retry=%d\n",
921 ret, cmd53_port, i);
922 i++;
923 if (MLAN_STATUS_SUCCESS !=
924 pcb->moal_write_reg(pmadapter->pmoal_handle,
925 HOST_TO_CARD_EVENT_REG,
926 HOST_TERM_CMD53)) {
927 PRINTM(MERROR, "Set Term cmd53 failed\n");
928 }
929 if (i > MAX_WRITE_IOMEM_RETRY) {
930 ret = MLAN_STATUS_FAILURE;
931 goto done;
932 }
933 }
934 } while (ret == MLAN_STATUS_FAILURE);
935 if (pmadapter->rx_work_flag)
936 pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
937 pmadapter->rx_data_queue.
938 plock);
939 if (!pmadapter->mpa_rx.buf && pmadapter->mpa_rx.pkt_cnt > 1) {
940 for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
941 mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind];
942 pkt_len =
943 wlan_le16_to_cpu(*(t_u16 *)
944 (mbuf_deaggr->pbuf +
945 mbuf_deaggr->data_offset));
946 pkt_type =
947 wlan_le16_to_cpu(*(t_u16 *)
948 (mbuf_deaggr->pbuf +
949 mbuf_deaggr->data_offset +
950 2));
951 pmadapter->upld_len = pkt_len;
952 wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type,
953 MFALSE);
954 }
955 } else {
956 DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd", pmadapter->mpa_rx.buf,
957 MIN(pmadapter->mpa_rx.buf_len, MAX_DATA_DUMP_LEN));
958
959 curr_ptr = pmadapter->mpa_rx.buf;
960
961 for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
962
963 /* get curr PKT len & type */
964 pkt_len = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[0]);
965 pkt_type = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[2]);
966
967 PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n",
968 pind, pkt_len, pkt_type);
969
970 /* copy pkt to deaggr buf */
971 mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind];
972 if ((pkt_type == MLAN_TYPE_DATA
973 || pkt_type == MLAN_TYPE_SPA_DATA) &&
974 (pkt_len <= pmadapter->mpa_rx.len_arr[pind])) {
975 memcpy(pmadapter,
976 mbuf_deaggr->pbuf +
977 mbuf_deaggr->data_offset, curr_ptr,
978 pkt_len);
979 pmadapter->upld_len = pkt_len;
980 /* Process de-aggr packet */
981 wlan_decode_rx_packet(pmadapter, mbuf_deaggr,
982 pkt_type, MFALSE);
983 } else {
984 PRINTM(MERROR,
985 "Wrong aggr packet: type=%d, len=%d, max_len=%d\n",
986 pkt_type, pkt_len,
987 pmadapter->mpa_rx.len_arr[pind]);
988 wlan_free_mlan_buffer(pmadapter, mbuf_deaggr);
989 }
990 curr_ptr += pmadapter->mpa_rx.len_arr[pind];
991 }
992 }
993 if (pmadapter->rx_work_flag)
994 pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
995 pmadapter->rx_data_queue.
996 plock);
997 pmadapter->mpa_rx_count[pmadapter->mpa_rx.pkt_cnt - 1]++;
998 MP_RX_AGGR_BUF_RESET(pmadapter);
999 done:
1000 return ret;
1001 }
1002
1003 /**
1004 * @brief This function receives data from the card in aggregate mode.
1005 *
1006 * @param pmadapter A pointer to mlan_adapter structure
1007 * @param pmbuf A pointer to the SDIO data/cmd buffer
1008 * @param port Current port on which packet needs to be rxed
1009 * @param rx_len Length of received packet
1010 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1011 */
1012 static mlan_status
wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u8 port,t_u16 rx_len)1013 wlan_sdio_card_to_host_mp_aggr(mlan_adapter *pmadapter, mlan_buffer
1014 *pmbuf, t_u8 port, t_u16 rx_len)
1015 {
1016 mlan_status ret = MLAN_STATUS_SUCCESS;
1017 t_s32 f_do_rx_aggr = 0;
1018 t_s32 f_do_rx_cur = 0;
1019 t_s32 f_aggr_cur = 0;
1020 t_s32 f_post_aggr_cur = 0;
1021 t_u32 pind = 0;
1022 t_u32 pkt_type = 0;
1023
1024 ENTER();
1025
1026 if (!pmadapter->mpa_rx.enabled) {
1027 PRINTM(MINFO,
1028 "card_2_host_mp_aggr: rx aggregation disabled !\n");
1029
1030 f_do_rx_cur = 1;
1031 goto rx_curr_single;
1032 }
1033
1034 if (pmadapter->mp_rd_bitmap & DATA_PORT_MASK) {
1035 /* Some more data RX pending */
1036 PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
1037
1038 if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1039 if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
1040 f_aggr_cur = 1;
1041 } else {
1042 /* No room in Aggr buf, do rx aggr now */
1043 f_do_rx_aggr = 1;
1044 f_post_aggr_cur = 1;
1045 }
1046 } else {
1047 /* Rx aggr not in progress */
1048 f_aggr_cur = 1;
1049 }
1050
1051 } else {
1052 /* No more data RX pending */
1053 PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
1054
1055 if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1056 f_do_rx_aggr = 1;
1057 if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
1058 f_aggr_cur = 1;
1059 } else {
1060 /* No room in Aggr buf, do rx aggr now */
1061 f_do_rx_cur = 1;
1062 }
1063 } else {
1064 f_do_rx_cur = 1;
1065 }
1066
1067 }
1068
1069 if (f_aggr_cur) {
1070 PRINTM(MINFO, "Current packet aggregation.\n");
1071 /* Curr pkt can be aggregated */
1072 MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
1073
1074 if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
1075 MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)
1076 ) {
1077 PRINTM(MINFO,
1078 "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
1079 /* No more pkts allowed in Aggr buf, rx it */
1080 f_do_rx_aggr = 1;
1081 }
1082 }
1083
1084 if (f_do_rx_aggr) {
1085 /* do aggr RX now */
1086 if (MLAN_STATUS_SUCCESS != wlan_receive_mp_aggr_buf(pmadapter)) {
1087 ret = MLAN_STATUS_FAILURE;
1088 goto done;
1089 }
1090 }
1091 rx_curr_single:
1092 if (f_do_rx_cur) {
1093 PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port,
1094 rx_len);
1095
1096 if (MLAN_STATUS_SUCCESS !=
1097 wlan_sdio_card_to_host(pmadapter, &pkt_type,
1098 (t_u32 *)&pmadapter->upld_len, pmbuf,
1099 rx_len, pmadapter->ioport + port)) {
1100 ret = MLAN_STATUS_FAILURE;
1101 goto done;
1102 }
1103 if (pkt_type != MLAN_TYPE_DATA
1104 && pkt_type != MLAN_TYPE_SPA_DATA) {
1105 PRINTM(MERROR,
1106 "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
1107 pkt_type, pmbuf->data_len);
1108 pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
1109 ret = MLAN_STATUS_FAILURE;
1110 goto done;
1111 }
1112
1113 pmadapter->mpa_rx_count[0]++;
1114
1115 wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
1116 }
1117 if (f_post_aggr_cur) {
1118 PRINTM(MINFO, "Current packet aggregation.\n");
1119 /* Curr pkt can be aggregated */
1120 MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
1121 }
1122 done:
1123 if (ret == MLAN_STATUS_FAILURE) {
1124 if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1125 /* MP-A transfer failed - cleanup */
1126 for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) {
1127 wlan_free_mlan_buffer(pmadapter,
1128 pmadapter->mpa_rx.
1129 mbuf_arr[pind]);
1130 }
1131 MP_RX_AGGR_BUF_RESET(pmadapter);
1132 }
1133
1134 if (f_do_rx_cur) {
1135 /* Single Transfer pending */
1136 /* Free curr buff also */
1137 wlan_free_mlan_buffer(pmadapter, pmbuf);
1138 }
1139 }
1140
1141 LEAVE();
1142 return ret;
1143
1144 }
1145 #endif
1146
1147 #ifdef SDIO_MULTI_PORT_TX_AGGR
1148 /**
1149 * @brief This function sends aggr buf
1150 *
1151 * @param pmadapter A pointer to mlan_adapter structure
1152 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1153 */
1154 mlan_status
wlan_send_mp_aggr_buf(mlan_adapter * pmadapter)1155 wlan_send_mp_aggr_buf(mlan_adapter *pmadapter)
1156 {
1157 mlan_status ret = MLAN_STATUS_SUCCESS;
1158 t_u32 cmd53_port = 0;
1159 t_u32 port_count = 0;
1160 mlan_buffer mbuf_aggr;
1161 t_u8 i = 0;
1162 t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1163
1164 ENTER();
1165
1166 if (!pmadapter->mpa_tx.pkt_cnt) {
1167 LEAVE();
1168 return ret;
1169 }
1170 PRINTM(MINFO, "host_2_card_mp_aggr: Send aggregation buffer."
1171 "%d %d\n", pmadapter->mpa_tx.start_port,
1172 pmadapter->mpa_tx.ports);
1173
1174 memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
1175
1176 if (!pmadapter->mpa_tx.buf && pmadapter->mpa_tx.pkt_cnt > 1) {
1177 mbuf_aggr.data_len = pmadapter->mpa_tx.buf_len;
1178 mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
1179 mbuf_aggr.use_count = 0;
1180 for (i = 0; i < pmadapter->mpa_tx.pkt_cnt; i++)
1181 wlan_link_buf_to_aggr(&mbuf_aggr,
1182 pmadapter->mpa_tx.mbuf_arr[i]);
1183 } else {
1184 mbuf_aggr.pbuf = (t_u8 *)pmadapter->mpa_tx.buf;
1185 mbuf_aggr.data_len = pmadapter->mpa_tx.buf_len;
1186 }
1187
1188 port_count = bitcount(pmadapter->mpa_tx.ports) - 1;
1189 cmd53_port =
1190 (pmadapter->ioport | SDIO_MPA_ADDR_BASE | (port_count << 8))
1191 + pmadapter->mpa_tx.start_port;
1192
1193 if (pmadapter->mpa_tx.pkt_cnt == 1)
1194 cmd53_port = pmadapter->ioport + pmadapter->mpa_tx.start_port;
1195 /** only one packet */
1196 if (!pmadapter->mpa_tx.buf && pmadapter->mpa_tx.pkt_cnt == 1)
1197 ret = wlan_write_data_sync(pmadapter,
1198 pmadapter->mpa_tx.mbuf_arr[0],
1199 cmd53_port);
1200 else
1201 ret = wlan_write_data_sync(pmadapter, &mbuf_aggr, cmd53_port);
1202 if (!pmadapter->mpa_tx.buf) {
1203 /** free mlan buffer */
1204 for (i = 0; i < pmadapter->mpa_tx.pkt_cnt; i++) {
1205 wlan_write_data_complete(pmadapter,
1206 pmadapter->mpa_tx.mbuf_arr[i],
1207 MLAN_STATUS_SUCCESS);
1208 }
1209 }
1210 if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port))
1211 && (pmadapter->mpa_tx.pkt_cnt < mp_aggr_pkt_limit))
1212 pmadapter->mpa_sent_no_ports++;
1213 pmadapter->mpa_tx_count[pmadapter->mpa_tx.pkt_cnt - 1]++;
1214 pmadapter->last_mp_wr_bitmap[pmadapter->last_mp_index] =
1215 pmadapter->mp_wr_bitmap;
1216 pmadapter->last_mp_wr_ports[pmadapter->last_mp_index] = cmd53_port;
1217 pmadapter->last_mp_wr_len[pmadapter->last_mp_index] =
1218 pmadapter->mpa_tx.buf_len;
1219 pmadapter->last_curr_wr_port[pmadapter->last_mp_index] =
1220 pmadapter->curr_wr_port;
1221 memcpy(pmadapter,
1222 (t_u8 *)&pmadapter->last_mp_wr_info[pmadapter->last_mp_index *
1223 mp_aggr_pkt_limit],
1224 (t_u8 *)pmadapter->mpa_tx.mp_wr_info,
1225 sizeof(pmadapter->mpa_tx.mp_wr_info)
1226 );
1227 pmadapter->last_mp_index++;
1228 if (pmadapter->last_mp_index >= SDIO_MP_DBG_NUM)
1229 pmadapter->last_mp_index = 0;
1230 MP_TX_AGGR_BUF_RESET(pmadapter);
1231 LEAVE();
1232 return ret;
1233 }
1234
1235 /**
1236 * @brief This function sends data to the card in SDIO aggregated mode.
1237 *
1238 * @param pmadapter A pointer to mlan_adapter structure
1239 * @param mbuf A pointer to the SDIO data/cmd buffer
1240 * @param port current port for aggregation
1241 * @param next_pkt_len Length of next packet used for multiport aggregation
1242 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1243 */
1244 static mlan_status
wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter,mlan_buffer * mbuf,t_u8 port,t_u32 next_pkt_len)1245 wlan_host_to_card_mp_aggr(mlan_adapter *pmadapter, mlan_buffer *mbuf, t_u8 port,
1246 t_u32 next_pkt_len)
1247 {
1248 mlan_status ret = MLAN_STATUS_SUCCESS;
1249 t_s32 f_send_aggr_buf = 0;
1250 t_s32 f_send_cur_buf = 0;
1251 t_s32 f_precopy_cur_buf = 0;
1252 t_s32 f_postcopy_cur_buf = 0;
1253 t_u8 aggr_sg = 0;
1254 t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
1255
1256 ENTER();
1257
1258 PRINTM(MIF_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
1259 next_pkt_len, port);
1260
1261 if (!pmadapter->mpa_tx.enabled) {
1262 PRINTM(MINFO,
1263 "host_2_card_mp_aggr: tx aggregation disabled !\n");
1264 f_send_cur_buf = 1;
1265 goto tx_curr_single;
1266 }
1267
1268 if (next_pkt_len) {
1269 /* More pkt in TX queue */
1270 PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
1271
1272 if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
1273 if (MP_TX_AGGR_BUF_HAS_ROOM
1274 (pmadapter, mbuf, mbuf->data_len)) {
1275 f_precopy_cur_buf = 1;
1276
1277 if (!
1278 (pmadapter->
1279 mp_wr_bitmap & (1 << pmadapter->
1280 curr_wr_port)) ||
1281 !MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
1282 mbuf->data_len +
1283 next_pkt_len)) {
1284 f_send_aggr_buf = 1;
1285 }
1286 } else {
1287 /* No room in Aggr buf, send it */
1288 f_send_aggr_buf = 1;
1289
1290 if (!
1291 (pmadapter->
1292 mp_wr_bitmap & (1 << pmadapter->
1293 curr_wr_port))) {
1294 f_send_cur_buf = 1;
1295 } else {
1296 f_postcopy_cur_buf = 1;
1297 }
1298 }
1299 } else {
1300 if (MP_TX_AGGR_BUF_HAS_ROOM
1301 (pmadapter, mbuf, mbuf->data_len) &&
1302 (pmadapter->
1303 mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
1304 f_precopy_cur_buf = 1;
1305 else
1306 f_send_cur_buf = 1;
1307 }
1308 } else {
1309 /* Last pkt in TX queue */
1310 PRINTM(MINFO,
1311 "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
1312
1313 if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
1314 /* some packs in Aggr buf already */
1315 f_send_aggr_buf = 1;
1316
1317 if (MP_TX_AGGR_BUF_HAS_ROOM
1318 (pmadapter, mbuf, mbuf->data_len)) {
1319 f_precopy_cur_buf = 1;
1320 } else {
1321 /* No room in Aggr buf, send it */
1322 f_send_cur_buf = 1;
1323 }
1324 } else {
1325 f_send_cur_buf = 1;
1326 }
1327 pmadapter->mpa_sent_last_pkt++;
1328 }
1329
1330 if (f_precopy_cur_buf) {
1331 PRINTM(MINFO, "host_2_card_mp_aggr: Precopy current buffer\n");
1332 if (pmadapter->mpa_buf)
1333 memcpy(pmadapter, pmadapter->mpa_buf +
1334 (pmadapter->last_mp_index * mp_aggr_pkt_limit +
1335 pmadapter->mpa_tx.pkt_cnt) *
1336 MLAN_SDIO_BLOCK_SIZE,
1337 mbuf->pbuf + mbuf->data_offset,
1338 MLAN_SDIO_BLOCK_SIZE);
1339 if (!pmadapter->mpa_tx.buf) {
1340 MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
1341 aggr_sg = MTRUE;
1342 } else {
1343
1344 MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
1345 }
1346 if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
1347 MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter)
1348 ) {
1349 PRINTM(MIF_D,
1350 "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
1351 /* No more pkts allowed in Aggr buf, send it */
1352 f_send_aggr_buf = 1;
1353 }
1354 }
1355
1356 if (f_send_aggr_buf)
1357 ret = wlan_send_mp_aggr_buf(pmadapter);
1358
1359 tx_curr_single:
1360 if (f_send_cur_buf) {
1361 PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n",
1362 port);
1363 ret = wlan_write_data_sync(pmadapter, mbuf,
1364 pmadapter->ioport + port);
1365 if (!(pmadapter->mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
1366 pmadapter->mpa_sent_no_ports++;
1367 pmadapter->last_mp_wr_bitmap[pmadapter->last_mp_index] =
1368 pmadapter->mp_wr_bitmap;
1369 pmadapter->last_mp_wr_ports[pmadapter->last_mp_index] =
1370 pmadapter->ioport + port;
1371 pmadapter->last_mp_wr_len[pmadapter->last_mp_index] =
1372 mbuf->data_len;
1373 memset(pmadapter,
1374 (t_u8 *)&pmadapter->last_mp_wr_info[pmadapter->
1375 last_mp_index *
1376 mp_aggr_pkt_limit],
1377 0, sizeof(t_u16) * mp_aggr_pkt_limit);
1378 pmadapter->last_mp_wr_info[pmadapter->last_mp_index *
1379 mp_aggr_pkt_limit] =
1380 *(t_u16 *)(mbuf->pbuf + mbuf->data_offset);
1381 pmadapter->last_curr_wr_port[pmadapter->last_mp_index] =
1382 pmadapter->curr_wr_port;
1383 if (pmadapter->mpa_buf)
1384 memcpy(pmadapter,
1385 pmadapter->mpa_buf +
1386 (pmadapter->last_mp_index * mp_aggr_pkt_limit *
1387 MLAN_SDIO_BLOCK_SIZE),
1388 mbuf->pbuf + mbuf->data_offset,
1389 MLAN_SDIO_BLOCK_SIZE);
1390 pmadapter->last_mp_index++;
1391 if (pmadapter->last_mp_index >= SDIO_MP_DBG_NUM)
1392 pmadapter->last_mp_index = 0;
1393 pmadapter->mpa_tx_count[0]++;
1394 }
1395 if (f_postcopy_cur_buf) {
1396 PRINTM(MINFO, "host_2_card_mp_aggr: Postcopy current buffer\n");
1397 if (pmadapter->mpa_buf)
1398 memcpy(pmadapter, pmadapter->mpa_buf +
1399 (pmadapter->last_mp_index * mp_aggr_pkt_limit +
1400 pmadapter->mpa_tx.pkt_cnt) *
1401 MLAN_SDIO_BLOCK_SIZE,
1402 mbuf->pbuf + mbuf->data_offset,
1403 MLAN_SDIO_BLOCK_SIZE);
1404 if (!pmadapter->mpa_tx.buf) {
1405 MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
1406 aggr_sg = MTRUE;
1407 } else {
1408 MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
1409 }
1410 }
1411 /* Always return PENDING in SG mode */
1412 if (aggr_sg)
1413 ret = MLAN_STATUS_PENDING;
1414
1415 LEAVE();
1416 return ret;
1417 }
1418 #endif /* SDIO_MULTI_PORT_TX_AGGR */
1419
1420 /********************************************************
1421 Global functions
1422 ********************************************************/
1423
1424 /**
1425 * @brief This function checks if the interface is ready to download
1426 * or not while other download interface is present
1427 *
1428 * @param pmadapter A pointer to mlan_adapter structure
1429 * @param val Winner status (0: winner)
1430 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1431 *
1432 */
1433 mlan_status
wlan_check_winner_status(mlan_adapter * pmadapter,t_u32 * val)1434 wlan_check_winner_status(mlan_adapter *pmadapter, t_u32 *val)
1435 {
1436 t_u32 winner = 0;
1437 pmlan_callbacks pcb;
1438 t_u8 card_fw_status0_reg = CARD_FW_STATUS0_REG;
1439
1440 ENTER();
1441
1442 pcb = &pmadapter->callbacks;
1443
1444 if (MLAN_STATUS_SUCCESS !=
1445 pcb->moal_read_reg(pmadapter->pmoal_handle, card_fw_status0_reg,
1446 &winner)) {
1447 LEAVE();
1448 return MLAN_STATUS_FAILURE;
1449 }
1450 *val = winner;
1451
1452 LEAVE();
1453 return MLAN_STATUS_SUCCESS;
1454 }
1455
1456 /**
1457 * @brief This function checks if the firmware is ready to accept
1458 * command or not.
1459 *
1460 * @param pmadapter A pointer to mlan_adapter structure
1461 * @param pollnum Maximum polling number
1462 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1463 */
1464 mlan_status
wlan_check_fw_status(mlan_adapter * pmadapter,t_u32 pollnum)1465 wlan_check_fw_status(mlan_adapter *pmadapter, t_u32 pollnum)
1466 {
1467 mlan_status ret = MLAN_STATUS_SUCCESS;
1468 t_u16 firmwarestat = 0;
1469 t_u32 tries;
1470
1471 ENTER();
1472
1473 /* Wait for firmware initialization event */
1474 for (tries = 0; tries < pollnum; tries++) {
1475 ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat);
1476 if (MLAN_STATUS_SUCCESS != ret)
1477 continue;
1478 if (firmwarestat == FIRMWARE_READY) {
1479 ret = MLAN_STATUS_SUCCESS;
1480 break;
1481 } else {
1482 wlan_mdelay(pmadapter, 100);
1483 ret = MLAN_STATUS_FAILURE;
1484 }
1485 }
1486
1487 if (ret != MLAN_STATUS_SUCCESS) {
1488 if (pollnum > 1)
1489 PRINTM(MERROR,
1490 "Fail to poll firmware status: firmwarestat=0x%x\n",
1491 firmwarestat);
1492 goto done;
1493 }
1494
1495 done:
1496 LEAVE();
1497 return ret;
1498 }
1499
1500 /**
1501 * @brief This function downloads firmware to card
1502 *
1503 * @param pmadapter A pointer to mlan_adapter
1504 * @param pmfw A pointer to firmware image
1505 *
1506 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1507 */
1508 mlan_status
wlan_dnld_fw(IN pmlan_adapter pmadapter,IN pmlan_fw_image pmfw)1509 wlan_dnld_fw(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw)
1510 {
1511 mlan_status ret = MLAN_STATUS_SUCCESS;
1512
1513 ENTER();
1514
1515 /* Download the firmware image via helper */
1516 ret = wlan_prog_fw_w_helper(pmadapter, pmfw->pfw_buf, pmfw->fw_len);
1517 if (ret != MLAN_STATUS_SUCCESS) {
1518 LEAVE();
1519 return MLAN_STATUS_FAILURE;
1520 }
1521
1522 LEAVE();
1523 return ret;
1524 }
1525
1526 /**
1527 * @brief This function probes the driver
1528 *
1529 * @param pmadapter A pointer to mlan_adapter structure
1530 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1531 */
1532 mlan_status
wlan_sdio_probe(pmlan_adapter pmadapter)1533 wlan_sdio_probe(pmlan_adapter pmadapter)
1534 {
1535 mlan_status ret = MLAN_STATUS_SUCCESS;
1536 t_u32 sdio_ireg = 0;
1537 pmlan_callbacks pcb = &pmadapter->callbacks;
1538
1539 ENTER();
1540 /*
1541 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
1542 * from the bootloader. If we don't do this we get a interrupt
1543 * as soon as we register the irq.
1544 */
1545 pcb->moal_read_reg(pmadapter->pmoal_handle,
1546 HOST_INT_STATUS_REG, &sdio_ireg);
1547
1548 /* Disable host interrupt mask register for SDIO */
1549 ret = wlan_disable_host_int(pmadapter);
1550 if (ret != MLAN_STATUS_SUCCESS) {
1551 LEAVE();
1552 return MLAN_STATUS_FAILURE;
1553 }
1554 /* Get SDIO ioport */
1555 ret = wlan_sdio_init_ioport(pmadapter);
1556 LEAVE();
1557 return ret;
1558 }
1559
1560 /**
1561 * @brief This function gets interrupt status.
1562 *
1563 * @param pmadapter A pointer to mlan_adapter structure
1564 * @return MLAN_STATUS_SUCCESS
1565 */
1566 mlan_status
wlan_interrupt(pmlan_adapter pmadapter)1567 wlan_interrupt(pmlan_adapter pmadapter)
1568 {
1569 pmlan_callbacks pcb = &pmadapter->callbacks;
1570 mlan_buffer mbuf;
1571 t_u32 sdio_ireg = 0;
1572
1573 t_u8 max_mp_regs = MAX_MP_REGS;
1574 t_u8 host_int_status_reg = HOST_INT_STATUS_REG;
1575
1576 ENTER();
1577
1578 memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
1579 mbuf.pbuf = pmadapter->mp_regs;
1580 mbuf.data_len = max_mp_regs;
1581
1582 if (MLAN_STATUS_SUCCESS !=
1583 pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf,
1584 REG_PORT | MLAN_SDIO_BYTE_MODE_MASK, 0)) {
1585 PRINTM(MERROR, "moal_read_data_sync: read registers failed\n");
1586 pmadapter->dbg.num_int_read_failure++;
1587 goto done;
1588 }
1589
1590 DBG_HEXDUMP(MIF_D, "SDIO MP Registers", pmadapter->mp_regs,
1591 max_mp_regs);
1592 sdio_ireg = pmadapter->mp_regs[host_int_status_reg];
1593 pmadapter->dbg.last_int_status = pmadapter->sdio_ireg | sdio_ireg;
1594 if (sdio_ireg) {
1595 /*
1596 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
1597 * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
1598 * UP_LD_CMD_PORT_HOST_INT_STATUS
1599 * Clear the interrupt status register
1600 */
1601 PRINTM(MINTR, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
1602 pmadapter->num_of_irq++;
1603 pcb->moal_spin_lock(pmadapter->pmoal_handle,
1604 pmadapter->pint_lock);
1605 pmadapter->sdio_ireg |= sdio_ireg;
1606 pcb->moal_spin_unlock(pmadapter->pmoal_handle,
1607 pmadapter->pint_lock);
1608
1609 if (!pmadapter->pps_uapsd_mode &&
1610 pmadapter->ps_state == PS_STATE_SLEEP) {
1611 pmadapter->pm_wakeup_fw_try = MFALSE;
1612 pmadapter->ps_state = PS_STATE_AWAKE;
1613 pmadapter->pm_wakeup_card_req = MFALSE;
1614 }
1615 } else {
1616 PRINTM(MMSG, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
1617 }
1618 done:
1619 LEAVE();
1620 return MLAN_STATUS_SUCCESS;
1621 }
1622
1623 /**
1624 * @brief This function enables the host interrupts.
1625 *
1626 * @param pmadapter A pointer to mlan_adapter structure
1627 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1628 */
1629 mlan_status
wlan_enable_host_int(pmlan_adapter pmadapter)1630 wlan_enable_host_int(pmlan_adapter pmadapter)
1631 {
1632 mlan_status ret;
1633 t_u8 mask = HIM_ENABLE;
1634
1635 ENTER();
1636 ret = wlan_sdio_enable_host_int_mask(pmadapter, mask);
1637 LEAVE();
1638 return ret;
1639 }
1640
1641 #if defined(SDIO_MULTI_PORT_RX_AGGR)
1642 /**
1643 * @brief This function try to read the packet when fail to alloc rx buffer
1644 *
1645 * @param pmadapter A pointer to mlan_adapter structure
1646 * @param port Current port on which packet needs to be rxed
1647 * @param rx_len Length of received packet
1648 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1649 */
1650 static mlan_status
wlan_sdio_card_to_host_recovery(mlan_adapter * pmadapter,t_u8 port,t_u16 rx_len)1651 wlan_sdio_card_to_host_recovery(mlan_adapter *pmadapter, t_u8 port,
1652 t_u16 rx_len)
1653 {
1654 mlan_buffer mbuf;
1655 t_u32 pkt_type = 0;
1656 mlan_status ret = MLAN_STATUS_FAILURE;
1657 ENTER();
1658 if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1659 PRINTM(MDATA, "Recovery:do Rx Aggr\n");
1660 /* do aggr RX now */
1661 wlan_receive_mp_aggr_buf(pmadapter);
1662 }
1663 memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
1664 mbuf.pbuf = pmadapter->rx_buf;
1665 mbuf.data_len = rx_len;
1666
1667 PRINTM(MDATA, "Recovery: Try read port=%d rx_len=%d\n", port, rx_len);
1668 if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type,
1669 (t_u32 *)&pmadapter->
1670 upld_len, &mbuf,
1671 rx_len,
1672 pmadapter->ioport +
1673 port)) {
1674 PRINTM(MERROR, "Recovery: Fail to do cmd53\n");
1675 }
1676 if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
1677 PRINTM(MERROR,
1678 "Recovery: Receive a wrong pkt: type=%d, len=%d\n",
1679 pkt_type, pmadapter->upld_len);
1680 goto done;
1681 }
1682 if (pkt_type == MLAN_TYPE_DATA) {
1683 //TODO fill the hole in Rx reorder table
1684 PRINTM(MDATA, "Recovery: Drop Data packet\n");
1685 pmadapter->dbg.num_pkt_dropped++;
1686 } else if (pkt_type == MLAN_TYPE_SPA_DATA) {
1687 PRINTM(MDATA, "Recovery: SPA Data packet len=%d\n",
1688 pmadapter->upld_len);
1689 wlan_decode_spa_buffer(pmadapter, pmadapter->rx_buf,
1690 pmadapter->upld_len);
1691 pmadapter->data_received = MTRUE;
1692 }
1693 PRINTM(MMSG, "wlan: Success handle rx port=%d, rx_len=%d \n", port,
1694 rx_len);
1695 ret = MLAN_STATUS_SUCCESS;
1696 done:
1697 LEAVE();
1698 return ret;
1699 }
1700 #endif
1701
1702 /**
1703 * @brief This function checks the interrupt status and handle it accordingly.
1704 *
1705 * @param pmadapter A pointer to mlan_adapter structure
1706 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1707 */
1708 mlan_status
wlan_process_int_status(mlan_adapter * pmadapter)1709 wlan_process_int_status(mlan_adapter *pmadapter)
1710 {
1711 mlan_status ret = MLAN_STATUS_SUCCESS;
1712 pmlan_callbacks pcb = &pmadapter->callbacks;
1713 t_u8 sdio_ireg;
1714 mlan_buffer *pmbuf = MNULL;
1715
1716 t_u8 port = 0;
1717 t_u32 len_reg_l, len_reg_u;
1718 t_u32 rx_blocks;
1719 t_u8 bit_count = 0;
1720 t_u32 ps_state = pmadapter->ps_state;
1721 t_u16 rx_len;
1722 t_u32 upld_typ = 0;
1723 t_u32 cr = 0;
1724 t_u8 rd_len_p0_l = RD_LEN_P0_L;
1725 t_u8 rd_len_p0_u = RD_LEN_P0_U;
1726 t_u8 cmd_rd_len_0 = CMD_RD_LEN_0;
1727 t_u8 cmd_rd_len_1 = CMD_RD_LEN_1;
1728
1729 ENTER();
1730
1731 pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
1732 sdio_ireg = pmadapter->sdio_ireg;
1733 pmadapter->sdio_ireg = 0;
1734 pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
1735
1736 if (!sdio_ireg)
1737 goto done;
1738 /* check the command port */
1739 if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS) {
1740 if (pmadapter->cmd_sent)
1741 pmadapter->cmd_sent = MFALSE;
1742 PRINTM(MINFO, "cmd_sent=%d\n", pmadapter->cmd_sent);
1743 }
1744
1745 if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) {
1746 /* read the len of control packet */
1747 rx_len = ((t_u16)pmadapter->mp_regs[cmd_rd_len_1]) << 8;
1748 rx_len |= (t_u16)pmadapter->mp_regs[cmd_rd_len_0];
1749 PRINTM(MINFO, "RX: cmd port rx_len=%u\n", rx_len);
1750 rx_blocks =
1751 (rx_len + MLAN_SDIO_BLOCK_SIZE -
1752 1) / MLAN_SDIO_BLOCK_SIZE;
1753 if (rx_len <= INTF_HEADER_LEN ||
1754 (rx_blocks * MLAN_SDIO_BLOCK_SIZE) > ALLOC_BUF_SIZE) {
1755 PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
1756 ret = MLAN_STATUS_FAILURE;
1757 goto done;
1758 }
1759 rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
1760 pmbuf = wlan_alloc_mlan_buffer(pmadapter, rx_len, 0,
1761 MOAL_MALLOC_BUFFER);
1762 if (pmbuf == MNULL) {
1763 PRINTM(MERROR, "Failed to allocate 'mlan_buffer'\n");
1764 ret = MLAN_STATUS_FAILURE;
1765 goto done;
1766 }
1767 PRINTM(MINFO, "cmd rx buffer rx_len = %d\n", rx_len);
1768
1769 /* Transfer data from card */
1770 if (MLAN_STATUS_SUCCESS !=
1771 wlan_sdio_card_to_host(pmadapter, &upld_typ,
1772 (t_u32 *)&pmadapter->upld_len, pmbuf,
1773 rx_len,
1774 pmadapter->ioport | CMD_PORT_SLCT)) {
1775 pmadapter->dbg.num_cmdevt_card_to_host_failure++;
1776 PRINTM(MERROR,
1777 "Card-to-host cmd failed: int status=0x%x\n",
1778 sdio_ireg);
1779 wlan_free_mlan_buffer(pmadapter, pmbuf);
1780 ret = MLAN_STATUS_FAILURE;
1781 goto term_cmd53;
1782 }
1783
1784 if ((upld_typ != MLAN_TYPE_CMD) &&
1785 (upld_typ != MLAN_TYPE_EVENT))
1786 PRINTM(MERROR,
1787 "receive a wrong packet from CMD PORT. type =0x%d\n",
1788 upld_typ);
1789
1790 wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ, MFALSE);
1791
1792 /* We might receive data/sleep_cfm at the same time */
1793 /* reset data_receive flag to avoid ps_state change */
1794 if ((ps_state == PS_STATE_SLEEP_CFM) &&
1795 (pmadapter->ps_state == PS_STATE_SLEEP))
1796 pmadapter->data_received = MFALSE;
1797 }
1798
1799 if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
1800 if (pmadapter->mp_wr_bitmap & pmadapter->mp_data_port_mask)
1801 pmadapter->mp_invalid_update++;
1802 pmadapter->mp_wr_bitmap =
1803 (t_u32)pmadapter->mp_regs[WR_BITMAP_L];
1804 pmadapter->mp_wr_bitmap |=
1805 ((t_u32)pmadapter->mp_regs[WR_BITMAP_U]) << 8;
1806 pmadapter->mp_wr_bitmap |=
1807 ((t_u32)pmadapter->mp_regs[WR_BITMAP_1L]) << 16;
1808 pmadapter->mp_wr_bitmap |=
1809 ((t_u32)pmadapter->mp_regs[WR_BITMAP_1U]) << 24;
1810 bit_count =
1811 bitcount(pmadapter->mp_wr_bitmap & pmadapter->
1812 mp_data_port_mask);
1813 if (bit_count) {
1814 pmadapter->mp_update[bit_count - 1]++;
1815 if (pmadapter->mp_update[bit_count - 1] == 0xffffffff)
1816 memset(pmadapter, pmadapter->mp_update, 0,
1817 sizeof(pmadapter->mp_update));
1818 }
1819
1820 pmadapter->last_recv_wr_bitmap = pmadapter->mp_wr_bitmap;
1821 PRINTM(MINTR, "DNLD: wr_bitmap=0x%08x\n",
1822 pmadapter->mp_wr_bitmap);
1823 if (pmadapter->data_sent &&
1824 (pmadapter->
1825 mp_wr_bitmap & (1 << pmadapter->curr_wr_port))) {
1826 PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
1827 pmadapter->data_sent = MFALSE;
1828 }
1829 }
1830
1831 if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
1832 pmadapter->mp_rd_bitmap =
1833 (t_u32)pmadapter->mp_regs[RD_BITMAP_L];
1834 pmadapter->mp_rd_bitmap |=
1835 ((t_u32)pmadapter->mp_regs[RD_BITMAP_U]) << 8;
1836 pmadapter->mp_rd_bitmap |=
1837 ((t_u32)pmadapter->mp_regs[RD_BITMAP_1L]) << 16;
1838 pmadapter->mp_rd_bitmap |=
1839 ((t_u32)pmadapter->mp_regs[RD_BITMAP_1U]) << 24;
1840 PRINTM(MINTR, "UPLD: rd_bitmap=0x%08x\n",
1841 pmadapter->mp_rd_bitmap);
1842
1843 while (MTRUE) {
1844 ret = wlan_get_rd_port(pmadapter, &port);
1845 if (ret != MLAN_STATUS_SUCCESS) {
1846 PRINTM(MINFO,
1847 "no more rd_port to be handled\n");
1848 break;
1849 }
1850 len_reg_l = rd_len_p0_l + (port << 1);
1851 len_reg_u = rd_len_p0_u + (port << 1);
1852 rx_len = ((t_u16)pmadapter->mp_regs[len_reg_u]) << 8;
1853 rx_len |= (t_u16)pmadapter->mp_regs[len_reg_l];
1854 PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
1855 rx_blocks =
1856 (rx_len + MLAN_SDIO_BLOCK_SIZE -
1857 1) / MLAN_SDIO_BLOCK_SIZE;
1858 #if defined(SDIO_MULTI_PORT_RX_AGGR)
1859 if (rx_len <= INTF_HEADER_LEN ||
1860 (rx_blocks * MLAN_SDIO_BLOCK_SIZE) >
1861 pmadapter->mpa_rx.buf_size) {
1862 #else
1863 if (rx_len <= INTF_HEADER_LEN ||
1864 (rx_blocks * MLAN_SDIO_BLOCK_SIZE) >
1865 ALLOC_BUF_SIZE) {
1866 #endif
1867 PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
1868 ret = MLAN_STATUS_FAILURE;
1869 goto done;
1870 }
1871 rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
1872 if (rx_len > MLAN_TX_DATA_BUF_SIZE_2K
1873 && !pmadapter->enable_net_mon)
1874 pmbuf = wlan_alloc_mlan_buffer(pmadapter,
1875 rx_len, 0,
1876 MOAL_MALLOC_BUFFER);
1877 else
1878 pmbuf = wlan_alloc_mlan_buffer(pmadapter,
1879 rx_len,
1880 MLAN_RX_HEADER_LEN,
1881 MOAL_ALLOC_MLAN_BUFFER);
1882 if (pmbuf == MNULL) {
1883 PRINTM(MERROR,
1884 "Failed to allocate 'mlan_buffer'\n");
1885 pmadapter->dbg.num_alloc_buffer_failure++;
1886 #if defined(SDIO_MULTI_PORT_RX_AGGR)
1887 if (MLAN_STATUS_SUCCESS ==
1888 wlan_sdio_card_to_host_recovery(pmadapter,
1889 port,
1890 rx_len))
1891 continue;
1892 #endif
1893 ret = MLAN_STATUS_FAILURE;
1894 goto done;
1895 }
1896 PRINTM(MINFO, "rx_len = %d\n", rx_len);
1897 #ifdef SDIO_MULTI_PORT_RX_AGGR
1898 if (MLAN_STATUS_SUCCESS !=
1899 wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf,
1900 port, rx_len)) {
1901 #else
1902 /* Transfer data from card */
1903 if (MLAN_STATUS_SUCCESS !=
1904 wlan_sdio_card_to_host(pmadapter, &upld_typ,
1905 (t_u32 *)&pmadapter->
1906 upld_len, pmbuf, rx_len,
1907 pmadapter->ioport + port)) {
1908 #endif /* SDIO_MULTI_PORT_RX_AGGR */
1909
1910 pmadapter->dbg.num_rx_card_to_host_failure++;
1911
1912 PRINTM(MERROR,
1913 "Card to host failed: int status=0x%x\n",
1914 sdio_ireg);
1915 #ifndef SDIO_MULTI_PORT_RX_AGGR
1916 wlan_free_mlan_buffer(pmadapter, pmbuf);
1917 #endif
1918 ret = MLAN_STATUS_FAILURE;
1919 goto term_cmd53;
1920 }
1921 #ifndef SDIO_MULTI_PORT_RX_AGGR
1922 wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ,
1923 MTRUE);
1924 #endif
1925 }
1926 /* We might receive data/sleep_cfm at the same time */
1927 /* reset data_receive flag to avoid ps_state change */
1928 if ((ps_state == PS_STATE_SLEEP_CFM) &&
1929 (pmadapter->ps_state == PS_STATE_SLEEP))
1930 pmadapter->data_received = MFALSE;
1931 }
1932
1933 ret = MLAN_STATUS_SUCCESS;
1934 goto done;
1935
1936 term_cmd53:
1937 /* terminate cmd53 */
1938 if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
1939 HOST_TO_CARD_EVENT_REG,
1940 &cr))
1941 PRINTM(MERROR, "read CFG reg failed\n");
1942 PRINTM(MINFO, "Config Reg val = %d\n", cr);
1943 if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
1944 HOST_TO_CARD_EVENT_REG,
1945 (cr | HOST_TERM_CMD53)))
1946 PRINTM(MERROR, "write CFG reg failed\n");
1947 PRINTM(MINFO, "write success\n");
1948 if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
1949 HOST_TO_CARD_EVENT_REG,
1950 &cr))
1951 PRINTM(MERROR, "read CFG reg failed\n");
1952 PRINTM(MINFO, "Config reg val =%x\n", cr);
1953
1954 done:
1955 LEAVE();
1956 return ret;
1957 }
1958
1959 /**
1960 * @brief This function sends data to the card.
1961 *
1962 * @param pmadapter A pointer to mlan_adapter structure
1963 * @param type data or command
1964 * @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include SDIO header)
1965 * @param tx_param A pointer to mlan_tx_param
1966 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1967 */
1968 mlan_status
1969 wlan_sdio_host_to_card(mlan_adapter *pmadapter, t_u8 type, mlan_buffer *pmbuf,
1970 mlan_tx_param *tx_param)
1971 {
1972 mlan_status ret = MLAN_STATUS_SUCCESS;
1973 t_u32 buf_block_len;
1974 t_u32 blksz;
1975 t_u8 port = 0;
1976 t_u32 cmd53_port = 0;
1977 t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
1978
1979 ENTER();
1980
1981 /* Allocate buffer and copy payload */
1982 blksz = MLAN_SDIO_BLOCK_SIZE;
1983 buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
1984 *(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
1985 *(t_u16 *)&payload[2] = wlan_cpu_to_le16(type);
1986
1987 /*
1988 * This is SDIO specific header
1989 * t_u16 length,
1990 * t_u16 type (MLAN_TYPE_DATA = 0,
1991 * MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
1992 */
1993 if (type == MLAN_TYPE_DATA) {
1994 ret = wlan_get_wr_port_data(pmadapter, &port);
1995 if (ret != MLAN_STATUS_SUCCESS) {
1996 PRINTM(MERROR,
1997 "no wr_port available: wr_bitmap=0x%08x curr_wr_port=%d\n",
1998 pmadapter->mp_wr_bitmap,
1999 pmadapter->curr_wr_port);
2000 goto exit;
2001 }
2002 /* Transfer data to card */
2003 pmbuf->data_len = buf_block_len * blksz;
2004
2005 #ifdef SDIO_MULTI_PORT_TX_AGGR
2006 if (tx_param)
2007 ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
2008 tx_param->next_pkt_len);
2009 else
2010 ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
2011 0);
2012 #else
2013 ret = wlan_write_data_sync(pmadapter, pmbuf,
2014 pmadapter->ioport + port);
2015 #endif /* SDIO_MULTI_PORT_TX_AGGR */
2016
2017 } else {
2018 /*Type must be MLAN_TYPE_CMD */
2019 pmadapter->cmd_sent = MTRUE;
2020 if (pmbuf->data_len <= INTF_HEADER_LEN ||
2021 pmbuf->data_len > WLAN_UPLD_SIZE)
2022 PRINTM(MWARN,
2023 "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
2024 payload, pmbuf->data_len);
2025 /* Transfer data to card */
2026 pmbuf->data_len = buf_block_len * blksz;
2027 cmd53_port = (pmadapter->ioport) | CMD_PORT_SLCT;
2028 ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
2029 }
2030
2031 if (ret == MLAN_STATUS_FAILURE) {
2032 if (type == MLAN_TYPE_CMD)
2033 pmadapter->cmd_sent = MFALSE;
2034 if (type == MLAN_TYPE_DATA)
2035 pmadapter->data_sent = MFALSE;
2036 } else {
2037 if (type == MLAN_TYPE_DATA) {
2038 if (!
2039 (pmadapter->
2040 mp_wr_bitmap & (1 << pmadapter->curr_wr_port)))
2041 pmadapter->data_sent = MTRUE;
2042 else
2043 pmadapter->data_sent = MFALSE;
2044 }
2045 DBG_HEXDUMP(MIF_D, "SDIO Blk Wr",
2046 pmbuf->pbuf + pmbuf->data_offset,
2047 MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
2048 }
2049 exit:
2050 LEAVE();
2051 return ret;
2052 }
2053
2054 /**
2055 * @brief Deaggregate single port aggregation packet
2056 *
2057 * @param pmadapter A pointer to mlan_adapter structure
2058 * @param buf A pointer to aggregated data packet
2059 * @param len
2060 *
2061 * @return N/A
2062 */
2063 void
2064 wlan_decode_spa_buffer(mlan_adapter *pmadapter, t_u8 *buf, t_u32 len)
2065 {
2066 int total_pkt_len;
2067 t_u8 block_num = 0;
2068 t_u16 block_size = 0;
2069 t_u8 *data;
2070 t_u32 pkt_len, pkt_type = 0;
2071 mlan_buffer *mbuf_deaggr = MNULL;
2072
2073 ENTER();
2074
2075 data = (t_u8 *)buf;
2076 total_pkt_len = len;
2077 if (total_pkt_len < pmadapter->sdio_rx_block_size) {
2078 PRINTM(MERROR, "Invalid sp aggr packet size=%d\n",
2079 total_pkt_len);
2080 goto done;
2081 }
2082 while (total_pkt_len >= (OFFSET_OF_SDIO_HEADER + INTF_HEADER_LEN)) {
2083 block_num = *(data + OFFSET_OF_BLOCK_NUMBER);
2084 block_size = pmadapter->sdio_rx_block_size * block_num;
2085 if (block_size > total_pkt_len) {
2086 PRINTM(MERROR,
2087 "Error in pkt, block_num=%d, pkt_len=%d\n",
2088 block_num, total_pkt_len);
2089 break;
2090 }
2091 pkt_len =
2092 wlan_le16_to_cpu(*(t_u16 *)
2093 (data + OFFSET_OF_SDIO_HEADER));
2094 pkt_type =
2095 wlan_le16_to_cpu(*(t_u16 *)
2096 (data + OFFSET_OF_SDIO_HEADER + 2));
2097 if ((pkt_len + OFFSET_OF_SDIO_HEADER) > block_size) {
2098 PRINTM(MERROR,
2099 "Error in pkt, pkt_len=%d, block_size=%d\n",
2100 pkt_len, block_size);
2101 break;
2102 }
2103 mbuf_deaggr =
2104 wlan_alloc_mlan_buffer(pmadapter,
2105 pkt_len - INTF_HEADER_LEN,
2106 MLAN_RX_HEADER_LEN,
2107 MOAL_ALLOC_MLAN_BUFFER);
2108 if (mbuf_deaggr == MNULL) {
2109 PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
2110 break;
2111 }
2112 memcpy(pmadapter, mbuf_deaggr->pbuf + mbuf_deaggr->data_offset,
2113 data + OFFSET_OF_SDIO_HEADER + INTF_HEADER_LEN,
2114 pkt_len - INTF_HEADER_LEN);
2115 mbuf_deaggr->data_len = pkt_len - INTF_HEADER_LEN;
2116 wlan_handle_rx_packet(pmadapter, mbuf_deaggr);
2117 data += block_size;
2118 total_pkt_len -= block_size;
2119 if (total_pkt_len < pmadapter->sdio_rx_block_size)
2120 break;
2121 }
2122 done:
2123 LEAVE();
2124 return;
2125 }
2126
2127 /**
2128 * @brief This function deaggr rx pkt
2129 *
2130 * @param pmadapter A pointer to mlan_adapter structure
2131 * @param pmbuf A pointer to the SDIO mpa data
2132 * @return N/A
2133 */
2134 t_void
2135 wlan_sdio_deaggr_rx_pkt(IN pmlan_adapter pmadapter, mlan_buffer *pmbuf)
2136 {
2137 if (pmbuf->buf_type == MLAN_BUF_TYPE_SPA_DATA) {
2138 wlan_decode_spa_buffer(pmadapter,
2139 pmbuf->pbuf + pmbuf->data_offset,
2140 pmbuf->data_len);
2141 wlan_free_mlan_buffer(pmadapter, pmbuf);
2142 } else
2143 wlan_handle_rx_packet(pmadapter, pmbuf);
2144 }
2145
2146 #if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
2147 /**
2148 * @brief This function allocates buffer for the SDIO aggregation buffer
2149 * related members of adapter structure
2150 *
2151 * @param pmadapter A pointer to mlan_adapter structure
2152 * @param mpa_tx_buf_size Tx buffer size to allocate
2153 * @param mpa_rx_buf_size Rx buffer size to allocate
2154 *
2155 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2156 */
2157 mlan_status
2158 wlan_alloc_sdio_mpa_buffers(IN mlan_adapter *pmadapter,
2159 t_u32 mpa_tx_buf_size, t_u32 mpa_rx_buf_size)
2160 {
2161 mlan_status ret = MLAN_STATUS_SUCCESS;
2162 pmlan_callbacks pcb = &pmadapter->callbacks;
2163 t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
2164
2165 ENTER();
2166
2167 #ifdef SDIO_MULTI_PORT_TX_AGGR
2168 if ((pmadapter->max_segs < mp_aggr_pkt_limit) ||
2169 (pmadapter->max_seg_size < pmadapter->max_sp_tx_size)) {
2170 ret = pcb->moal_malloc(pmadapter->pmoal_handle,
2171 mpa_tx_buf_size + DMA_ALIGNMENT,
2172 MLAN_MEM_DEF | MLAN_MEM_DMA,
2173 (t_u8 **)&pmadapter->mpa_tx.head_ptr);
2174 if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_tx.head_ptr) {
2175 PRINTM(MERROR,
2176 "Could not allocate buffer for SDIO MP TX aggr\n");
2177 ret = MLAN_STATUS_FAILURE;
2178 goto error;
2179 }
2180 pmadapter->mpa_tx.buf =
2181 (t_u8 *)ALIGN_ADDR(pmadapter->mpa_tx.head_ptr,
2182 DMA_ALIGNMENT);
2183 } else {
2184 PRINTM(MMSG, "wlan: Enable TX SG mode\n");
2185 pmadapter->mpa_tx.head_ptr = MNULL;
2186 pmadapter->mpa_tx.buf = MNULL;
2187 }
2188 pmadapter->mpa_tx.buf_size = mpa_tx_buf_size;
2189 #endif /* SDIO_MULTI_PORT_TX_AGGR */
2190
2191 #ifdef SDIO_MULTI_PORT_RX_AGGR
2192 if ((pmadapter->max_segs < mp_aggr_pkt_limit) ||
2193 (pmadapter->max_seg_size < pmadapter->max_sp_rx_size)) {
2194 ret = pcb->moal_malloc(pmadapter->pmoal_handle,
2195 mpa_rx_buf_size + DMA_ALIGNMENT,
2196 MLAN_MEM_DEF | MLAN_MEM_DMA,
2197 (t_u8 **)&pmadapter->mpa_rx.head_ptr);
2198 if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
2199 PRINTM(MERROR,
2200 "Could not allocate buffer for SDIO MP RX aggr\n");
2201 ret = MLAN_STATUS_FAILURE;
2202 goto error;
2203 }
2204 pmadapter->mpa_rx.buf =
2205 (t_u8 *)ALIGN_ADDR(pmadapter->mpa_rx.head_ptr,
2206 DMA_ALIGNMENT);
2207 } else {
2208 PRINTM(MMSG, "wlan: Enable RX SG mode\n");
2209 pmadapter->mpa_rx.head_ptr = MNULL;
2210 pmadapter->mpa_rx.buf = MNULL;
2211 }
2212 pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
2213 #endif /* SDIO_MULTI_PORT_RX_AGGR */
2214 error:
2215 if (ret != MLAN_STATUS_SUCCESS)
2216 wlan_free_sdio_mpa_buffers(pmadapter);
2217
2218 LEAVE();
2219 return ret;
2220 }
2221
2222 /**
2223 * @brief This function frees buffers for the SDIO aggregation
2224 *
2225 * @param pmadapter A pointer to mlan_adapter structure
2226 *
2227 * @return MLAN_STATUS_SUCCESS
2228 */
2229 mlan_status
2230 wlan_free_sdio_mpa_buffers(IN mlan_adapter *pmadapter)
2231 {
2232 pmlan_callbacks pcb = &pmadapter->callbacks;
2233
2234 ENTER();
2235
2236 #ifdef SDIO_MULTI_PORT_TX_AGGR
2237 if (pmadapter->mpa_tx.buf) {
2238 pcb->moal_mfree(pmadapter->pmoal_handle,
2239 (t_u8 *)pmadapter->mpa_tx.head_ptr);
2240 pmadapter->mpa_tx.head_ptr = MNULL;
2241 pmadapter->mpa_tx.buf = MNULL;
2242 pmadapter->mpa_tx.buf_size = 0;
2243 }
2244 #endif /* SDIO_MULTI_PORT_TX_AGGR */
2245
2246 #ifdef SDIO_MULTI_PORT_RX_AGGR
2247 if (pmadapter->mpa_rx.buf) {
2248 pcb->moal_mfree(pmadapter->pmoal_handle,
2249 (t_u8 *)pmadapter->mpa_rx.head_ptr);
2250 pmadapter->mpa_rx.head_ptr = MNULL;
2251 pmadapter->mpa_rx.buf = MNULL;
2252 pmadapter->mpa_rx.buf_size = 0;
2253 }
2254 #endif /* SDIO_MULTI_PORT_RX_AGGR */
2255
2256 LEAVE();
2257 return MLAN_STATUS_SUCCESS;
2258 }
2259
2260 #if defined(SDIO_MULTI_PORT_RX_AGGR)
2261 /**
2262 * @brief This function re-allocate rx mpa buffer
2263 *
2264 * @param pmadapter A pointer to mlan_adapter structure
2265 *
2266 * @return MLAN_STATUS_SUCCESS
2267 */
2268 mlan_status
2269 wlan_re_alloc_sdio_rx_mpa_buffer(IN mlan_adapter *pmadapter)
2270 {
2271 mlan_status ret = MLAN_STATUS_SUCCESS;
2272 pmlan_callbacks pcb = &pmadapter->callbacks;
2273 t_u8 mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
2274
2275 t_u32 mpa_rx_buf_size = SDIO_MP_RX_AGGR_DEF_BUF_SIZE;
2276
2277 #ifdef SDIO_MULTI_PORT_RX_AGGR
2278 if (pmadapter->mpa_rx.buf) {
2279 pcb->moal_mfree(pmadapter->pmoal_handle,
2280 (t_u8 *)pmadapter->mpa_rx.head_ptr);
2281 pmadapter->mpa_rx.head_ptr = MNULL;
2282 pmadapter->mpa_rx.buf = MNULL;
2283 pmadapter->mpa_rx.buf_size = 0;
2284 }
2285 #endif /* SDIO_MULTI_PORT_RX_AGGR */
2286 if (pmadapter->sdio_rx_aggr_enable)
2287 mpa_rx_buf_size = MAX(mpa_rx_buf_size, SDIO_CMD53_MAX_SIZE);
2288 if ((pmadapter->max_segs < mp_aggr_pkt_limit) ||
2289 (pmadapter->max_seg_size < pmadapter->max_sp_rx_size)) {
2290 ret = pcb->moal_malloc(pmadapter->pmoal_handle,
2291 mpa_rx_buf_size + DMA_ALIGNMENT,
2292 MLAN_MEM_DEF | MLAN_MEM_DMA,
2293 (t_u8 **)&pmadapter->mpa_rx.head_ptr);
2294 if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
2295 PRINTM(MERROR,
2296 "Could not allocate buffer for SDIO MP RX aggr\n");
2297 ret = MLAN_STATUS_FAILURE;
2298 goto error;
2299 }
2300 pmadapter->mpa_rx.buf =
2301 (t_u8 *)ALIGN_ADDR(pmadapter->mpa_rx.head_ptr,
2302 DMA_ALIGNMENT);
2303 } else {
2304 PRINTM(MMSG, "wlan: Enable RX SG mode\n");
2305 pmadapter->mpa_rx.head_ptr = MNULL;
2306 pmadapter->mpa_rx.buf = MNULL;
2307 }
2308 pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
2309 PRINTM(MMSG, "mpa_rx_buf_size=%d\n", mpa_rx_buf_size);
2310 error:
2311 return ret;
2312 }
2313 #endif
2314
2315 #endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */
2316
2317 /**
2318 * @brief This function issues commands to initialize firmware
2319 *
2320 * @param priv A pointer to mlan_private structure
2321 *
2322 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2323 */
2324 mlan_status
2325 wlan_set_sdio_gpio_int(IN pmlan_private priv)
2326 {
2327 mlan_status ret = MLAN_STATUS_SUCCESS;
2328 pmlan_adapter pmadapter = MNULL;
2329 HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_int_cfg;
2330
2331 if (!priv) {
2332 LEAVE();
2333 return MLAN_STATUS_FAILURE;
2334 }
2335 pmadapter = priv->adapter;
2336
2337 ENTER();
2338
2339 if (pmadapter->int_mode == INT_MODE_GPIO) {
2340 if (pmadapter->gpio_pin != GPIO_INT_NEW_MODE) {
2341 PRINTM(MINFO,
2342 "SDIO_GPIO_INT_CONFIG: interrupt mode is GPIO\n");
2343 sdio_int_cfg.action = HostCmd_ACT_GEN_SET;
2344 sdio_int_cfg.gpio_pin = pmadapter->gpio_pin;
2345 sdio_int_cfg.gpio_int_edge = INT_FALLING_EDGE;
2346 sdio_int_cfg.gpio_pulse_width = DELAY_1_US;
2347 ret = wlan_prepare_cmd(priv,
2348 HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
2349 HostCmd_ACT_GEN_SET, 0, MNULL,
2350 &sdio_int_cfg);
2351
2352 if (ret) {
2353 PRINTM(MERROR,
2354 "SDIO_GPIO_INT_CONFIG: send command fail\n");
2355 ret = MLAN_STATUS_FAILURE;
2356 }
2357 }
2358 } else {
2359 PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is SDIO\n");
2360 }
2361
2362 LEAVE();
2363 return ret;
2364 }
2365
2366 /**
2367 * @brief This function prepares command of SDIO GPIO interrupt
2368 *
2369 * @param pmpriv A pointer to mlan_private structure
2370 * @param cmd A pointer to HostCmd_DS_COMMAND structure
2371 * @param cmd_action The action: GET or SET
2372 * @param pdata_buf A pointer to data buffer
2373 * @return MLAN_STATUS_SUCCESS
2374 */
2375 mlan_status
2376 wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
2377 IN HostCmd_DS_COMMAND *cmd,
2378 IN t_u16 cmd_action, IN t_void *pdata_buf)
2379 {
2380 HostCmd_DS_SDIO_GPIO_INT_CONFIG *psdio_gpio_int =
2381 &cmd->params.sdio_gpio_int;
2382
2383 ENTER();
2384
2385 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
2386 cmd->size =
2387 wlan_cpu_to_le16((sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG)) +
2388 S_DS_GEN);
2389
2390 memset(pmpriv->adapter, psdio_gpio_int, 0,
2391 sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
2392 if (cmd_action == HostCmd_ACT_GEN_SET) {
2393 memcpy(pmpriv->adapter, psdio_gpio_int, pdata_buf,
2394 sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
2395 psdio_gpio_int->action =
2396 wlan_cpu_to_le16(psdio_gpio_int->action);
2397 psdio_gpio_int->gpio_pin =
2398 wlan_cpu_to_le16(psdio_gpio_int->gpio_pin);
2399 psdio_gpio_int->gpio_int_edge =
2400 wlan_cpu_to_le16(psdio_gpio_int->gpio_int_edge);
2401 psdio_gpio_int->gpio_pulse_width =
2402 wlan_cpu_to_le16(psdio_gpio_int->gpio_pulse_width);
2403 }
2404
2405 LEAVE();
2406 return MLAN_STATUS_SUCCESS;
2407 }
2408
2409 #define FW_RESET_REG 0x0EE
2410 #define FW_RESET_VAL 0x99
2411 mlan_status
2412 wlan_reset_fw(pmlan_adapter pmadapter)
2413 {
2414 t_u32 tries = 0;
2415 t_u32 value = 1;
2416 t_u32 reset_reg = FW_RESET_REG;
2417 t_u8 reset_val = FW_RESET_VAL;
2418 pmlan_callbacks pcb = &pmadapter->callbacks;
2419 mlan_status ret = MLAN_STATUS_SUCCESS;
2420
2421 ENTER();
2422 wlan_pm_wakeup_card(pmadapter);
2423
2424 /** wait SOC fully wake up */
2425 for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
2426 if (MLAN_STATUS_SUCCESS ==
2427 pcb->moal_write_reg(pmadapter->pmoal_handle, reset_reg,
2428 0xba)) {
2429 pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg,
2430 &value);
2431 if (value == 0xba) {
2432 PRINTM(MMSG, "FW wake up\n");
2433 break;
2434 }
2435 }
2436 pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
2437 }
2438 /* Write register to notify FW */
2439 if (MLAN_STATUS_FAILURE ==
2440 pcb->moal_write_reg(pmadapter->pmoal_handle, reset_reg,
2441 reset_val)) {
2442 PRINTM(MERROR, "Failed to write register.\n");
2443 ret = MLAN_STATUS_FAILURE;
2444 goto done;
2445 }
2446 pcb->moal_read_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
2447 &value);
2448 pcb->moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG,
2449 value | HOST_POWER_UP);
2450 /* Poll register around 100 ms */
2451 for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
2452 pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg, &value);
2453 if (value == 0)
2454 /* FW is ready */
2455 break;
2456 pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
2457 }
2458
2459 if (value) {
2460 PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
2461 reset_reg, value);
2462 ret = MLAN_STATUS_FAILURE;
2463 goto done;
2464 }
2465 PRINTM(MMSG, "FW Reset success\n");
2466 ret = wlan_sdio_probe(pmadapter);
2467 done:
2468 LEAVE();
2469 return ret;
2470 }
2471