1 /** @file moal_sdio_mmc.c
2 *
3 * @brief This file contains SDIO MMC IF (interface) module
4 * related functions.
5 *
6 *
7 * Copyright 2008-2022 NXP
8 *
9 * This software file (the File) is distributed by NXP
10 * under the terms of the GNU General Public License Version 2, June 1991
11 * (the License). You may use, redistribute and/or modify the File in
12 * accordance with the terms and conditions of the License, a copy of which
13 * is available by writing to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16 *
17 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
20 * this warranty disclaimer.
21 *
22 */
23 /****************************************************
24 Change log:
25 02/25/09: Initial creation -
26 This file supports SDIO MMC only
27 ****************************************************/
28
29 #include <linux/firmware.h>
30
31 #include "moal_sdio.h"
32
33 /** define nxp vendor id */
34 #define NXP_VENDOR_ID 0x0471
35 #define MRVL_VENDOR_ID 0x02df
36
37 /********************************************************
38 Local Variables
39 ********************************************************/
40 /* moal interface ops */
41 static moal_if_ops sdiommc_ops;
42 /********************************************************
43 Global Variables
44 ********************************************************/
45
46 #ifdef SD8887
47 /** Device ID for SD8887 */
48 #define SD_DEVICE_ID_8887 (0x9135)
49 #endif
50 #ifdef SD8801
51 /** Device ID for SD8801 FN1 */
52 #define SD_DEVICE_ID_8801 (0x9139)
53 #endif
54 #ifdef SD8897
55 /** Device ID for SD8897 */
56 #define SD_DEVICE_ID_8897 (0x912d)
57 #endif
58 #ifdef SD8977
59 /** Device ID for SD8977 */
60 #define SD_DEVICE_ID_8977 (0x9145)
61 #endif
62 #ifdef SD8978
63 /** Device ID for SD8978 */
64 #define SD_DEVICE_ID_8978 (0x9159)
65 #endif
66 #ifdef SD8997
67 /** Device ID for SD8997 */
68 #define SD_DEVICE_ID_8997 (0x9141)
69 #endif
70 #ifdef SD8987
71 /** Device ID for SD8987 */
72 #define SD_DEVICE_ID_8987 (0x9149)
73 #endif
74 #ifdef SD9098
75 /** Device ID for SD9098 */
76 #define SD_DEVICE_ID_9098_FN1 (0x914D)
77 /** Device ID for SD9098 */
78 #define SD_DEVICE_ID_9098_FN2 (0x914E)
79 #endif
80 #ifdef SD9097
81 /** Device ID for SD9097 */
82 #define SD_DEVICE_ID_9097 (0x9155)
83 #endif
84 #ifdef SD9177
85 /** Device ID for SD9177 */
86 #define SD_DEVICE_ID_9177 (0x0205)
87 #endif
88 #ifdef SDNW62X
89 /** Device ID for SDNW62X */
90 #define SD_DEVICE_ID_NW62X (0x020D)
91 #endif
92
93 /** WLAN IDs */
94 static const struct sdio_device_id wlan_ids[] = {
95 #ifdef SD8887
96 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8887)},
97 #endif
98 #ifdef SD8801
99 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8801)},
100 #endif
101 #ifdef SD8897
102 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8897)},
103 #endif
104 #ifdef SD8977
105 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8977)},
106 #endif
107 #ifdef SD8978
108 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8978)},
109 #endif
110 #ifdef SD8997
111 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8997)},
112 #endif
113 #ifdef SD8987
114 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_8987)},
115 #endif
116 #ifdef SD9098
117 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_9098_FN1)},
118 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_9098_FN2)},
119 #endif
120 #ifdef SD9097
121 {SDIO_DEVICE(MRVL_VENDOR_ID, SD_DEVICE_ID_9097)},
122 #endif
123 #ifdef SD9177
124 {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9177)},
125 #endif
126 #ifdef SDNW62X
127 {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_NW62X)},
128 #endif
129 {},
130 };
131
132 int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
133 void woal_sdio_remove(struct sdio_func *func);
134 #ifdef SDIO
135 static void woal_sdiommc_reg_dbg(pmoal_handle handle);
136 #endif
137
138 #ifdef SDIO_SUSPEND_RESUME
139 #ifdef MMC_PM_KEEP_POWER
140 int woal_sdio_suspend(struct device *dev);
141 int woal_sdio_resume(struct device *dev);
142
143 static struct dev_pm_ops wlan_sdio_pm_ops = {
144 .suspend = woal_sdio_suspend,
145 .resume = woal_sdio_resume,
146 };
147
148 void woal_sdio_shutdown(struct device *dev);
149 #endif
150 #endif
151
152 // clang-format off
153 static struct sdio_driver REFDATA wlan_sdio = {
154 .name = "wlan_sdio",
155 .id_table = wlan_ids,
156 .probe = woal_sdio_probe,
157 .remove = woal_sdio_remove,
158 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
159 .drv = {
160 .owner = THIS_MODULE,
161 #ifdef SDIO_SUSPEND_RESUME
162 #ifdef MMC_PM_KEEP_POWER
163 .pm = &wlan_sdio_pm_ops,
164 .shutdown = woal_sdio_shutdown,
165 #endif
166 #endif
167
168 }
169 #else
170 #ifdef SDIO_SUSPEND_RESUME
171 #ifdef MMC_PM_KEEP_POWER
172 .drv = {
173 .pm = &wlan_sdio_pm_ops,
174 .shutdown = woal_sdio_shutdown,
175 }
176 #endif
177 #endif
178 #endif
179 };
180 // clang-format on
181
182 /********************************************************
183 Local Functions
184 ********************************************************/
185 static void woal_sdiommc_dump_fw_info(moal_handle *phandle);
186 #if 0
187 /** @brief This function dump the sdio register
188 *
189 * @param handle A Pointer to the moal_handle structure
190 * @return N/A
191 */
192 static void woal_dump_sdio_reg(moal_handle *handle)
193 {
194 int ret = 0;
195 t_u8 data, i;
196 int fun0_reg[] = {0x05, 0x04};
197 t_u8 array_size = 0;
198 #ifdef SD8897
199 int fun1_reg_8897[] = {0x03, 0x04, 0x05, 0x06, 0x07, 0xC0, 0xC1};
200 #endif
201 int fun1_reg_other[] = {0x03, 0x04, 0x05, 0x60, 0x61};
202 int *fun1_reg = NULL;
203
204 for (i = 0; i < ARRAY_SIZE(fun0_reg); i++) {
205 data = sdio_f0_readb(
206 ((struct sdio_mmc_card *)handle->card)->func,
207 fun0_reg[i], &ret);
208 PRINTM(MMSG, "fun0: reg 0x%02x=0x%02x ret=%d\n", fun0_reg[i],
209 data, ret);
210 }
211
212 #ifdef SD8897
213 if (IS_SD8897(handle->card_type)) {
214 fun1_reg = fun1_reg_8897;
215 array_size = sizeof(fun1_reg_8897) / sizeof(int);
216 } else {
217 #endif
218 fun1_reg = fun1_reg_other;
219 array_size = sizeof(fun1_reg_other) / sizeof(int);
220 #ifdef SD8897
221 }
222 #endif
223 for (i = 0; i < array_size; i++) {
224 data = sdio_readb(((struct sdio_mmc_card *)handle->card)->func,
225 fun1_reg[i], &ret);
226 PRINTM(MMSG, "fun1: reg 0x%02x=0x%02x ret=%d\n", fun1_reg[i],
227 data, ret);
228 }
229 return;
230 }
231 #endif
232 /********************************************************
233 Global Functions
234 ********************************************************/
235 /**
236 * @brief This function handles the interrupt.
237 *
238 * @param func A pointer to the sdio_func structure
239 * @return N/A
240 */
woal_sdio_interrupt(struct sdio_func * func)241 static void woal_sdio_interrupt(struct sdio_func *func)
242 {
243 moal_handle *handle;
244 struct sdio_mmc_card *card;
245
246 ENTER();
247
248 card = sdio_get_drvdata(func);
249 if (!card || !card->handle) {
250 PRINTM(MINFO,
251 "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
252 func, card);
253 LEAVE();
254 return;
255 }
256 handle = card->handle;
257 if (handle->surprise_removed == MTRUE) {
258 LEAVE();
259 return;
260 }
261 handle->main_state = MOAL_RECV_INT;
262 PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
263 PRINTM(MINTR, "*\n");
264
265 /* call mlan_interrupt to read int status */
266 mlan_interrupt(0, handle->pmlan_adapter);
267 #ifdef SDIO_SUSPEND_RESUME
268 if (handle->is_suspended) {
269 PRINTM(MINTR, "Receive interrupt in hs_suspended\n");
270 LEAVE();
271 return;
272 }
273 #endif
274 handle->main_state = MOAL_START_MAIN_PROCESS;
275 /* Call MLAN main process */
276 mlan_main_process(handle->pmlan_adapter);
277 handle->main_state = MOAL_END_MAIN_PROCESS;
278 LEAVE();
279 }
280
281 /** @brief This function updates the card types
282 *
283 * @param handle A Pointer to the moal_handle structure
284 * @param card A Pointer to card
285 *
286 * @return N/A
287 */
woal_update_card_type(t_void * card)288 static t_u16 woal_update_card_type(t_void *card)
289 {
290 struct sdio_mmc_card *cardp_sd = (struct sdio_mmc_card *)card;
291 t_u16 card_type = 0;
292
293 /* Update card type */
294 #ifdef SD8887
295 if (cardp_sd->func->device == SD_DEVICE_ID_8887) {
296 card_type = CARD_TYPE_SD8887;
297 moal_memcpy_ext(NULL, driver_version, CARD_SD8887,
298 strlen(CARD_SD8887), strlen(driver_version));
299 moal_memcpy_ext(
300 NULL,
301 driver_version + strlen(INTF_CARDTYPE) +
302 strlen(KERN_VERSION),
303 V15, strlen(V15),
304 strlen(driver_version) -
305 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
306 }
307 #endif
308 #ifdef SD8801
309 if (cardp_sd->func->device == SD_DEVICE_ID_8801) {
310 card_type = CARD_TYPE_SD8801;
311 moal_memcpy_ext(NULL, driver_version, CARD_SD8801,
312 strlen(CARD_SD8801), strlen(driver_version));
313 moal_memcpy_ext(
314 NULL,
315 driver_version + strlen(INTF_CARDTYPE) +
316 strlen(KERN_VERSION),
317 V14, strlen(V14),
318 strlen(driver_version) -
319 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
320 }
321 #endif
322
323 #ifdef SD8897
324 if (cardp_sd->func->device == SD_DEVICE_ID_8897) {
325 card_type = CARD_TYPE_SD8897;
326 moal_memcpy_ext(NULL, driver_version, CARD_SD8897,
327 strlen(CARD_SD8897), strlen(driver_version));
328 moal_memcpy_ext(
329 NULL,
330 driver_version + strlen(INTF_CARDTYPE) +
331 strlen(KERN_VERSION),
332 V15, strlen(V15),
333 strlen(driver_version) -
334 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
335 }
336 #endif
337 #ifdef SD8977
338 if (cardp_sd->func->device == SD_DEVICE_ID_8977) {
339 card_type = CARD_TYPE_SD8977;
340 moal_memcpy_ext(NULL, driver_version, CARD_SD8977,
341 strlen(CARD_SD8977), strlen(driver_version));
342 moal_memcpy_ext(
343 NULL,
344 driver_version + strlen(INTF_CARDTYPE) +
345 strlen(KERN_VERSION),
346 V16, strlen(V16),
347 strlen(driver_version) -
348 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
349 }
350 #endif
351 #ifdef SD8978
352 if (cardp_sd->func->device == SD_DEVICE_ID_8978) {
353 card_type = CARD_TYPE_SD8978;
354 moal_memcpy_ext(NULL, driver_version, "SDIW416",
355 strlen("SDIW416"), strlen(driver_version));
356 moal_memcpy_ext(
357 NULL,
358 driver_version + strlen(INTF_CARDTYPE) +
359 strlen(KERN_VERSION),
360 V16, strlen(V16),
361 strlen(driver_version) -
362 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
363 }
364 #endif
365 #ifdef SD8997
366 if (cardp_sd->func->device == SD_DEVICE_ID_8997) {
367 card_type = CARD_TYPE_SD8997;
368 moal_memcpy_ext(NULL, driver_version, CARD_SD8997,
369 strlen(CARD_SD8997), strlen(driver_version));
370 moal_memcpy_ext(
371 NULL,
372 driver_version + strlen(INTF_CARDTYPE) +
373 strlen(KERN_VERSION),
374 V16, strlen(V16),
375 strlen(driver_version) -
376 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
377 }
378 #endif
379 #ifdef SD8987
380 if (cardp_sd->func->device == SD_DEVICE_ID_8987) {
381 card_type = CARD_TYPE_SD8987;
382 moal_memcpy_ext(NULL, driver_version, CARD_SD8987,
383 strlen(CARD_SD8987), strlen(driver_version));
384 moal_memcpy_ext(
385 NULL,
386 driver_version + strlen(INTF_CARDTYPE) +
387 strlen(KERN_VERSION),
388 V16, strlen(V16),
389 strlen(driver_version) -
390 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
391 }
392 #endif
393 #ifdef SDNW62X
394 if (cardp_sd->func->device == SD_DEVICE_ID_NW62X) {
395 card_type = CARD_TYPE_SDNW62X;
396 moal_memcpy_ext(NULL, driver_version, CARD_SDNW62X,
397 strlen(CARD_SDNW62X), strlen(driver_version));
398 moal_memcpy_ext(
399 NULL,
400 driver_version + strlen(INTF_CARDTYPE) +
401 strlen(KERN_VERSION),
402 V17, strlen(V17),
403 strlen(driver_version) -
404 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
405 }
406 #endif
407 #ifdef SD9097
408 if (cardp_sd->func->device == SD_DEVICE_ID_9097) {
409 card_type = CARD_TYPE_SD9097;
410 moal_memcpy_ext(NULL, driver_version, CARD_SD9097,
411 strlen(CARD_SD9097), strlen(driver_version));
412 moal_memcpy_ext(
413 NULL,
414 driver_version + strlen(INTF_CARDTYPE) +
415 strlen(KERN_VERSION),
416 V17, strlen(V17),
417 strlen(driver_version) -
418 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
419 }
420 #endif
421 #ifdef SD9098
422 if (cardp_sd->func->device == SD_DEVICE_ID_9098_FN1 ||
423 cardp_sd->func->device == SD_DEVICE_ID_9098_FN2) {
424 card_type = CARD_TYPE_SD9098;
425 moal_memcpy_ext(NULL, driver_version, CARD_SD9098,
426 strlen(CARD_SD9098), strlen(driver_version));
427 moal_memcpy_ext(
428 NULL,
429 driver_version + strlen(INTF_CARDTYPE) +
430 strlen(KERN_VERSION),
431 V17, strlen(V17),
432 strlen(driver_version) -
433 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
434 }
435 #endif
436 #ifdef SD9177
437 if (cardp_sd->func->device == SD_DEVICE_ID_9177) {
438 card_type = CARD_TYPE_SD9177;
439 moal_memcpy_ext(NULL, driver_version, CARD_SD9177,
440 strlen(CARD_SD9177), strlen(driver_version));
441 moal_memcpy_ext(
442 NULL,
443 driver_version + strlen(INTF_CARDTYPE) +
444 strlen(KERN_VERSION),
445 V18, strlen(V18),
446 strlen(driver_version) -
447 (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION)));
448 }
449 #endif
450 return card_type;
451 }
452
453 /** @brief This function handles client driver probe.
454 *
455 * @param func A pointer to sdio_func structure.
456 * @param id A pointer to sdio_device_id structure.
457 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code
458 */
woal_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)459 int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
460 {
461 int ret = MLAN_STATUS_SUCCESS;
462 struct sdio_mmc_card *card = NULL;
463 t_u16 card_type = 0;
464
465 ENTER();
466
467 PRINTM(MMSG, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
468 func->vendor, func->device, func->class, func->num);
469
470 card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
471 if (!card) {
472 PRINTM(MFATAL,
473 "Failed to allocate memory in probe function!\n");
474 LEAVE();
475 return -ENOMEM;
476 }
477
478 card->func = func;
479
480 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
481 /* The byte mode patch is available in kernel MMC driver
482 * which fixes one issue in MP-A transfer.
483 * bit1: use func->cur_blksize for byte mode
484 */
485 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
486 #endif
487 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
488 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
489 #endif
490
491 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
492 /* wait for chip fully wake up */
493 if (!func->enable_timeout)
494 func->enable_timeout = 200;
495 #endif
496 sdio_claim_host(func);
497 ret = sdio_enable_func(func);
498 if (ret) {
499 sdio_release_host(func);
500 PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
501 ret = -EIO;
502 goto err;
503 }
504 sdio_release_host(func);
505
506 card_type = woal_update_card_type(card);
507 if (!card_type) {
508 PRINTM(MERROR, "sdmmc probe: woal_update_card_type() failed\n");
509 ret = MLAN_STATUS_FAILURE;
510 goto err;
511 }
512
513 if (NULL ==
514 woal_add_card(card, &card->func->dev, &sdiommc_ops, card_type)) {
515 PRINTM(MMSG, "woal_add_card failed\n");
516 ret = MLAN_STATUS_FAILURE;
517 goto err;
518 }
519
520 #ifdef IMX_SUPPORT
521 woal_regist_oob_wakeup_irq(card->handle);
522 #endif /* IMX_SUPPORT */
523
524 LEAVE();
525 return ret;
526 err:
527 kfree(card);
528 sdio_claim_host(func);
529 sdio_disable_func(func);
530 sdio_release_host(func);
531
532 LEAVE();
533 return ret;
534 }
535
536 /** @brief This function handles client driver remove.
537 *
538 * @param func A pointer to sdio_func structure.
539 * @return N/A
540 */
woal_sdio_remove(struct sdio_func * func)541 void woal_sdio_remove(struct sdio_func *func)
542 {
543 struct sdio_mmc_card *card;
544
545 ENTER();
546
547 if (func) {
548 PRINTM(MINFO, "SDIO func=%d\n", func->num);
549 card = sdio_get_drvdata(func);
550 if (card) {
551 #ifdef IMX_SUPPORT
552 woal_unregist_oob_wakeup_irq(card->handle);
553 #endif /* IMX_SUPPORT */
554 woal_remove_card(card);
555 kfree(card);
556 }
557 }
558
559 LEAVE();
560 }
561
562 #ifdef SDIO_SUSPEND_RESUME
563 #ifdef MMC_PM_KEEP_POWER
564 #ifdef MMC_PM_FUNC_SUSPENDED
565 /** @brief This function tells lower driver that WLAN is suspended
566 *
567 * @param handle A Pointer to the moal_handle structure
568 * @return N/A
569 */
woal_wlan_is_suspended(moal_handle * handle)570 void woal_wlan_is_suspended(moal_handle *handle)
571 {
572 ENTER();
573 if (handle->suspend_notify_req == MTRUE) {
574 handle->is_suspended = MTRUE;
575 sdio_func_suspended(
576 ((struct sdio_mmc_card *)handle->card)->func);
577 }
578 LEAVE();
579 }
580 #endif
581
582 /** @brief This function handles client driver shutdown
583 *
584 * @param dev A pointer to device structure
585 * @return N/A
586 */
woal_sdio_shutdown(struct device * dev)587 void woal_sdio_shutdown(struct device *dev)
588 {
589 struct sdio_func *func = dev_to_sdio_func(dev);
590 moal_handle *handle = NULL;
591 struct sdio_mmc_card *cardp;
592 mlan_ds_ps_info pm_info;
593 int i, retry_num = 8;
594
595 ENTER();
596 PRINTM(MCMND, "<--- Enter woal_sdio_shutdown --->\n");
597 cardp = sdio_get_drvdata(func);
598 if (!cardp || !cardp->handle) {
599 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
600 LEAVE();
601 return;
602 }
603 handle = cardp->handle;
604 for (i = 0; i < handle->priv_num; i++)
605 netif_device_detach(handle->priv[i]->netdev);
606
607 if (moal_extflg_isset(handle, EXT_SHUTDOWN_HS)) {
608 handle->shutdown_hs_in_process = MTRUE;
609 memset(&pm_info, 0, sizeof(pm_info));
610 for (i = 0; i < retry_num; i++) {
611 if (MLAN_STATUS_SUCCESS ==
612 woal_get_pm_info(woal_get_priv(handle,
613 MLAN_BSS_ROLE_ANY),
614 &pm_info)) {
615 if (pm_info.is_suspend_allowed == MTRUE)
616 break;
617 else
618 PRINTM(MMSG,
619 "Shutdown not allowed and retry again\n");
620 }
621 woal_sched_timeout(100);
622 }
623 if (pm_info.is_suspend_allowed == MFALSE) {
624 PRINTM(MMSG, "Shutdown not allowed\n");
625 goto done;
626 }
627 woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
628
629 wait_event_interruptible_timeout(
630 handle->hs_activate_wait_q,
631 handle->hs_activate_wait_q_woken, HS_ACTIVE_TIMEOUT);
632 if (handle->hs_activated == MTRUE)
633 PRINTM(MMSG, "HS actived in shutdown\n");
634 else
635 PRINTM(MMSG, "Fail to enable HS in shutdown\n");
636 } else {
637 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
638 if (handle->priv[i]) {
639 if (handle->priv[i]->media_connected == MTRUE
640 #ifdef UAP_SUPPORT
641 || (GET_BSS_ROLE(handle->priv[i]) ==
642 MLAN_BSS_ROLE_UAP)
643 #endif
644 ) {
645 PRINTM(MIOCTL,
646 "disconnect on suspend\n");
647 woal_disconnect(handle->priv[i],
648 MOAL_NO_WAIT, NULL,
649 DEF_DEAUTH_REASON_CODE);
650 }
651 }
652 }
653 }
654
655 done:
656 PRINTM(MCMND, "<--- Leave woal_sdio_shutdown --->\n");
657 LEAVE();
658 return;
659 }
660
661 /** @brief This function handles client driver suspend
662 *
663 * @param dev A pointer to device structure
664 * @return MLAN_STATUS_SUCCESS or error code
665 */
woal_sdio_suspend(struct device * dev)666 int woal_sdio_suspend(struct device *dev)
667 {
668 struct sdio_func *func = dev_to_sdio_func(dev);
669 mmc_pm_flag_t pm_flags = 0;
670 moal_handle *handle = NULL;
671 struct sdio_mmc_card *cardp;
672 int i, retry_num = 8;
673 int ret = MLAN_STATUS_SUCCESS;
674 int hs_actived = 0;
675 mlan_ds_ps_info pm_info;
676
677 ENTER();
678 PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n");
679 pm_flags = sdio_get_host_pm_caps(func);
680 PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
681 pm_flags);
682 cardp = sdio_get_drvdata(func);
683 if (!cardp || !cardp->handle) {
684 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
685 LEAVE();
686 return MLAN_STATUS_SUCCESS;
687 }
688
689 handle = cardp->handle;
690
691 if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER) &&
692 !(pm_flags & MMC_PM_KEEP_POWER)) {
693 PRINTM(MERROR,
694 "%s: cannot remain alive while host is suspended\n",
695 sdio_func_id(func));
696 LEAVE();
697 return -ENOSYS;
698 }
699 if (handle->is_suspended == MTRUE) {
700 PRINTM(MWARN, "Device already suspended\n");
701 LEAVE();
702 return MLAN_STATUS_SUCCESS;
703 }
704 if (handle->fw_dump) {
705 PRINTM(MMSG, "suspend not allowed while FW dump!");
706 ret = -EBUSY;
707 goto done;
708 }
709 #ifdef STA_SUPPORT
710 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
711 if (handle->priv[i] &&
712 (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
713 woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
714 }
715 #endif
716 handle->suspend_fail = MFALSE;
717 memset(&pm_info, 0, sizeof(pm_info));
718 for (i = 0; i < retry_num; i++) {
719 if (MLAN_STATUS_SUCCESS ==
720 woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
721 &pm_info)) {
722 if (pm_info.is_suspend_allowed == MTRUE)
723 break;
724 else
725 PRINTM(MMSG,
726 "Suspend not allowed and retry again\n");
727 }
728 woal_sched_timeout(100);
729 }
730 if (pm_info.is_suspend_allowed == MFALSE) {
731 PRINTM(MMSG, "Suspend not allowed\n");
732 ret = -EBUSY;
733 goto done;
734 }
735
736 for (i = 0; i < handle->priv_num; i++)
737 netif_device_detach(handle->priv[i]->netdev);
738
739 if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER)) {
740 /* Enable the Host Sleep */
741 #ifdef MMC_PM_FUNC_SUSPENDED
742 handle->suspend_notify_req = MTRUE;
743 #endif
744 hs_actived = woal_enable_hs(
745 woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
746 #ifdef MMC_PM_FUNC_SUSPENDED
747 handle->suspend_notify_req = MFALSE;
748 #endif
749 if (hs_actived) {
750 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 4)
751 if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
752 ret = sdio_set_host_pm_flags(
753 func, MMC_PM_WAKE_SDIO_IRQ);
754 PRINTM(MCMND,
755 "suspend with MMC_PM_WAKE_SDIO_IRQ ret=%d\n",
756 ret);
757 }
758 #endif
759 #ifdef MMC_PM_SKIP_RESUME_PROBE
760 PRINTM(MCMND,
761 "suspend with MMC_PM_KEEP_POWER and MMC_PM_SKIP_RESUME_PROBE\n");
762 ret = sdio_set_host_pm_flags(
763 func,
764 MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE);
765 #else
766 PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n");
767 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
768 #endif
769 } else {
770 PRINTM(MMSG, "HS not actived, suspend fail!");
771 handle->suspend_fail = MTRUE;
772 for (i = 0; i < handle->priv_num; i++)
773 netif_device_attach(handle->priv[i]->netdev);
774 ret = -EBUSY;
775 goto done;
776 }
777 }
778
779 /* Indicate device suspended */
780 handle->is_suspended = MTRUE;
781 #ifdef IMX_SUPPORT
782 woal_enable_oob_wakeup_irq(handle);
783 #endif /* IMX_SUPPORT */
784 done:
785 PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n");
786 LEAVE();
787 return ret;
788 }
789
790 /** @brief This function handles client driver resume
791 *
792 * @param dev A pointer to device structure
793 * @return MLAN_STATUS_SUCCESS
794 */
woal_sdio_resume(struct device * dev)795 int woal_sdio_resume(struct device *dev)
796 {
797 struct sdio_func *func = dev_to_sdio_func(dev);
798 mmc_pm_flag_t pm_flags = 0;
799 moal_handle *handle = NULL;
800 struct sdio_mmc_card *cardp;
801 int i;
802
803 ENTER();
804 PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n");
805 pm_flags = sdio_get_host_pm_caps(func);
806 PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func),
807 pm_flags);
808 cardp = sdio_get_drvdata(func);
809 if (!cardp || !cardp->handle) {
810 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
811 LEAVE();
812 return MLAN_STATUS_SUCCESS;
813 }
814 handle = cardp->handle;
815
816 if (handle->is_suspended == MFALSE) {
817 PRINTM(MWARN, "Device already resumed\n");
818 LEAVE();
819 return MLAN_STATUS_SUCCESS;
820 }
821 handle->is_suspended = MFALSE;
822 if (woal_check_driver_status(handle)) {
823 PRINTM(MERROR, "Resuem, device is in hang state\n");
824 LEAVE();
825 return MLAN_STATUS_SUCCESS;
826 }
827 for (i = 0; i < handle->priv_num; i++)
828 netif_device_attach(handle->priv[i]->netdev);
829
830 /* Disable Host Sleep */
831 woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
832 #ifdef IMX_SUPPORT
833 woal_disable_oob_wakeup_irq(handle);
834 #endif /* IMX_SUPPORT */
835 PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n");
836 LEAVE();
837 return MLAN_STATUS_SUCCESS;
838 }
839 #endif
840 #endif /* SDIO_SUSPEND_RESUME */
841
842 /**
843 * @brief This function writes data into card register
844 *
845 * @param handle A Pointer to the moal_handle structure
846 * @param reg Register offset
847 * @param data Value
848 *
849 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
850 */
woal_sdiommc_write_reg(moal_handle * handle,t_u32 reg,t_u32 data)851 static mlan_status woal_sdiommc_write_reg(moal_handle *handle, t_u32 reg,
852 t_u32 data)
853 {
854 mlan_status ret = MLAN_STATUS_FAILURE;
855 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
856 sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data,
857 reg, (int *)&ret);
858 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
859 return ret;
860 }
861
862 /**
863 * @brief This function reads data from card register
864 *
865 * @param handle A Pointer to the moal_handle structure
866 * @param reg Register offset
867 * @param data Value
868 *
869 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
870 */
woal_sdiommc_read_reg(moal_handle * handle,t_u32 reg,t_u32 * data)871 static mlan_status woal_sdiommc_read_reg(moal_handle *handle, t_u32 reg,
872 t_u32 *data)
873 {
874 mlan_status ret = MLAN_STATUS_FAILURE;
875 t_u8 val;
876 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
877 val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
878 (int *)&ret);
879 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
880 *data = val;
881
882 return ret;
883 }
884
885 /**
886 * @brief This function writes data into card register
887 *
888 * @param handle A Pointer to the moal_handle structure
889 * @param reg Register offset
890 * @param data Value
891 *
892 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
893 */
woal_sdio_writeb(moal_handle * handle,t_u32 reg,t_u8 data)894 static mlan_status woal_sdio_writeb(moal_handle *handle, t_u32 reg, t_u8 data)
895 {
896 mlan_status ret = MLAN_STATUS_FAILURE;
897 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
898 sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data,
899 reg, (int *)&ret);
900 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
901 return ret;
902 }
903
904 /**
905 * @brief This function reads data from card register
906 *
907 * @param handle A Pointer to the moal_handle structure
908 * @param reg Register offset
909 * @param data Value
910 *
911 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
912 */
woal_sdio_readb(moal_handle * handle,t_u32 reg,t_u8 * data)913 static mlan_status woal_sdio_readb(moal_handle *handle, t_u32 reg, t_u8 *data)
914 {
915 mlan_status ret = MLAN_STATUS_FAILURE;
916 t_u8 val;
917 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
918 val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
919 (int *)&ret);
920 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
921 *data = val;
922
923 return ret;
924 }
925
926 /**
927 * @brief This function reads data from card register FN0
928 *
929 * @param handle A Pointer to the moal_handle structure
930 * @param reg Register offset
931 * @param data Value
932 *
933 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
934 */
woal_sdio_f0_readb(moal_handle * handle,t_u32 reg,t_u8 * data)935 static mlan_status woal_sdio_f0_readb(moal_handle *handle, t_u32 reg,
936 t_u8 *data)
937 {
938 mlan_status ret = MLAN_STATUS_FAILURE;
939 t_u8 val;
940 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
941 val = sdio_f0_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
942 (int *)&ret);
943 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
944 *data = val;
945
946 return ret;
947 }
948
949 /**
950 * @brief This function use SG mode to read/write data into card memory
951 *
952 * @param handle A Pointer to the moal_handle structure
953 * @param pmbuf_list Pointer to a linked list of mlan_buffer structure
954 * @param port Port
955 * @param write write flag
956 *
957 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
958 */
woal_sdio_rw_mb(moal_handle * handle,pmlan_buffer pmbuf_list,t_u32 port,t_u8 write)959 static mlan_status woal_sdio_rw_mb(moal_handle *handle, pmlan_buffer pmbuf_list,
960 t_u32 port, t_u8 write)
961 {
962 struct scatterlist sg_list[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX];
963 int num_sg = pmbuf_list->use_count;
964 int i = 0;
965 mlan_buffer *pmbuf = NULL;
966 struct mmc_request mmc_req;
967 struct mmc_command mmc_cmd;
968 struct mmc_data mmc_dat;
969 struct sdio_func *func = ((struct sdio_mmc_card *)handle->card)->func;
970 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
971 t_u32 blkcnt = pmbuf_list->data_len / MLAN_SDIO_BLOCK_SIZE;
972 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
973 int status;
974 #endif
975
976 if (num_sg > SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX) {
977 PRINTM(MERROR, "ERROR: num_sg=%d", num_sg);
978 return MLAN_STATUS_FAILURE;
979 }
980 sg_init_table(sg_list, num_sg);
981 pmbuf = pmbuf_list->pnext;
982 for (i = 0; i < num_sg; i++) {
983 if (pmbuf == pmbuf_list)
984 break;
985 sg_set_buf(&sg_list[i], pmbuf->pbuf + pmbuf->data_offset,
986 pmbuf->data_len);
987 pmbuf = pmbuf->pnext;
988 }
989 memset(&mmc_req, 0, sizeof(struct mmc_request));
990 memset(&mmc_cmd, 0, sizeof(struct mmc_command));
991 memset(&mmc_dat, 0, sizeof(struct mmc_data));
992
993 mmc_dat.sg = sg_list;
994 mmc_dat.sg_len = num_sg;
995 mmc_dat.blksz = MLAN_SDIO_BLOCK_SIZE;
996 mmc_dat.blocks = blkcnt;
997 mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
998
999 mmc_cmd.opcode = SD_IO_RW_EXTENDED;
1000 mmc_cmd.arg = write ? 1 << 31 : 0;
1001 mmc_cmd.arg |= (func->num & 0x7) << 28;
1002 mmc_cmd.arg |= 1 << 27; /* block basic */
1003 mmc_cmd.arg |= 0; /* fix address */
1004 mmc_cmd.arg |= (ioport & 0x1FFFF) << 9;
1005 mmc_cmd.arg |= blkcnt & 0x1FF;
1006 mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
1007
1008 mmc_req.cmd = &mmc_cmd;
1009 mmc_req.data = &mmc_dat;
1010
1011 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
1012 mmc_set_data_timeout(
1013 &mmc_dat, ((struct sdio_mmc_card *)handle->card)->func->card);
1014 mmc_wait_for_req(
1015 ((struct sdio_mmc_card *)handle->card)->func->card->host,
1016 &mmc_req);
1017
1018 if (mmc_cmd.error || mmc_dat.error) {
1019 PRINTM(MERROR, "CMD53 %s cmd_error = %d data_error=%d\n",
1020 write ? "write" : "read", mmc_cmd.error, mmc_dat.error);
1021 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
1022 /* issue abort cmd52 command through F0*/
1023 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
1024 0x01, SDIO_CCCR_ABORT, &status);
1025 #endif
1026 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
1027 return MLAN_STATUS_FAILURE;
1028 }
1029 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
1030 return MLAN_STATUS_SUCCESS;
1031 }
1032
1033 /**
1034 * @brief This function writes multiple bytes into card memory
1035 *
1036 * @param handle A Pointer to the moal_handle structure
1037 * @param pmbuf Pointer to mlan_buffer structure
1038 * @param port Port
1039 * @param timeout Time out value
1040 *
1041 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1042 */
woal_sdiommc_write_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 port,t_u32 timeout)1043 static mlan_status woal_sdiommc_write_data_sync(moal_handle *handle,
1044 mlan_buffer *pmbuf, t_u32 port,
1045 t_u32 timeout)
1046 {
1047 mlan_status ret = MLAN_STATUS_FAILURE;
1048 t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
1049 t_u8 blkmode =
1050 (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
1051 t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
1052 t_u32 blkcnt = (blkmode == BLOCK_MODE) ?
1053 (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) :
1054 pmbuf->data_len;
1055 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
1056 int status = 0;
1057 if (pmbuf->use_count > 1)
1058 return woal_sdio_rw_mb(handle, pmbuf, port, MTRUE);
1059 #ifdef SDIO_MMC_DEBUG
1060 handle->cmd53w = 1;
1061 #endif
1062 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
1063 status = sdio_writesb(((struct sdio_mmc_card *)handle->card)->func,
1064 ioport, buffer, blkcnt * blksz);
1065 if (!status)
1066 ret = MLAN_STATUS_SUCCESS;
1067 else {
1068 PRINTM(MERROR, "cmd53 write error=%d\n", status);
1069 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
1070 /* issue abort cmd52 command through F0*/
1071 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
1072 0x01, SDIO_CCCR_ABORT, &status);
1073 #endif
1074 }
1075 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
1076 #ifdef SDIO_MMC_DEBUG
1077 handle->cmd53w = 2;
1078 #endif
1079 return ret;
1080 }
1081
1082 /**
1083 * @brief This function reads multiple bytes from card memory
1084 *
1085 * @param handle A Pointer to the moal_handle structure
1086 * @param pmbuf Pointer to mlan_buffer structure
1087 * @param port Port
1088 * @param timeout Time out value
1089 *
1090 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1091 */
woal_sdiommc_read_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 port,t_u32 timeout)1092 static mlan_status woal_sdiommc_read_data_sync(moal_handle *handle,
1093 mlan_buffer *pmbuf, t_u32 port,
1094 t_u32 timeout)
1095 {
1096 mlan_status ret = MLAN_STATUS_FAILURE;
1097 t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
1098 t_u8 blkmode =
1099 (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
1100 t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
1101 t_u32 blkcnt = (blkmode == BLOCK_MODE) ?
1102 (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) :
1103 pmbuf->data_len;
1104 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
1105 int status = 0;
1106 if (pmbuf->use_count > 1)
1107 return woal_sdio_rw_mb(handle, pmbuf, port, MFALSE);
1108 #ifdef SDIO_MMC_DEBUG
1109 handle->cmd53r = 1;
1110 #endif
1111 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
1112 status = sdio_readsb(((struct sdio_mmc_card *)handle->card)->func,
1113 buffer, ioport, blkcnt * blksz);
1114 if (!status) {
1115 ret = MLAN_STATUS_SUCCESS;
1116 } else {
1117 PRINTM(MERROR, "cmd53 read error=%d\n", status);
1118 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
1119 /* issue abort cmd52 command through F0*/
1120 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
1121 0x01, SDIO_CCCR_ABORT, &status);
1122 #endif
1123 }
1124 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
1125 #ifdef SDIO_MMC_DEBUG
1126 handle->cmd53r = 2;
1127 #endif
1128 return ret;
1129 }
1130
1131 /**
1132 * @brief This function registers the IF module in bus driver
1133 *
1134 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1135 */
woal_sdiommc_bus_register(void)1136 mlan_status woal_sdiommc_bus_register(void)
1137 {
1138 mlan_status ret = MLAN_STATUS_SUCCESS;
1139
1140 ENTER();
1141
1142 /* SDIO Driver Registration */
1143 if (sdio_register_driver(&wlan_sdio)) {
1144 PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
1145 LEAVE();
1146 return MLAN_STATUS_FAILURE;
1147 }
1148
1149 LEAVE();
1150 return ret;
1151 }
1152
1153 /**
1154 * @brief This function de-registers the IF module in bus driver
1155 *
1156 * @return N/A
1157 */
woal_sdiommc_bus_unregister(void)1158 void woal_sdiommc_bus_unregister(void)
1159 {
1160 ENTER();
1161
1162 /* SDIO Driver Unregistration */
1163 sdio_unregister_driver(&wlan_sdio);
1164
1165 LEAVE();
1166 }
1167
1168 /**
1169 * @brief This function de-registers the device
1170 *
1171 * @param handle A pointer to moal_handle structure
1172 * @return N/A
1173 */
woal_sdiommc_unregister_dev(moal_handle * handle)1174 static void woal_sdiommc_unregister_dev(moal_handle *handle)
1175 {
1176 ENTER();
1177 if (handle->card) {
1178 struct sdio_mmc_card *card = handle->card;
1179 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
1180 struct sdio_func *func = card->func;
1181 #endif
1182 /* Release the SDIO IRQ */
1183 sdio_claim_host(card->func);
1184 sdio_release_irq(card->func);
1185 sdio_disable_func(card->func);
1186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
1187 if (handle->driver_status)
1188 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
1189 mmc_hw_reset(func->card);
1190 #else
1191 mmc_hw_reset(func->card->host);
1192 #endif
1193 #endif
1194 sdio_release_host(card->func);
1195
1196 sdio_set_drvdata(card->func, NULL);
1197
1198 PRINTM(MWARN, "Making the sdio dev card as NULL\n");
1199 card->handle = NULL;
1200 }
1201
1202 LEAVE();
1203 }
1204
1205 /**
1206 * @brief This function registers the device
1207 *
1208 * @param handle A pointer to moal_handle structure
1209 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1210 */
woal_sdiommc_register_dev(moal_handle * handle)1211 static mlan_status woal_sdiommc_register_dev(moal_handle *handle)
1212 {
1213 int ret = MLAN_STATUS_SUCCESS;
1214 struct sdio_mmc_card *card = handle->card;
1215 struct sdio_func *func;
1216
1217 ENTER();
1218
1219 /* save adapter pointer in card */
1220 card->handle = handle;
1221 func = card->func;
1222 sdio_claim_host(func);
1223 /* Request the SDIO IRQ */
1224 ret = sdio_claim_irq(func, woal_sdio_interrupt);
1225 if (ret) {
1226 PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
1227 goto release_host;
1228 }
1229
1230 /* Set block size */
1231 ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
1232 if (ret) {
1233 PRINTM(MERROR,
1234 "sdio_set_block_seize(): cannot set SDIO block size\n");
1235 ret = MLAN_STATUS_FAILURE;
1236 goto release_irq;
1237 }
1238
1239 sdio_release_host(func);
1240 sdio_set_drvdata(func, card);
1241
1242 LEAVE();
1243 return MLAN_STATUS_SUCCESS;
1244
1245 release_irq:
1246 sdio_release_irq(func);
1247 release_host:
1248 sdio_release_host(func);
1249 handle->card = NULL;
1250
1251 LEAVE();
1252 return MLAN_STATUS_FAILURE;
1253 }
1254
1255 /**
1256 * @brief This function set bus clock on/off
1257 *
1258 * @param handle A pointer to moal_handle structure
1259 * @param option TRUE--on , FALSE--off
1260 * @return MLAN_STATUS_SUCCESS
1261 */
woal_sdio_set_bus_clock(moal_handle * handle,t_u8 option)1262 int woal_sdio_set_bus_clock(moal_handle *handle, t_u8 option)
1263 {
1264 struct sdio_mmc_card *cardp = (struct sdio_mmc_card *)handle->card;
1265 struct mmc_host *host = cardp->func->card->host;
1266
1267 ENTER();
1268 if (option == MTRUE) {
1269 /* restore value if non-zero */
1270 if (cardp->host_clock)
1271 host->ios.clock = cardp->host_clock;
1272 } else {
1273 /* backup value if non-zero, then clear */
1274 if (host->ios.clock)
1275 cardp->host_clock = host->ios.clock;
1276 host->ios.clock = 0;
1277 }
1278
1279 host->ops->set_ios(host, &host->ios);
1280 LEAVE();
1281 return MLAN_STATUS_SUCCESS;
1282 }
1283
1284 /**
1285 * @brief This function updates card reg based on the Cmd52 value in dev
1286 * structure
1287 *
1288 * @param handle A pointer to moal_handle structure
1289 * @param func A pointer to store func variable
1290 * @param reg A pointer to store reg variable
1291 * @param val A pointer to store val variable
1292 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1293 */
woal_sdio_read_write_cmd52(moal_handle * handle,int func,int reg,int val)1294 int woal_sdio_read_write_cmd52(moal_handle *handle, int func, int reg, int val)
1295 {
1296 int ret = MLAN_STATUS_SUCCESS;
1297 struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
1298
1299 ENTER();
1300 /* Save current func and reg for read */
1301 handle->cmd52_func = func;
1302 handle->cmd52_reg = reg;
1303 sdio_claim_host(card->func);
1304 if (val >= 0) {
1305 /* Perform actual write only if val is provided */
1306 if (func)
1307 sdio_writeb(card->func, val, reg, &ret);
1308 else
1309 sdio_f0_writeb(card->func, val, reg, &ret);
1310 if (ret) {
1311 PRINTM(MERROR,
1312 "Cannot write value (0x%x) to func %d reg 0x%x\n",
1313 val, func, reg);
1314 } else {
1315 PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n",
1316 (u8)val, func, reg);
1317 handle->cmd52_val = val;
1318 }
1319 } else {
1320 if (func)
1321 val = sdio_readb(card->func, reg, &ret);
1322 else
1323 val = sdio_f0_readb(card->func, reg, &ret);
1324 if (ret) {
1325 PRINTM(MERROR,
1326 "Cannot read value from func %d reg 0x%x\n",
1327 func, reg);
1328 } else {
1329 PRINTM(MMSG,
1330 "read value (0x%x) from func %d reg 0x%x\n",
1331 (u8)val, func, reg);
1332 handle->cmd52_val = val;
1333 }
1334 }
1335 sdio_release_host(card->func);
1336 LEAVE();
1337 return ret;
1338 }
1339
1340 /**
1341 * @brief This function check if this is second mac
1342 *
1343 * @param handle A pointer to moal_handle structure
1344 * @return MTRUE/MFALSE
1345 *
1346 */
woal_sdiommc_is_second_mac(moal_handle * handle)1347 static t_u8 woal_sdiommc_is_second_mac(moal_handle *handle)
1348 {
1349 #ifdef SD9098
1350 struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
1351 if (card->func->device == SD_DEVICE_ID_9098_FN2)
1352 return MTRUE;
1353 #endif
1354 return MFALSE;
1355 }
1356
woal_sdiommc_get_fw_name(moal_handle * handle)1357 static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle)
1358 {
1359 mlan_status ret = MLAN_STATUS_SUCCESS;
1360 #ifdef SD9098
1361 struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
1362 #endif
1363 t_u32 revision_id = 0;
1364 t_u32 rev_id_reg = handle->card_info->rev_id_reg;
1365
1366 #if defined(SD8987) || defined(SD8997) || defined(SD9098) || \
1367 defined(SD9097) || defined(SDNW62X) || defined(SD8978) || \
1368 defined(SD9177)
1369 t_u32 magic_reg = handle->card_info->magic_reg;
1370 t_u32 magic = 0;
1371 t_u32 host_strap_reg = handle->card_info->host_strap_reg;
1372 t_u32 strap = 0;
1373 #endif
1374
1375 ENTER();
1376
1377 if (handle->params.fw_name)
1378 goto done;
1379 #ifdef SD8801
1380 if (IS_SD8801(handle->card_type))
1381 goto done;
1382 #endif
1383 /** Revision ID register */
1384 woal_sdiommc_read_reg(handle, rev_id_reg, &revision_id);
1385 PRINTM(MCMND, "revision_id=0x%x\n", revision_id);
1386
1387 #if defined(SD8987) || defined(SD8997) || defined(SD9098) || \
1388 defined(SD9097) || defined(SDNW62X) || defined(SD8978) || \
1389 defined(SD9177)
1390 /** Revision ID register */
1391 woal_sdiommc_read_reg(handle, magic_reg, &magic);
1392 /** Revision ID register */
1393 woal_sdiommc_read_reg(handle, host_strap_reg, &strap);
1394 strap &= 0x1;
1395 magic &= 0xFF;
1396 /* 1 = SDSD, 0 --SD UART */
1397 PRINTM(MCMND, "magic=0x%x strap=0x%x\n", magic, strap);
1398 #endif
1399 #if defined(SD8977)
1400 if (IS_SD8977(handle->card_type)) {
1401 switch (revision_id) {
1402 case SD8977_V0:
1403 strcpy(handle->card_info->fw_name, SD8977_V0_FW_NAME);
1404 strcpy(handle->card_info->fw_name_wlan,
1405 SD8977_WLAN_V0_FW_NAME);
1406 break;
1407 case SD8977_V1:
1408 strcpy(handle->card_info->fw_name, SD8977_V1_FW_NAME);
1409 strcpy(handle->card_info->fw_name_wlan,
1410 SD8977_WLAN_V1_FW_NAME);
1411 break;
1412 case SD8977_V2:
1413 strcpy(handle->card_info->fw_name, SD8977_V2_FW_NAME);
1414 strcpy(handle->card_info->fw_name_wlan,
1415 SD8977_WLAN_V2_FW_NAME);
1416 break;
1417 default:
1418 break;
1419 }
1420 }
1421 #endif
1422 #if defined(SD8887)
1423 if (IS_SD8887(handle->card_type)) {
1424 /* Check revision ID */
1425 switch (revision_id) {
1426 case SD8887_A0:
1427 strcpy(handle->card_info->fw_name, SD8887_A0_FW_NAME);
1428 strcpy(handle->card_info->fw_name_wlan,
1429 SD8887_WLAN_A0_FW_NAME);
1430 break;
1431 case SD8887_A2:
1432 strcpy(handle->card_info->fw_name, SD8887_A2_FW_NAME);
1433 strcpy(handle->card_info->fw_name_wlan,
1434 SD8887_WLAN_A2_FW_NAME);
1435 break;
1436 default:
1437 break;
1438 }
1439 }
1440 #endif
1441
1442 #ifdef SD8997
1443 if (IS_SD8997(handle->card_type)) {
1444 if (magic == CHIP_MAGIC_VALUE) {
1445 if (strap == CARD_TYPE_SD_UART)
1446 strcpy(handle->card_info->fw_name,
1447 SDUART8997_DEFAULT_COMBO_FW_NAME);
1448 else
1449 strcpy(handle->card_info->fw_name,
1450 SDSD8997_DEFAULT_COMBO_FW_NAME);
1451 }
1452 }
1453 #endif
1454
1455 #ifdef SD8987
1456 if (IS_SD8987(handle->card_type)) {
1457 if (magic == CHIP_MAGIC_VALUE) {
1458 if (strap == CARD_TYPE_SD_UART)
1459 strcpy(handle->card_info->fw_name,
1460 SDUART8987_DEFAULT_COMBO_FW_NAME);
1461 else
1462 strcpy(handle->card_info->fw_name,
1463 SDSD8987_DEFAULT_COMBO_FW_NAME);
1464 }
1465 }
1466 #endif
1467
1468 #ifdef SD8978
1469 if (IS_SD8978(handle->card_type)) {
1470 if (magic == CHIP_MAGIC_VALUE) {
1471 if (strap == CARD_TYPE_SD_UART)
1472 strcpy(handle->card_info->fw_name,
1473 SDUART8978_DEFAULT_COMBO_FW_NAME);
1474 else
1475 strcpy(handle->card_info->fw_name,
1476 SDSD8978_DEFAULT_COMBO_FW_NAME);
1477 }
1478 }
1479 #endif
1480
1481 #ifdef SD9098
1482 if (IS_SD9098(handle->card_type) &&
1483 (card->func->device == SD_DEVICE_ID_9098_FN1)) {
1484 switch (revision_id) {
1485 case SD9098_Z1Z2:
1486 if (magic == CHIP_MAGIC_VALUE) {
1487 if (strap == CARD_TYPE_SD_UART)
1488 strcpy(handle->card_info->fw_name,
1489 SDUART9098_DEFAULT_COMBO_FW_NAME);
1490 else
1491 strcpy(handle->card_info->fw_name,
1492 SDSD9098_DEFAULT_COMBO_FW_NAME);
1493 }
1494 strcpy(handle->card_info->fw_name_wlan,
1495 SD9098_DEFAULT_WLAN_FW_NAME);
1496 break;
1497 case SD9098_A0:
1498 case SD9098_A1:
1499 case SD9098_A2:
1500 if (magic == CHIP_MAGIC_VALUE) {
1501 if (strap == CARD_TYPE_SD_UART)
1502 strcpy(handle->card_info->fw_name,
1503 SDUART9098_COMBO_V1_FW_NAME);
1504 else
1505 strcpy(handle->card_info->fw_name,
1506 SDSD9098_COMBO_V1_FW_NAME);
1507 }
1508 strcpy(handle->card_info->fw_name_wlan,
1509 SD9098_WLAN_V1_FW_NAME);
1510 break;
1511 default:
1512 break;
1513 }
1514 }
1515 #endif
1516 #ifdef SD9097
1517 if (IS_SD9097(handle->card_type)) {
1518 switch (revision_id) {
1519 case SD9097_B0:
1520 case SD9097_B1:
1521 if (magic == CHIP_MAGIC_VALUE) {
1522 if (strap == CARD_TYPE_SD_UART)
1523 strcpy(handle->card_info->fw_name,
1524 SDUART9097_COMBO_V1_FW_NAME);
1525 else
1526 strcpy(handle->card_info->fw_name,
1527 SDSD9097_COMBO_V1_FW_NAME);
1528 }
1529 strcpy(handle->card_info->fw_name_wlan,
1530 SD9097_WLAN_V1_FW_NAME);
1531 break;
1532 default:
1533 break;
1534 }
1535 }
1536 #endif
1537 #ifdef SDNW62X
1538 if (IS_SDNW62X(handle->card_type)) {
1539 if (magic == CHIP_MAGIC_VALUE) {
1540 if (strap == CARD_TYPE_SD_UART)
1541 strcpy(handle->card_info->fw_name,
1542 SDUARTNW62X_COMBO_FW_NAME);
1543 else
1544 strcpy(handle->card_info->fw_name,
1545 SDSDNW62X_COMBO_FW_NAME);
1546 }
1547 }
1548 #endif
1549
1550 #ifdef SD9177
1551 if (IS_SD9177(handle->card_type)) {
1552 switch (revision_id) {
1553 case SD9177_A0:
1554 if (magic == CHIP_MAGIC_VALUE) {
1555 if (strap == CARD_TYPE_SD9177_UART)
1556 strcpy(handle->card_info->fw_name,
1557 SDUART9177_DEFAULT_COMBO_FW_NAME);
1558 else
1559 strcpy(handle->card_info->fw_name,
1560 SDSD9177_DEFAULT_COMBO_FW_NAME);
1561 }
1562 strcpy(handle->card_info->fw_name_wlan,
1563 SD9177_DEFAULT_WLAN_FW_NAME);
1564 break;
1565 case SD9177_A1:
1566 if (magic == CHIP_MAGIC_VALUE) {
1567 if (strap == CARD_TYPE_SD9177_UART)
1568 strcpy(handle->card_info->fw_name,
1569 SDUART9177_DEFAULT_COMBO_V1_FW_NAME);
1570 else
1571 strcpy(handle->card_info->fw_name,
1572 SDSD9177_DEFAULT_COMBO_V1_FW_NAME);
1573 }
1574 strcpy(handle->card_info->fw_name_wlan,
1575 SD9177_DEFAULT_WLAN_V1_FW_NAME);
1576 break;
1577 default:
1578 break;
1579 }
1580 }
1581 #endif
1582 done:
1583 PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name,
1584 handle->card_info->fw_name_wlan);
1585 LEAVE();
1586 return ret;
1587 }
1588
1589 #define DEBUG_FW_DONE 0xFF
1590 #define DEBUG_MEMDUMP_FINISH 0xFE
1591 #define MAX_POLL_TRIES 100
1592
1593 typedef enum {
1594 DUMP_TYPE_ITCM = 0,
1595 DUMP_TYPE_DTCM = 1,
1596 DUMP_TYPE_SQRAM = 2,
1597 DUMP_TYPE_APU_REGS = 3,
1598 DUMP_TYPE_CIU_REGS = 4,
1599 DUMP_TYPE_ICU_REGS = 5,
1600 DUMP_TYPE_MAC_REGS = 6,
1601 DUMP_TYPE_EXTEND_7 = 7,
1602 DUMP_TYPE_EXTEND_8 = 8,
1603 DUMP_TYPE_EXTEND_9 = 9,
1604 DUMP_TYPE_EXTEND_10 = 10,
1605 DUMP_TYPE_EXTEND_11 = 11,
1606 DUMP_TYPE_EXTEND_12 = 12,
1607 DUMP_TYPE_EXTEND_13 = 13,
1608 DUMP_TYPE_EXTEND_LAST = 14
1609 } dumped_mem_type;
1610
1611 #define MAX_NAME_LEN 8
1612
1613 typedef struct {
1614 t_u8 mem_name[MAX_NAME_LEN];
1615 t_u8 *mem_Ptr;
1616 struct file *pfile_mem;
1617 t_u8 done_flag;
1618 t_u8 type;
1619 } memory_type_mapping;
1620
1621 static memory_type_mapping mem_type_mapping_tbl[] = {
1622 {"ITCM", NULL, NULL, 0xF0, FW_DUMP_TYPE_MEM_ITCM},
1623 {"DTCM", NULL, NULL, 0xF1, FW_DUMP_TYPE_MEM_DTCM},
1624 {"SQRAM", NULL, NULL, 0xF2, FW_DUMP_TYPE_MEM_SQRAM},
1625 {"APU", NULL, NULL, 0xF3, FW_DUMP_TYPE_REG_APU},
1626 {"CIU", NULL, NULL, 0xF4, FW_DUMP_TYPE_REG_CIU},
1627 {"ICU", NULL, NULL, 0xF5, FW_DUMP_TYPE_REG_ICU},
1628 {"MAC", NULL, NULL, 0xF6, FW_DUMP_TYPE_REG_MAC},
1629 {"EXT7", NULL, NULL, 0xF7, 0},
1630 {"EXT8", NULL, NULL, 0xF8, 0},
1631 {"EXT9", NULL, NULL, 0xF9, 0},
1632 {"EXT10", NULL, NULL, 0xFA, 0},
1633 {"EXT11", NULL, NULL, 0xFB, 0},
1634 {"EXT12", NULL, NULL, 0xFC, 0},
1635 {"EXT13", NULL, NULL, 0xFD, 0},
1636 {"EXTLAST", NULL, NULL, 0xFE, 0},
1637 };
1638 static memory_type_mapping mem_type_mapping_tbl_8977_8997 = {"DUMP", NULL, NULL,
1639 0xDD, 0};
1640 /**
1641 * @brief This function read/write firmware via cmd52
1642 *
1643 * @param phandle A pointer to moal_handle
1644 * @param doneflag A flag
1645 *
1646 * @return MLAN_STATUS_SUCCESS
1647 */
woal_cmd52_rdwr_firmware(moal_handle * phandle,t_u8 doneflag)1648 static rdwr_status woal_cmd52_rdwr_firmware(moal_handle *phandle, t_u8 doneflag)
1649 {
1650 int ret = 0;
1651 int tries = 0;
1652 t_u8 ctrl_data = 0;
1653 t_u8 dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg;
1654 t_u8 debug_host_ready = phandle->card_info->dump_fw_host_ready;
1655
1656 #ifdef SD9177
1657 if (IS_SD9177(phandle->card_type)) {
1658 if (phandle->event_fw_dump)
1659 debug_host_ready = 0xAA;
1660 }
1661 #endif
1662 ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg, debug_host_ready);
1663 if (ret) {
1664 PRINTM(MERROR, "SDIO Write ERR\n");
1665 return RDWR_STATUS_FAILURE;
1666 }
1667 #ifdef SD9177
1668 if (IS_SD9177(phandle->card_type)) {
1669 if (phandle->event_fw_dump)
1670 return RDWR_STATUS_SUCCESS;
1671 }
1672 #endif
1673 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
1674 ret = woal_sdio_readb(phandle, dbg_dump_ctrl_reg, &ctrl_data);
1675 if (ret) {
1676 PRINTM(MERROR, "SDIO READ ERR\n");
1677 return RDWR_STATUS_FAILURE;
1678 }
1679 if (ctrl_data == DEBUG_FW_DONE)
1680 break;
1681 if (doneflag && ctrl_data == doneflag)
1682 return RDWR_STATUS_DONE;
1683 if (ctrl_data != debug_host_ready) {
1684 PRINTM(MMSG,
1685 "The ctrl reg was changed, re-try again!\n");
1686 ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg,
1687 debug_host_ready);
1688 if (ret) {
1689 PRINTM(MERROR, "SDIO Write ERR\n");
1690 return RDWR_STATUS_FAILURE;
1691 }
1692 }
1693 udelay(100);
1694 }
1695 if (ctrl_data == debug_host_ready || tries == MAX_POLL_TRIES) {
1696 PRINTM(MERROR, "Fail to pull ctrl_data\n");
1697 return RDWR_STATUS_FAILURE;
1698 }
1699 return RDWR_STATUS_SUCCESS;
1700 }
1701
1702 #ifdef SD8801
1703 #define DEBUG_HOST_READY 0xEE
1704 #define DEBUG_FW_DONE 0xFF
1705 #define DEBUG_MEMDUMP_FINISH 0xFE
1706 #define MAX_POLL_TRIES 100
1707 #define DEBUG_ITCM_DONE 0xaa
1708 #define DEBUG_DTCM_DONE 0xbb
1709 #define DEBUG_SQRAM_DONE 0xcc
1710
1711 #define DEBUG_DUMP_CTRL_REG 0x63
1712 #define DEBUG_DUMP_FIRST_REG 0x62
1713 #define DEBUG_DUMP_START_REG 0x64
1714 #define DEBUG_DUMP_END_REG 0x6a
1715 #define ITCM_SIZE 0x60000
1716 #define SQRAM_SIZE 0x33500
1717 #define DTCM_SIZE 0x14000
1718
1719 /**
1720 * @brief This function dump firmware memory to file
1721 *
1722 * @param phandle A pointer to moal_handle
1723 *
1724 * @return N/A
1725 */
woal_dump_firmware_info(moal_handle * phandle)1726 void woal_dump_firmware_info(moal_handle *phandle)
1727 {
1728 int ret = 0;
1729 unsigned int reg, reg_start, reg_end;
1730 t_u8 *ITCM_Ptr = NULL;
1731 t_u8 *DTCM_Ptr = NULL;
1732 t_u8 *SQRAM_Ptr = NULL;
1733 t_u8 *dbg_ptr = NULL;
1734 t_u32 sec, usec;
1735 t_u8 ctrl_data = 0;
1736 t_u32 dtcm_size = DTCM_SIZE;
1737 t_u32 sqram_size = SQRAM_SIZE;
1738 t_u8 *end_ptr = NULL;
1739 int tries;
1740
1741 if (!phandle) {
1742 PRINTM(MERROR, "Could not dump firmwware info\n");
1743 return;
1744 }
1745 if (!phandle->fw_dump_buf) {
1746 ret = moal_vmalloc(phandle, FW_DUMP_INFO_LEN,
1747 &(phandle->fw_dump_buf));
1748 if (ret != MLAN_STATUS_SUCCESS || !phandle->fw_dump_buf) {
1749 PRINTM(MERROR, "Failed to vmalloc fw dump bufffer\n");
1750 return;
1751 }
1752 } else {
1753 memset(phandle->fw_dump_buf, 0x00, FW_DUMP_INFO_LEN);
1754 }
1755 phandle->fw_dump_len = 0;
1756
1757 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1758 sdio_claim_host(((struct sdio_mmc_card *)phandle->card)->func);
1759 #endif
1760 /* start dump fw memory */
1761 moal_get_system_time(phandle, &sec, &usec);
1762 PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
1763 ret = moal_vmalloc(phandle, ITCM_SIZE + 1, (t_u8 **)&ITCM_Ptr);
1764 if ((ret != MLAN_STATUS_SUCCESS) || !ITCM_Ptr) {
1765 PRINTM(MERROR, "Error: vmalloc ITCM buffer failed!!!\n");
1766 goto done;
1767 }
1768
1769 PRINTM(MMSG, "DTCM_SIZE=0x%x\n", dtcm_size);
1770 ret = moal_vmalloc(phandle, dtcm_size + 1, (t_u8 **)&DTCM_Ptr);
1771 if ((ret != MLAN_STATUS_SUCCESS) || !DTCM_Ptr) {
1772 PRINTM(MERROR, "Error: vmalloc DTCM buffer failed!!!\n");
1773 goto done;
1774 }
1775 ret = moal_vmalloc(phandle, sqram_size + 1, (t_u8 **)&SQRAM_Ptr);
1776 if ((ret != MLAN_STATUS_SUCCESS) || !SQRAM_Ptr) {
1777 PRINTM(MERROR, "Error: vmalloc SQRAM buffer failed!!!\n");
1778 goto done;
1779 }
1780 dbg_ptr = ITCM_Ptr;
1781 end_ptr = ITCM_Ptr + ITCM_SIZE;
1782 moal_get_system_time(phandle, &sec, &usec);
1783 PRINTM(MMSG, "Start ITCM output %u.%06u, please wait...\n", sec, usec);
1784 reg_start = DEBUG_DUMP_START_REG;
1785 reg_end = DEBUG_DUMP_END_REG;
1786 do {
1787 ret = woal_sdio_writeb(phandle, DEBUG_DUMP_CTRL_REG,
1788 DEBUG_HOST_READY);
1789 if (ret) {
1790 PRINTM(MERROR, "SDIO Write ERR\n");
1791 goto done;
1792 }
1793 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
1794 ret = woal_sdio_readb(phandle, DEBUG_DUMP_CTRL_REG,
1795 &ctrl_data);
1796 if (ret) {
1797 PRINTM(MERROR, "SDIO READ ERR\n");
1798 goto done;
1799 }
1800 if ((ctrl_data == DEBUG_FW_DONE) ||
1801 (ctrl_data == DEBUG_ITCM_DONE) ||
1802 (ctrl_data == DEBUG_DTCM_DONE) ||
1803 (ctrl_data == DEBUG_SQRAM_DONE))
1804 break;
1805 if (ctrl_data != DEBUG_HOST_READY) {
1806 ret = woal_sdio_writeb(phandle,
1807 DEBUG_DUMP_CTRL_REG,
1808 DEBUG_HOST_READY);
1809 if (ret) {
1810 PRINTM(MERROR, "SDIO Write ERR\n");
1811 goto done;
1812 }
1813 }
1814 udelay(100);
1815 }
1816 if (ctrl_data == DEBUG_HOST_READY) {
1817 PRINTM(MERROR, "Fail to pull ctrl_data\n");
1818 goto done;
1819 }
1820 reg = DEBUG_DUMP_FIRST_REG;
1821 ret = woal_sdio_readb(phandle, reg, dbg_ptr);
1822 if (ret) {
1823 PRINTM(MMSG, "SDIO READ ERR\n");
1824 goto done;
1825 }
1826 if (dbg_ptr < end_ptr)
1827 dbg_ptr++;
1828 else {
1829 PRINTM(MINFO, "pre-allocced buf is not enough\n");
1830 goto done;
1831 }
1832 for (reg = reg_start; reg <= reg_end; reg++) {
1833 ret = woal_sdio_readb(phandle, reg, dbg_ptr);
1834 if (ret) {
1835 PRINTM(MMSG, "SDIO READ ERR\n");
1836 goto done;
1837 }
1838 if (dbg_ptr < end_ptr)
1839 dbg_ptr++;
1840 else
1841 PRINTM(MINFO,
1842 "pre-allocced buf is not enough\n");
1843 }
1844 switch (ctrl_data) {
1845 case DEBUG_ITCM_DONE:
1846 #ifdef MLAN_64BIT
1847 PRINTM(MMSG, "ITCM done: size=0x%lx\n",
1848 dbg_ptr - ITCM_Ptr);
1849 #else
1850 PRINTM(MMSG, "ITCM done: size=0x%x\n",
1851 dbg_ptr - ITCM_Ptr);
1852 #endif
1853 woal_save_dump_info_to_buf(phandle, ITCM_Ptr, ITCM_SIZE,
1854 FW_DUMP_TYPE_MEM_ITCM);
1855 dbg_ptr = DTCM_Ptr;
1856 end_ptr = DTCM_Ptr + dtcm_size;
1857 moal_get_system_time(phandle, &sec, &usec);
1858 PRINTM(MMSG,
1859 "Start DTCM output %u.%06u, please wait...\n",
1860 sec, usec);
1861 break;
1862 case DEBUG_DTCM_DONE:
1863 #ifdef MLAN_64BIT
1864 PRINTM(MMSG, "DTCM done: size=0x%lx\n",
1865 dbg_ptr - DTCM_Ptr);
1866 #else
1867 PRINTM(MMSG, "DTCM done: size=0x%x\n",
1868 dbg_ptr - DTCM_Ptr);
1869 #endif
1870 woal_save_dump_info_to_buf(phandle, ITCM_Ptr, dtcm_size,
1871 FW_DUMP_TYPE_MEM_DTCM);
1872 dbg_ptr = SQRAM_Ptr;
1873 end_ptr = SQRAM_Ptr + sqram_size;
1874 moal_get_system_time(phandle, &sec, &usec);
1875 PRINTM(MMSG,
1876 "Start SQRAM output %u.%06u, please wait...\n",
1877 sec, usec);
1878 break;
1879 case DEBUG_SQRAM_DONE:
1880 #ifdef MLAN_64BIT
1881 PRINTM(MMSG, "SQRAM done: size=0x%lx\n",
1882 dbg_ptr - SQRAM_Ptr);
1883 #else
1884 PRINTM(MMSG, "SQRAM done: size=0x%x\n",
1885 dbg_ptr - SQRAM_Ptr);
1886 #endif
1887 woal_save_dump_info_to_buf(phandle, SQRAM_Ptr,
1888 sqram_size,
1889 FW_DUMP_TYPE_MEM_SQRAM);
1890 PRINTM(MMSG, "End output!\n");
1891 break;
1892 default:
1893 break;
1894 }
1895 } while (ctrl_data != DEBUG_SQRAM_DONE);
1896
1897 woal_append_end_block(phandle);
1898 PRINTM(MMSG,
1899 "The output ITCM/DTCM/SQRAM have been saved to files successfully!\n");
1900 moal_get_system_time(phandle, &sec, &usec);
1901 PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
1902 /* end dump fw memory */
1903 done:
1904 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
1905 sdio_release_host(((struct sdio_mmc_card *)phandle->card)->func);
1906 #endif
1907 if (ITCM_Ptr)
1908 moal_vfree(phandle, ITCM_Ptr);
1909 if (DTCM_Ptr)
1910 moal_vfree(phandle, DTCM_Ptr);
1911 if (SQRAM_Ptr)
1912 moal_vfree(phandle, SQRAM_Ptr);
1913 PRINTM(MMSG, "==== DEBUG MODE END ====\n");
1914 return;
1915 }
1916 #endif
1917
1918 /**
1919 * @brief This function dump firmware memory to file
1920 *
1921 * @param phandle A pointer to moal_handle
1922 *
1923 * @return N/A
1924 */
woal_dump_firmware_info_v2(moal_handle * phandle)1925 void woal_dump_firmware_info_v2(moal_handle *phandle)
1926 {
1927 int ret = 0;
1928 unsigned int reg, reg_start, reg_end;
1929 t_u8 *dbg_ptr = NULL;
1930 t_u32 sec, usec;
1931 t_u8 dump_num = 0;
1932 t_u8 idx = 0;
1933 t_u8 doneflag = 0;
1934 rdwr_status stat;
1935 t_u8 i = 0;
1936 t_u8 read_reg = 0;
1937 t_u32 memory_size = 0;
1938 t_u8 *end_ptr = NULL;
1939 t_u8 dbg_dump_start_reg = 0;
1940 t_u8 dbg_dump_end_reg = 0;
1941 t_u8 dbg_dump_ctrl_reg = 0;
1942
1943 if (!phandle) {
1944 PRINTM(MERROR, "Could not dump firmwware info\n");
1945 return;
1946 }
1947
1948 dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg;
1949 dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg;
1950 dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg;
1951
1952 if (!phandle->fw_dump_buf) {
1953 ret = moal_vmalloc(phandle, FW_DUMP_INFO_LEN,
1954 &(phandle->fw_dump_buf));
1955 if (ret != MLAN_STATUS_SUCCESS || !phandle->fw_dump_buf) {
1956 PRINTM(MERROR, "Failed to vmalloc fw dump bufffer\n");
1957 return;
1958 }
1959 } else {
1960 memset(phandle->fw_dump_buf, 0x00, FW_DUMP_INFO_LEN);
1961 }
1962 phandle->fw_dump_len = 0;
1963
1964 /* start dump fw memory */
1965 moal_get_system_time(phandle, &sec, &usec);
1966 PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
1967 /* read the number of the memories which will dump */
1968 if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag))
1969 goto done;
1970 reg = dbg_dump_start_reg;
1971 ret = woal_sdio_readb(phandle, reg, &dump_num);
1972 if (ret) {
1973 PRINTM(MMSG, "SDIO READ MEM NUM ERR\n");
1974 goto done;
1975 }
1976
1977 /* read the length of every memory which will dump */
1978 for (idx = 0; idx < dump_num; idx++) {
1979 if (RDWR_STATUS_FAILURE ==
1980 woal_cmd52_rdwr_firmware(phandle, doneflag))
1981 goto done;
1982 memory_size = 0;
1983 reg = dbg_dump_start_reg;
1984 for (i = 0; i < 4; i++) {
1985 ret = woal_sdio_readb(phandle, reg, &read_reg);
1986 if (ret) {
1987 PRINTM(MMSG, "SDIO READ ERR\n");
1988 goto done;
1989 }
1990 memory_size |= (read_reg << i * 8);
1991 reg++;
1992 }
1993 if (memory_size == 0) {
1994 PRINTM(MMSG, "Firmware Dump Finished!\n");
1995 ret = woal_sdiommc_write_reg(phandle, dbg_dump_ctrl_reg,
1996 DEBUG_MEMDUMP_FINISH);
1997 if (ret) {
1998 PRINTM(MERROR,
1999 "SDIO Write MEMDUMP_FINISH ERR\n");
2000 goto done;
2001 }
2002 break;
2003 } else {
2004 PRINTM(MMSG, "%s_SIZE=0x%x\n",
2005 mem_type_mapping_tbl[idx].mem_name, memory_size);
2006 ret = moal_vmalloc(
2007 phandle, memory_size + 1,
2008 (t_u8 **)&mem_type_mapping_tbl[idx].mem_Ptr);
2009 if ((ret != MLAN_STATUS_SUCCESS) ||
2010 !mem_type_mapping_tbl[idx].mem_Ptr) {
2011 PRINTM(MERROR,
2012 "Error: vmalloc %s buffer failed!!!\n",
2013 mem_type_mapping_tbl[idx].mem_name);
2014 goto done;
2015 }
2016 dbg_ptr = mem_type_mapping_tbl[idx].mem_Ptr;
2017 end_ptr = dbg_ptr + memory_size;
2018 }
2019 doneflag = mem_type_mapping_tbl[idx].done_flag;
2020 moal_get_system_time(phandle, &sec, &usec);
2021 PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
2022 mem_type_mapping_tbl[idx].mem_name, sec, usec);
2023 do {
2024 stat = woal_cmd52_rdwr_firmware(phandle, doneflag);
2025 if (RDWR_STATUS_FAILURE == stat)
2026 goto done;
2027 reg_start = dbg_dump_start_reg;
2028 reg_end = dbg_dump_end_reg;
2029 for (reg = reg_start; reg <= reg_end; reg++) {
2030 ret = woal_sdio_readb(phandle, reg, dbg_ptr);
2031 if (ret) {
2032 PRINTM(MMSG, "SDIO READ ERR\n");
2033 goto done;
2034 }
2035 if (dbg_ptr < end_ptr)
2036 dbg_ptr++;
2037 else
2038 PRINTM(MINFO,
2039 "pre-allocced buf is not enough\n");
2040 }
2041 if (RDWR_STATUS_DONE == stat) {
2042 #ifdef MLAN_64BIT
2043 PRINTM(MMSG,
2044 "%s done:"
2045 "size = 0x%lx\n",
2046 mem_type_mapping_tbl[idx].mem_name,
2047 dbg_ptr - mem_type_mapping_tbl[idx]
2048 .mem_Ptr);
2049 #else
2050 PRINTM(MMSG,
2051 "%s done:"
2052 "size = 0x%x\n",
2053 mem_type_mapping_tbl[idx].mem_name,
2054 dbg_ptr - mem_type_mapping_tbl[idx]
2055 .mem_Ptr);
2056 #endif
2057 woal_save_dump_info_to_buf(
2058 phandle,
2059 mem_type_mapping_tbl[idx].mem_Ptr,
2060 memory_size,
2061 mem_type_mapping_tbl[idx].type);
2062 moal_vfree(phandle,
2063 mem_type_mapping_tbl[idx].mem_Ptr);
2064 mem_type_mapping_tbl[idx].mem_Ptr = NULL;
2065 break;
2066 }
2067 } while (1);
2068 }
2069 woal_append_end_block(phandle);
2070 moal_get_system_time(phandle, &sec, &usec);
2071 PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
2072 /* end dump fw memory */
2073 done:
2074 for (idx = 0; idx < dump_num; idx++) {
2075 if (mem_type_mapping_tbl[idx].mem_Ptr) {
2076 moal_vfree(phandle, mem_type_mapping_tbl[idx].mem_Ptr);
2077 mem_type_mapping_tbl[idx].mem_Ptr = NULL;
2078 }
2079 }
2080 PRINTM(MMSG, "==== DEBUG MODE END ====\n");
2081 return;
2082 }
2083
2084 /**
2085 * @brief This function dump firmware memory to file
2086 *
2087 * @param phandle A pointer to moal_handle
2088 *
2089 * @return N/A
2090 */
woal_dump_firmware_info_v3(moal_handle * phandle)2091 void woal_dump_firmware_info_v3(moal_handle *phandle)
2092 {
2093 int ret = 0;
2094 int tries = 0;
2095 unsigned int reg, reg_start, reg_end;
2096 t_u8 *dbg_ptr = NULL;
2097 t_u8 *temp_Ptr = NULL;
2098 t_u32 sec, usec;
2099 t_u8 start_flag = 0;
2100 t_u8 doneflag = 0;
2101 rdwr_status stat;
2102 t_u32 memory_size = 0;
2103 t_u8 *end_ptr = NULL;
2104 t_u8 dbg_dump_start_reg = 0;
2105 t_u8 dbg_dump_end_reg = 0;
2106 memory_type_mapping *pmem_type_mapping_tbl =
2107 &mem_type_mapping_tbl_8977_8997;
2108
2109 if (!phandle) {
2110 PRINTM(MERROR, "Could not dump firmwware info\n");
2111 return;
2112 }
2113 #ifdef SD9177
2114 if (IS_SD9177(phandle->card_type)) {
2115 if (phandle->event_fw_dump) {
2116 if (RDWR_STATUS_FAILURE !=
2117 woal_cmd52_rdwr_firmware(phandle, doneflag)) {
2118 PRINTM(MMSG,
2119 "====SDIO FW DUMP EVENT MODE START ====\n");
2120 return;
2121 }
2122 }
2123 }
2124 #endif
2125
2126 dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg;
2127 dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg;
2128
2129 /* start dump fw memory */
2130 moal_get_system_time(phandle, &sec, &usec);
2131 PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec);
2132 /* read the number of the memories which will dump */
2133 if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag))
2134 goto done;
2135
2136 /** check the reg which indicate dump starting */
2137 for (reg = dbg_dump_start_reg; reg <= dbg_dump_end_reg; reg++) {
2138 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
2139 ret = woal_sdio_readb(phandle, reg, &start_flag);
2140 if (ret) {
2141 PRINTM(MMSG, "SDIO READ ERR\n");
2142 goto done;
2143 }
2144 /** 0 means dump starting*/
2145 if (start_flag == 0)
2146 break;
2147 udelay(100);
2148 }
2149 if (tries == MAX_POLL_TRIES) {
2150 PRINTM(MMSG, "FW not ready to dump\n");
2151 goto done;
2152 }
2153 }
2154 memory_size = 0xF0000;
2155 PRINTM(MMSG, "%s_SIZE=0x%x\n", pmem_type_mapping_tbl->mem_name,
2156 memory_size);
2157 ret = moal_vmalloc(phandle, memory_size + 1,
2158 (t_u8 **)&pmem_type_mapping_tbl->mem_Ptr);
2159 if ((ret != MLAN_STATUS_SUCCESS) || !pmem_type_mapping_tbl->mem_Ptr) {
2160 PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n",
2161 pmem_type_mapping_tbl->mem_name);
2162 goto done;
2163 }
2164 dbg_ptr = pmem_type_mapping_tbl->mem_Ptr;
2165 end_ptr = dbg_ptr + memory_size;
2166 doneflag = pmem_type_mapping_tbl->done_flag;
2167 moal_get_system_time(phandle, &sec, &usec);
2168 PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n",
2169 pmem_type_mapping_tbl->mem_name, sec, usec);
2170 do {
2171 stat = woal_cmd52_rdwr_firmware(phandle, doneflag);
2172 if (RDWR_STATUS_FAILURE == stat)
2173 goto done;
2174 reg_start = dbg_dump_start_reg;
2175 reg_end = dbg_dump_end_reg;
2176 for (reg = reg_start; reg <= reg_end; reg++) {
2177 ret = woal_sdio_readb(phandle, reg, dbg_ptr);
2178 if (ret) {
2179 PRINTM(MMSG, "SDIO READ ERR\n");
2180 goto done;
2181 }
2182 dbg_ptr++;
2183 if (dbg_ptr >= end_ptr) {
2184 PRINTM(MINFO,
2185 "pre-allocced buf is not enough\n");
2186
2187 ret = moal_vmalloc(phandle,
2188 memory_size + 0x2000 + 1,
2189 (t_u8 **)&temp_Ptr);
2190 if ((ret != MLAN_STATUS_SUCCESS) || !temp_Ptr) {
2191 PRINTM(MERROR,
2192 "Error: vmalloc buffer failed!!!\n");
2193 goto done;
2194 }
2195
2196 moal_memcpy_ext(phandle, temp_Ptr,
2197 pmem_type_mapping_tbl->mem_Ptr,
2198 memory_size,
2199 memory_size + 0x2000);
2200 moal_vfree(phandle,
2201 pmem_type_mapping_tbl->mem_Ptr);
2202 pmem_type_mapping_tbl->mem_Ptr = temp_Ptr;
2203 temp_Ptr = NULL;
2204 dbg_ptr = pmem_type_mapping_tbl->mem_Ptr +
2205 memory_size;
2206
2207 memory_size += 0x2000;
2208 end_ptr = pmem_type_mapping_tbl->mem_Ptr +
2209 memory_size;
2210 }
2211 }
2212 if (RDWR_STATUS_DONE == stat) {
2213 #ifdef MLAN_64BIT
2214 PRINTM(MMSG,
2215 "%s done:"
2216 "size = 0x%lx\n",
2217 pmem_type_mapping_tbl->mem_name,
2218 dbg_ptr - pmem_type_mapping_tbl->mem_Ptr);
2219 #else
2220 PRINTM(MMSG,
2221 "%s done:"
2222 "size = 0x%x\n",
2223 pmem_type_mapping_tbl->mem_name,
2224 dbg_ptr - pmem_type_mapping_tbl->mem_Ptr);
2225
2226 #endif
2227 if (phandle->fw_dump_buf) {
2228 moal_vfree(phandle, phandle->fw_dump_buf);
2229 phandle->fw_dump_buf = NULL;
2230 phandle->fw_dump_len = 0;
2231 }
2232 phandle->fw_dump_buf = pmem_type_mapping_tbl->mem_Ptr;
2233 phandle->fw_dump_len =
2234 dbg_ptr - pmem_type_mapping_tbl->mem_Ptr;
2235 pmem_type_mapping_tbl->mem_Ptr = NULL;
2236 break;
2237 }
2238 } while (1);
2239 moal_get_system_time(phandle, &sec, &usec);
2240 PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec);
2241 /* end dump fw memory */
2242 done:
2243 if (pmem_type_mapping_tbl->mem_Ptr) {
2244 moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr);
2245 pmem_type_mapping_tbl->mem_Ptr = NULL;
2246 }
2247 PRINTM(MMSG, "==== DEBUG MODE END ====\n");
2248 return;
2249 }
2250
2251 /**
2252 * @brief This function reads and displays SDIO registers for debugging
2253 *
2254 * @param phandle A pointer to moal_handle
2255 *
2256 * @return N/A
2257 */
woal_sdiommc_reg_dbg(moal_handle * phandle)2258 static void woal_sdiommc_reg_dbg(moal_handle *phandle)
2259 {
2260 int ret = 0;
2261 t_u8 loop, index = 0, func, data;
2262 unsigned int reg, reg_start, reg_end;
2263 unsigned int scratch_reg = phandle->card_info->scratch_reg;
2264 t_u8 *reg_table = phandle->card_info->dump_reg.reg_table;
2265 t_u8 reg_table_size = phandle->card_info->dump_reg.reg_table_size;
2266 char buf[256], *ptr;
2267
2268 mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
2269 for (loop = 0; loop < 5; loop++) {
2270 memset(buf, 0, sizeof(buf));
2271 ptr = buf;
2272 if (loop == 0) {
2273 /* Read the registers of SDIO function0 */
2274 func = loop;
2275 reg_start = 0;
2276 reg_end = 9;
2277 } else if (loop == 1) {
2278 /* Read the registers of SDIO function1 */
2279 func = loop;
2280 reg_start = phandle->card_info->func1_reg_start;
2281 reg_end = phandle->card_info->func1_reg_end;
2282 } else if (loop == 2) {
2283 /* Read specific registers of SDIO function1 */
2284 index = 0;
2285 func = 1;
2286 reg_start = reg_table[index++];
2287 reg_end = reg_table[reg_table_size - 1];
2288 } else {
2289 /* Read the scratch registers of SDIO function1 */
2290 if (loop == 4)
2291 mdelay(100);
2292 func = 1;
2293 reg_start = scratch_reg;
2294 reg_end = scratch_reg + 10;
2295 }
2296 if (loop != 2)
2297 ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
2298 reg_start, reg_end);
2299 else
2300 ptr += sprintf(ptr, "SDIO Func%d: ", func);
2301 for (reg = reg_start; reg <= reg_end;) {
2302 if (func == 0)
2303 ret = woal_sdio_f0_readb(phandle, reg, &data);
2304 else
2305 ret = woal_sdio_readb(phandle, reg, &data);
2306 if (loop == 2)
2307 ptr += sprintf(ptr, "(%#x) ", reg);
2308 if (!ret)
2309 ptr += sprintf(ptr, "%02x ", data);
2310 else {
2311 ptr += sprintf(ptr, "ERR");
2312 break;
2313 }
2314 if (loop == 2 && reg < reg_end)
2315 reg = reg_table[index++];
2316 else
2317 reg++;
2318 }
2319 PRINTM(MMSG, "%s\n", buf);
2320 }
2321 mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
2322 }
2323
2324 /**
2325 * @brief This function dump firmware memory to file
2326 *
2327 * @param phandle A pointer to moal_handle
2328 *
2329 * @return N/A
2330 */
woal_sdiommc_dump_fw_info(moal_handle * phandle)2331 static void woal_sdiommc_dump_fw_info(moal_handle *phandle)
2332 {
2333 if (!phandle) {
2334 PRINTM(MERROR, "Could not dump firmwware info\n");
2335 return;
2336 }
2337 /** cancel all pending commands */
2338 mlan_ioctl(phandle->pmlan_adapter, NULL);
2339
2340 mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
2341 phandle->fw_dump = MTRUE;
2342 if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V2) {
2343 woal_dump_firmware_info_v2(phandle);
2344 } else if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V3) {
2345 woal_dump_firmware_info_v3(phandle);
2346 if (phandle->event_fw_dump) {
2347 phandle->event_fw_dump = MFALSE;
2348 queue_work(phandle->workqueue, &phandle->main_work);
2349 phandle->is_fw_dump_timer_set = MTRUE;
2350 woal_mod_timer(&phandle->fw_dump_timer, MOAL_TIMER_5S);
2351 return;
2352 }
2353 }
2354 #ifdef SD8801
2355 else {
2356 woal_dump_firmware_info(phandle);
2357 }
2358 #endif
2359 phandle->fw_dump = MFALSE;
2360 if (!phandle->priv_num)
2361 return;
2362 woal_send_fw_dump_complete_event(
2363 woal_get_priv(phandle, MLAN_BSS_ROLE_ANY));
2364 mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
2365 queue_work(phandle->workqueue, &phandle->main_work);
2366 woal_process_hang(phandle);
2367 return;
2368 }
2369
2370 /**
2371 * @brief This function save sdio reg info
2372 *
2373 * @param phandle A pointer to moal_handle
2374 * @param buf A pointer buffer saving log
2375 *
2376 * @return The length of this log
2377 */
woal_sdiommc_dump_reg_info(moal_handle * phandle,t_u8 * drv_buf)2378 static int woal_sdiommc_dump_reg_info(moal_handle *phandle, t_u8 *drv_buf)
2379 {
2380 char *drv_ptr = (char *)drv_buf;
2381 int ret = 0;
2382 t_u8 loop, index = 0, func, data;
2383 unsigned int reg, reg_start, reg_end;
2384 unsigned int scratch_reg = 0;
2385 t_u8 *reg_table = NULL;
2386 t_u8 reg_table_size = 0;
2387 char buf[256], *ptr;
2388
2389 ENTER();
2390
2391 if (!phandle || !drv_buf) {
2392 PRINTM(MMSG, "%s: can't retreive info\n", __func__);
2393 LEAVE();
2394 return 0;
2395 }
2396
2397 scratch_reg = phandle->card_info->scratch_reg;
2398 reg_table = phandle->card_info->dump_reg.reg_table;
2399 reg_table_size = phandle->card_info->dump_reg.reg_table_size;
2400
2401 mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE);
2402
2403 drv_ptr += sprintf(drv_ptr, "--------sdio_reg_debug_info---------\n");
2404 for (loop = 0; loop < 5; loop++) {
2405 memset(buf, 0, sizeof(buf));
2406 ptr = buf;
2407 if (loop == 0) {
2408 /* Read the registers of SDIO function0 */
2409 func = loop;
2410 reg_start = 0;
2411 reg_end = 9;
2412
2413 } else if (loop == 1) {
2414 /* Read the registers of SDIO function1 */
2415 func = loop;
2416 reg_start = phandle->card_info->func1_reg_start;
2417 reg_end = phandle->card_info->func1_reg_end;
2418 } else if (loop == 2) {
2419 /* Read specific registers of SDIO function1 */
2420 index = 0;
2421 func = 1;
2422 reg_start = reg_table[index++];
2423 reg_end = reg_table[reg_table_size - 1];
2424 } else {
2425 /* Read the scratch registers of SDIO function1 */
2426 if (loop == 4)
2427 mdelay(100);
2428 func = 1;
2429 reg_start = scratch_reg;
2430 reg_end = scratch_reg + 10;
2431 }
2432 if (loop != 2)
2433 ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func,
2434 reg_start, reg_end);
2435 else
2436 ptr += sprintf(ptr, "SDIO Func%d: ", func);
2437 for (reg = reg_start; reg <= reg_end;) {
2438 if (func == 0)
2439 ret = woal_sdio_f0_readb(phandle, reg, &data);
2440 else
2441 ret = woal_sdio_readb(phandle, reg, &data);
2442
2443 if (loop == 2)
2444 ptr += sprintf(ptr, "(%#x) ", reg);
2445 if (!ret)
2446 ptr += sprintf(ptr, "%02x ", data);
2447 else {
2448 ptr += sprintf(ptr, "ERR");
2449 break;
2450 }
2451 if (loop == 2 && reg < reg_end)
2452 reg = reg_table[index++];
2453 else
2454 reg++;
2455 }
2456 drv_ptr += sprintf(drv_ptr, "%s\n", buf);
2457 }
2458
2459 drv_ptr +=
2460 sprintf(drv_ptr, "--------sdio_reg_debug_info End---------\n");
2461 mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE);
2462
2463 LEAVE();
2464 return drv_ptr - (char *)drv_buf;
2465 }
2466
2467 /**
2468 * @brief This function reset sdio through sdio bus driver
2469 *
2470 * @param phandle A pointer to moal_handle
2471 *
2472 * @return N/A
2473 */
woal_sdio_reset_hw(moal_handle * handle)2474 void woal_sdio_reset_hw(moal_handle *handle)
2475 {
2476 struct sdio_mmc_card *card = handle->card;
2477 struct sdio_func *func = card->func;
2478 ENTER();
2479 sdio_claim_host(func);
2480 sdio_release_irq(card->func);
2481 sdio_disable_func(card->func);
2482 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
2483 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
2484 mmc_hw_reset(func->card);
2485 #else
2486 mmc_hw_reset(func->card->host);
2487 #endif
2488 #endif
2489
2490 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
2491 /* The byte mode patch is available in kernel MMC driver
2492 * which fixes one issue in MP-A transfer.
2493 * bit1: use func->cur_blksize for byte mode
2494 */
2495 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
2496 #endif
2497 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2498 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
2499 #endif
2500 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
2501 /* wait for chip fully wake up */
2502 if (!func->enable_timeout)
2503 func->enable_timeout = 200;
2504 #endif
2505 sdio_enable_func(func);
2506 sdio_claim_irq(func, woal_sdio_interrupt);
2507 sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
2508 sdio_release_host(func);
2509 LEAVE();
2510 return;
2511 }
2512
2513 static moal_if_ops sdiommc_ops = {
2514 .register_dev = woal_sdiommc_register_dev,
2515 .unregister_dev = woal_sdiommc_unregister_dev,
2516 .read_reg = woal_sdiommc_read_reg,
2517 .write_reg = woal_sdiommc_write_reg,
2518 .read_data_sync = woal_sdiommc_read_data_sync,
2519 .write_data_sync = woal_sdiommc_write_data_sync,
2520 .get_fw_name = woal_sdiommc_get_fw_name,
2521 .dump_fw_info = woal_sdiommc_dump_fw_info,
2522 .dump_reg_info = woal_sdiommc_dump_reg_info,
2523 .reg_dbg = woal_sdiommc_reg_dbg,
2524 .is_second_mac = woal_sdiommc_is_second_mac,
2525 };
2526