xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlan/mlan_sdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 						      &reg)) {
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, &reg)) {
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, &reg)) {
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 			       &reg)) {
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 			       &reg)) {
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