• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ***************************************************************************
3  *  FILE:     putest.c
4  *
5  *  PURPOSE:    putest related functions.
6  *
7  *  Copyright (C) 2008-2009 by Cambridge Silicon Radio Ltd.
8  *
9  * Refer to LICENSE.txt included with this source code for details on
10  * the license terms.
11  *
12  * ***************************************************************************
13  */
14 
15 #include <linux/vmalloc.h>
16 #include <linux/firmware.h>
17 
18 #include "unifi_priv.h"
19 #include "csr_wifi_hip_chiphelper.h"
20 
21 #define UNIFI_PROC_BOTH 3
22 
23 
unifi_putest_cmd52_read(unifi_priv_t * priv,unsigned char * arg)24 int unifi_putest_cmd52_read(unifi_priv_t *priv, unsigned char *arg)
25 {
26     struct unifi_putest_cmd52 cmd52_params;
27     u8 *arg_pos;
28     unsigned int cmd_param_size;
29     int r;
30     CsrResult csrResult;
31     unsigned char ret_buffer[32];
32     u8 *ret_buffer_pos;
33     u8 retries;
34 
35     arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
36     if (get_user(cmd_param_size, (int*)arg_pos)) {
37         unifi_error(priv,
38                     "unifi_putest_cmd52_read: Failed to get the argument\n");
39         return -EFAULT;
40     }
41 
42     if (cmd_param_size != sizeof(struct unifi_putest_cmd52)) {
43         unifi_error(priv,
44                     "unifi_putest_cmd52_read: cmd52 struct mismatch\n");
45         return -EINVAL;
46     }
47 
48     arg_pos += sizeof(unsigned int);
49     if (copy_from_user(&cmd52_params,
50                        (void*)arg_pos,
51                        sizeof(struct unifi_putest_cmd52))) {
52         unifi_error(priv,
53                     "unifi_putest_cmd52_read: Failed to get the cmd52 params\n");
54         return -EFAULT;
55     }
56 
57     unifi_trace(priv, UDBG2, "cmd52r: func=%d addr=0x%x ",
58                 cmd52_params.funcnum, cmd52_params.addr);
59 
60     retries = 3;
61     CsrSdioClaim(priv->sdio);
62     do {
63         if (cmd52_params.funcnum == 0) {
64             csrResult = CsrSdioF0Read8(priv->sdio, cmd52_params.addr, &cmd52_params.data);
65         } else {
66             csrResult = CsrSdioRead8(priv->sdio, cmd52_params.addr, &cmd52_params.data);
67         }
68     } while (--retries && ((csrResult == CSR_SDIO_RESULT_CRC_ERROR) || (csrResult == CSR_SDIO_RESULT_TIMEOUT)));
69     CsrSdioRelease(priv->sdio);
70 
71     if (csrResult != CSR_RESULT_SUCCESS) {
72         unifi_error(priv,
73                     "\nunifi_putest_cmd52_read: Read8() failed (csrResult=0x%x)\n", csrResult);
74         return -EFAULT;
75     }
76     unifi_trace(priv, UDBG2, "data=%d\n", cmd52_params.data);
77 
78     /* Copy the info to the out buffer */
79     *(unifi_putest_command_t*)ret_buffer = UNIFI_PUTEST_CMD52_READ;
80     ret_buffer_pos = (u8*)(((unifi_putest_command_t*)ret_buffer) + 1);
81     *(unsigned int*)ret_buffer_pos = sizeof(struct unifi_putest_cmd52);
82     ret_buffer_pos += sizeof(unsigned int);
83     memcpy(ret_buffer_pos, &cmd52_params, sizeof(struct unifi_putest_cmd52));
84     ret_buffer_pos += sizeof(struct unifi_putest_cmd52);
85 
86     r = copy_to_user((void*)arg,
87                      ret_buffer,
88                      ret_buffer_pos - ret_buffer);
89     if (r) {
90         unifi_error(priv,
91                     "unifi_putest_cmd52_read: Failed to return the data\n");
92         return -EFAULT;
93     }
94 
95     return 0;
96 }
97 
98 
unifi_putest_cmd52_write(unifi_priv_t * priv,unsigned char * arg)99 int unifi_putest_cmd52_write(unifi_priv_t *priv, unsigned char *arg)
100 {
101     struct unifi_putest_cmd52 cmd52_params;
102     u8 *arg_pos;
103     unsigned int cmd_param_size;
104     CsrResult csrResult;
105     u8 retries;
106 
107     arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
108     if (get_user(cmd_param_size, (int*)arg_pos)) {
109         unifi_error(priv,
110                     "unifi_putest_cmd52_write: Failed to get the argument\n");
111         return -EFAULT;
112     }
113 
114     if (cmd_param_size != sizeof(struct unifi_putest_cmd52)) {
115         unifi_error(priv,
116                     "unifi_putest_cmd52_write: cmd52 struct mismatch\n");
117         return -EINVAL;
118     }
119 
120     arg_pos += sizeof(unsigned int);
121     if (copy_from_user(&cmd52_params,
122                        (void*)(arg_pos),
123                        sizeof(struct unifi_putest_cmd52))) {
124         unifi_error(priv,
125                     "unifi_putest_cmd52_write: Failed to get the cmd52 params\n");
126         return -EFAULT;
127     }
128 
129     unifi_trace(priv, UDBG2, "cmd52w: func=%d addr=0x%x data=%d\n",
130                 cmd52_params.funcnum, cmd52_params.addr, cmd52_params.data);
131 
132     retries = 3;
133     CsrSdioClaim(priv->sdio);
134     do {
135         if (cmd52_params.funcnum == 0) {
136             csrResult = CsrSdioF0Write8(priv->sdio, cmd52_params.addr, cmd52_params.data);
137         } else {
138             csrResult = CsrSdioWrite8(priv->sdio, cmd52_params.addr, cmd52_params.data);
139         }
140     } while (--retries && ((csrResult == CSR_SDIO_RESULT_CRC_ERROR) || (csrResult == CSR_SDIO_RESULT_TIMEOUT)));
141     CsrSdioRelease(priv->sdio);
142 
143     if (csrResult != CSR_RESULT_SUCCESS) {
144         unifi_error(priv,
145                     "unifi_putest_cmd52_write: Write8() failed (csrResult=0x%x)\n", csrResult);
146         return -EFAULT;
147     }
148 
149     return 0;
150 }
151 
unifi_putest_gp_read16(unifi_priv_t * priv,unsigned char * arg)152 int unifi_putest_gp_read16(unifi_priv_t *priv, unsigned char *arg)
153 {
154     struct unifi_putest_gp_rw16 gp_r16_params;
155     u8 *arg_pos;
156     unsigned int cmd_param_size;
157     int r;
158     CsrResult csrResult;
159     unsigned char ret_buffer[32];
160     u8 *ret_buffer_pos;
161 
162     arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
163     if (get_user(cmd_param_size, (int*)arg_pos)) {
164         unifi_error(priv,
165                     "unifi_putest_gp_read16: Failed to get the argument\n");
166         return -EFAULT;
167     }
168 
169     if (cmd_param_size != sizeof(struct unifi_putest_gp_rw16)) {
170         unifi_error(priv,
171                     "unifi_putest_gp_read16: struct mismatch\n");
172         return -EINVAL;
173     }
174 
175     arg_pos += sizeof(unsigned int);
176     if (copy_from_user(&gp_r16_params,
177                        (void*)arg_pos,
178                        sizeof(struct unifi_putest_gp_rw16))) {
179         unifi_error(priv,
180                     "unifi_putest_gp_read16: Failed to get the params\n");
181         return -EFAULT;
182     }
183     CsrSdioClaim(priv->sdio);
184     csrResult = unifi_card_read16(priv->card, gp_r16_params.addr, &gp_r16_params.data);
185     CsrSdioRelease(priv->sdio);
186     if (csrResult != CSR_RESULT_SUCCESS) {
187         unifi_error(priv,
188                     "unifi_putest_gp_read16: unifi_card_read16() GP=0x%x failed (csrResult=0x%x)\n", gp_r16_params.addr, csrResult);
189         return -EFAULT;
190     }
191 
192     unifi_trace(priv, UDBG2, "gp_r16: GP=0x%08x, data=0x%04x\n", gp_r16_params.addr, gp_r16_params.data);
193 
194     /* Copy the info to the out buffer */
195     *(unifi_putest_command_t*)ret_buffer = UNIFI_PUTEST_GP_READ16;
196     ret_buffer_pos = (u8*)(((unifi_putest_command_t*)ret_buffer) + 1);
197     *(unsigned int*)ret_buffer_pos = sizeof(struct unifi_putest_gp_rw16);
198     ret_buffer_pos += sizeof(unsigned int);
199     memcpy(ret_buffer_pos, &gp_r16_params, sizeof(struct unifi_putest_gp_rw16));
200     ret_buffer_pos += sizeof(struct unifi_putest_gp_rw16);
201 
202     r = copy_to_user((void*)arg,
203                      ret_buffer,
204                      ret_buffer_pos - ret_buffer);
205     if (r) {
206         unifi_error(priv,
207                     "unifi_putest_gp_read16: Failed to return the data\n");
208         return -EFAULT;
209     }
210 
211     return 0;
212 }
213 
unifi_putest_gp_write16(unifi_priv_t * priv,unsigned char * arg)214 int unifi_putest_gp_write16(unifi_priv_t *priv, unsigned char *arg)
215 {
216     struct unifi_putest_gp_rw16 gp_w16_params;
217     u8 *arg_pos;
218     unsigned int cmd_param_size;
219     CsrResult csrResult;
220 
221     arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
222     if (get_user(cmd_param_size, (int*)arg_pos)) {
223         unifi_error(priv,
224                     "unifi_putest_gp_write16: Failed to get the argument\n");
225         return -EFAULT;
226     }
227 
228     if (cmd_param_size != sizeof(struct unifi_putest_gp_rw16)) {
229         unifi_error(priv,
230                     "unifi_putest_gp_write16: struct mismatch\n");
231         return -EINVAL;
232     }
233 
234     arg_pos += sizeof(unsigned int);
235     if (copy_from_user(&gp_w16_params,
236                        (void*)(arg_pos),
237                        sizeof(struct unifi_putest_gp_rw16))) {
238         unifi_error(priv,
239                     "unifi_putest_gp_write16: Failed to get the params\n");
240         return -EFAULT;
241     }
242 
243     unifi_trace(priv, UDBG2, "gp_w16: GP=0x%08x, data=0x%04x\n", gp_w16_params.addr, gp_w16_params.data);
244     CsrSdioClaim(priv->sdio);
245     csrResult = unifi_card_write16(priv->card, gp_w16_params.addr, gp_w16_params.data);
246     CsrSdioRelease(priv->sdio);
247     if (csrResult != CSR_RESULT_SUCCESS) {
248         unifi_error(priv,
249                     "unifi_putest_gp_write16: unifi_card_write16() GP=%x failed (csrResult=0x%x)\n", gp_w16_params.addr, csrResult);
250         return -EFAULT;
251     }
252 
253     return 0;
254 }
255 
unifi_putest_set_sdio_clock(unifi_priv_t * priv,unsigned char * arg)256 int unifi_putest_set_sdio_clock(unifi_priv_t *priv, unsigned char *arg)
257 {
258     int sdio_clock_speed;
259     CsrResult csrResult;
260 
261     if (get_user(sdio_clock_speed, (int*)(((unifi_putest_command_t*)arg) + 1))) {
262         unifi_error(priv,
263                     "unifi_putest_set_sdio_clock: Failed to get the argument\n");
264         return -EFAULT;
265     }
266 
267     unifi_trace(priv, UDBG2, "set sdio clock: %d KHz\n", sdio_clock_speed);
268 
269     CsrSdioClaim(priv->sdio);
270     csrResult = CsrSdioMaxBusClockFrequencySet(priv->sdio, sdio_clock_speed * 1000);
271     CsrSdioRelease(priv->sdio);
272     if (csrResult != CSR_RESULT_SUCCESS) {
273         unifi_error(priv,
274                     "unifi_putest_set_sdio_clock: Set clock failed (csrResult=0x%x)\n", csrResult);
275         return -EFAULT;
276     }
277 
278     return 0;
279 }
280 
281 
unifi_putest_start(unifi_priv_t * priv,unsigned char * arg)282 int unifi_putest_start(unifi_priv_t *priv, unsigned char *arg)
283 {
284     int r;
285     CsrResult csrResult;
286     int already_in_test = priv->ptest_mode;
287 
288     /* Ensure that sme_sys_suspend() doesn't power down the chip because:
289      *  1) Power is needed anyway for ptest.
290      *  2) The app code uses the START ioctl as a reset, so it gets called
291      *     multiple times. If the app stops the XAPs, but the power_down/up
292      *     sequence doesn't actually power down the chip, there can be problems
293      *     resetting, because part of the power_up sequence disables function 1
294      */
295     priv->ptest_mode = 1;
296 
297     /* Suspend the SME and UniFi */
298     if (priv->sme_cli) {
299         r = sme_sys_suspend(priv);
300         if (r) {
301             unifi_error(priv,
302                         "unifi_putest_start: failed to suspend UniFi\n");
303             return r;
304         }
305     }
306 
307     /* Application may have stopped the XAPs, but they are needed for reset */
308     if (already_in_test) {
309         CsrSdioClaim(priv->sdio);
310         csrResult = unifi_start_processors(priv->card);
311         CsrSdioRelease(priv->sdio);
312         if (csrResult != CSR_RESULT_SUCCESS) {
313             unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
314         }
315     } else {
316         /* Ensure chip is powered for the case where there's no unifi_helper */
317         CsrSdioClaim(priv->sdio);
318         csrResult = CsrSdioPowerOn(priv->sdio);
319         CsrSdioRelease(priv->sdio);
320         if (csrResult != CSR_RESULT_SUCCESS) {
321             unifi_error(priv, "CsrSdioPowerOn csrResult = %d\n", csrResult);
322         }
323     }
324     CsrSdioClaim(priv->sdio);
325     csrResult = unifi_init(priv->card);
326     CsrSdioRelease(priv->sdio);
327     if (csrResult != CSR_RESULT_SUCCESS) {
328         unifi_error(priv,
329                     "unifi_putest_start: failed to init UniFi\n");
330         return CsrHipResultToStatus(csrResult);
331     }
332 
333     return 0;
334 }
335 
336 
unifi_putest_stop(unifi_priv_t * priv,unsigned char * arg)337 int unifi_putest_stop(unifi_priv_t *priv, unsigned char *arg)
338 {
339     int r = 0;
340     CsrResult csrResult;
341 
342     /* Application may have stopped the XAPs, but they are needed for reset */
343     CsrSdioClaim(priv->sdio);
344     csrResult = unifi_start_processors(priv->card);
345     CsrSdioRelease(priv->sdio);
346     if (csrResult != CSR_RESULT_SUCCESS) {
347         unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
348     }
349 
350     /* PUTEST_STOP is also used to resume the XAPs after SME coredump.
351      * Don't power off the chip, leave that to the normal wifi-off which is
352      * about to carry on. No need to resume the SME either, as it wasn't suspended.
353      */
354     if (priv->coredump_mode) {
355         priv->coredump_mode = 0;
356         return 0;
357     }
358 
359     /* At this point function 1 is enabled and the XAPs are running, so it is
360      * safe to let the card power down. Power is restored later, asynchronously,
361      * during the wifi_on requested by the SME.
362      */
363     CsrSdioClaim(priv->sdio);
364     CsrSdioPowerOff(priv->sdio);
365     CsrSdioRelease(priv->sdio);
366 
367     /* Resume the SME and UniFi */
368     if (priv->sme_cli) {
369         r = sme_sys_resume(priv);
370         if (r) {
371             unifi_error(priv,
372                         "unifi_putest_stop: failed to resume SME\n");
373         }
374     }
375     priv->ptest_mode = 0;
376 
377     return r;
378 }
379 
380 
unifi_putest_dl_fw(unifi_priv_t * priv,unsigned char * arg)381 int unifi_putest_dl_fw(unifi_priv_t *priv, unsigned char *arg)
382 {
383 #define UF_PUTEST_MAX_FW_FILE_NAME      16
384 #define UNIFI_MAX_FW_PATH_LEN           32
385     unsigned int fw_name_length;
386     unsigned char fw_name[UF_PUTEST_MAX_FW_FILE_NAME+1];
387     unsigned char *name_buffer;
388     int postfix;
389     char fw_path[UNIFI_MAX_FW_PATH_LEN];
390     const struct firmware *fw_entry;
391     struct dlpriv temp_fw_sta;
392     int r;
393     CsrResult csrResult;
394 
395     /* Get the f/w file name length */
396     if (get_user(fw_name_length, (unsigned int*)(((unifi_putest_command_t*)arg) + 1))) {
397         unifi_error(priv,
398                     "unifi_putest_dl_fw: Failed to get the length argument\n");
399         return -EFAULT;
400     }
401 
402     unifi_trace(priv, UDBG2, "unifi_putest_dl_fw: file name size = %d\n", fw_name_length);
403 
404     /* Sanity check for the f/w file name length */
405     if (fw_name_length > UF_PUTEST_MAX_FW_FILE_NAME) {
406         unifi_error(priv,
407                     "unifi_putest_dl_fw: F/W file name is too long\n");
408         return -EINVAL;
409     }
410 
411     /* Get the f/w file name */
412     name_buffer = ((unsigned char*)arg) + sizeof(unifi_putest_command_t) + sizeof(unsigned int);
413     if (copy_from_user(fw_name, (void*)name_buffer, fw_name_length)) {
414         unifi_error(priv, "unifi_putest_dl_fw: Failed to get the file name\n");
415         return -EFAULT;
416     }
417     fw_name[fw_name_length] = '\0';
418     unifi_trace(priv, UDBG2, "unifi_putest_dl_fw: file = %s\n", fw_name);
419 
420     /* Keep the existing f/w to a temp, we need to restore it later */
421     temp_fw_sta = priv->fw_sta;
422 
423     /* Get the putest f/w */
424     postfix = priv->instance;
425     scnprintf(fw_path, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
426               postfix, fw_name);
427     r = request_firmware(&fw_entry, fw_path, priv->unifi_device);
428     if (r == 0) {
429         priv->fw_sta.fw_desc = (void *)fw_entry;
430         priv->fw_sta.dl_data = fw_entry->data;
431         priv->fw_sta.dl_len = fw_entry->size;
432     } else {
433         unifi_error(priv, "Firmware file not available\n");
434         return -EINVAL;
435     }
436 
437     /* Application may have stopped the XAPs, but they are needed for reset */
438     CsrSdioClaim(priv->sdio);
439     csrResult = unifi_start_processors(priv->card);
440     CsrSdioRelease(priv->sdio);
441     if (csrResult != CSR_RESULT_SUCCESS) {
442         unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
443     }
444 
445     /* Download the f/w. On UF6xxx this will cause the f/w file to convert
446      * into patch format and download via the ROM boot loader
447      */
448     CsrSdioClaim(priv->sdio);
449     csrResult = unifi_download(priv->card, 0x0c00);
450     CsrSdioRelease(priv->sdio);
451     if (csrResult != CSR_RESULT_SUCCESS) {
452         unifi_error(priv,
453                     "unifi_putest_dl_fw: failed to download the f/w\n");
454         goto free_fw;
455     }
456 
457     /* Free the putest f/w... */
458 free_fw:
459     uf_release_firmware(priv, &priv->fw_sta);
460     /* ... and restore the original f/w */
461     priv->fw_sta = temp_fw_sta;
462 
463     return CsrHipResultToStatus(csrResult);
464 }
465 
466 
unifi_putest_dl_fw_buff(unifi_priv_t * priv,unsigned char * arg)467 int unifi_putest_dl_fw_buff(unifi_priv_t *priv, unsigned char *arg)
468 {
469     unsigned int fw_length;
470     unsigned char *fw_buf = NULL;
471     unsigned char *fw_user_ptr;
472     struct dlpriv temp_fw_sta;
473     CsrResult csrResult;
474 
475     /* Get the f/w buffer length */
476     if (get_user(fw_length, (unsigned int*)(((unifi_putest_command_t*)arg) + 1))) {
477         unifi_error(priv,
478                     "unifi_putest_dl_fw_buff: Failed to get the length arg\n");
479         return -EFAULT;
480     }
481 
482     unifi_trace(priv, UDBG2, "unifi_putest_dl_fw_buff: size = %d\n", fw_length);
483 
484     /* Sanity check for the buffer length */
485     if (fw_length == 0 || fw_length > 0xfffffff) {
486         unifi_error(priv,
487                     "unifi_putest_dl_fw_buff: buffer length bad %u\n", fw_length);
488         return -EINVAL;
489     }
490 
491     /* Buffer for kernel copy of the f/w image */
492     fw_buf = kmalloc(fw_length, GFP_KERNEL);
493     if (!fw_buf) {
494         unifi_error(priv, "unifi_putest_dl_fw_buff: malloc fail\n");
495         return -ENOMEM;
496     }
497 
498     /* Get the f/w image */
499     fw_user_ptr = ((unsigned char*)arg) + sizeof(unifi_putest_command_t) + sizeof(unsigned int);
500     if (copy_from_user(fw_buf, (void*)fw_user_ptr, fw_length)) {
501         unifi_error(priv, "unifi_putest_dl_fw_buff: Failed to get the buffer\n");
502         kfree(fw_buf);
503         return -EFAULT;
504     }
505 
506     /* Save the existing f/w to a temp, we need to restore it later */
507     temp_fw_sta = priv->fw_sta;
508 
509     /* Setting fw_desc NULL indicates to the core that no f/w file was loaded
510      * via the kernel request_firmware() mechanism. This indicates to the core
511      * that it shouldn't call release_firmware() after the download is done.
512      */
513     priv->fw_sta.fw_desc = NULL;            /* No OS f/w resource */
514     priv->fw_sta.dl_data = fw_buf;
515     priv->fw_sta.dl_len = fw_length;
516 
517     /* Application may have stopped the XAPs, but they are needed for reset */
518     CsrSdioClaim(priv->sdio);
519     csrResult = unifi_start_processors(priv->card);
520     CsrSdioRelease(priv->sdio);
521     if (csrResult != CSR_RESULT_SUCCESS) {
522         unifi_error(priv, "Failed to start XAPs. Hard reset required.\n");
523     }
524 
525     /* Download the f/w. On UF6xxx this will cause the f/w file to convert
526      * into patch format and download via the ROM boot loader
527      */
528     CsrSdioClaim(priv->sdio);
529     csrResult = unifi_download(priv->card, 0x0c00);
530     CsrSdioRelease(priv->sdio);
531     if (csrResult != CSR_RESULT_SUCCESS) {
532         unifi_error(priv,
533                     "unifi_putest_dl_fw_buff: failed to download the f/w\n");
534         goto free_fw;
535     }
536 
537 free_fw:
538     /* Finished with the putest f/w, so restore the station f/w */
539     priv->fw_sta = temp_fw_sta;
540     kfree(fw_buf);
541 
542     return CsrHipResultToStatus(csrResult);
543 }
544 
545 
unifi_putest_coredump_prepare(unifi_priv_t * priv,unsigned char * arg)546 int unifi_putest_coredump_prepare(unifi_priv_t *priv, unsigned char *arg)
547 {
548     u16 data_u16;
549     s32 i;
550     CsrResult r;
551 
552     unifi_info(priv, "Preparing for SDIO coredump\n");
553 #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE)
554     unifi_debug_buf_dump();
555 #endif
556 
557     /* Sanity check that userspace hasn't called a PUTEST_START, because that
558      * would have reset UniFi, potentially power cycling it and losing context
559      */
560     if (priv->ptest_mode) {
561         unifi_error(priv, "PUTEST_START shouldn't be used before a coredump\n");
562     }
563 
564     /* Flag that the userspace has requested coredump. Even if this preparation
565      * fails, the SME will call PUTEST_STOP to tidy up.
566      */
567     priv->coredump_mode = 1;
568 
569     for (i = 0; i < 3; i++) {
570         CsrSdioClaim(priv->sdio);
571         r = CsrSdioRead16(priv->sdio, CHIP_HELPER_UNIFI_GBL_CHIP_VERSION*2, &data_u16);
572         CsrSdioRelease(priv->sdio);
573         if (r != CSR_RESULT_SUCCESS) {
574             unifi_info(priv, "Failed to read chip version! Try %d\n", i);
575 
576             /* First try, re-enable function which may have been disabled by f/w panic */
577             if (i == 0) {
578                 unifi_info(priv, "Try function enable\n");
579                 CsrSdioClaim(priv->sdio);
580                 r = CsrSdioFunctionEnable(priv->sdio);
581                 CsrSdioRelease(priv->sdio);
582                 if (r != CSR_RESULT_SUCCESS) {
583                     unifi_error(priv, "CsrSdioFunctionEnable failed %d\n", r);
584                 }
585                 continue;
586             }
587 
588             /* Subsequent tries, reset */
589 
590             /* Set clock speed low */
591             CsrSdioClaim(priv->sdio);
592             r = CsrSdioMaxBusClockFrequencySet(priv->sdio, UNIFI_SDIO_CLOCK_SAFE_HZ);
593             CsrSdioRelease(priv->sdio);
594             if (r != CSR_RESULT_SUCCESS) {
595                 unifi_error(priv, "CsrSdioMaxBusClockFrequencySet() failed %d\n", r);
596             }
597 
598             /* Card software reset */
599             CsrSdioClaim(priv->sdio);
600             r = unifi_card_hard_reset(priv->card);
601             CsrSdioRelease(priv->sdio);
602             if (r != CSR_RESULT_SUCCESS) {
603                 unifi_error(priv, "unifi_card_hard_reset() failed %d\n", r);
604             }
605         } else {
606             unifi_info(priv, "Read chip version of 0x%04x\n", data_u16);
607             break;
608         }
609     }
610 
611     if (r != CSR_RESULT_SUCCESS) {
612         unifi_error(priv, "Failed to prepare chip\n");
613         return -EIO;
614     }
615 
616     /* Stop the XAPs for coredump. The PUTEST_STOP must be called, e.g. at
617      * Raw SDIO deinit, to resume them.
618      */
619     CsrSdioClaim(priv->sdio);
620     r = unifi_card_stop_processor(priv->card, UNIFI_PROC_BOTH);
621     CsrSdioRelease(priv->sdio);
622     if (r != CSR_RESULT_SUCCESS) {
623         unifi_error(priv, "Failed to stop processors\n");
624     }
625 
626     return 0;
627 }
628 
unifi_putest_cmd52_block_read(unifi_priv_t * priv,unsigned char * arg)629 int unifi_putest_cmd52_block_read(unifi_priv_t *priv, unsigned char *arg)
630 {
631     struct unifi_putest_block_cmd52_r block_cmd52;
632     u8 *arg_pos;
633     unsigned int cmd_param_size;
634     CsrResult r;
635     u8 *block_local_buffer;
636 
637     arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
638     if (get_user(cmd_param_size, (int*)arg_pos)) {
639         unifi_error(priv,
640                     "cmd52r_block: Failed to get the argument\n");
641         return -EFAULT;
642     }
643 
644     if (cmd_param_size != sizeof(struct unifi_putest_block_cmd52_r)) {
645         unifi_error(priv,
646                     "cmd52r_block: cmd52 struct mismatch\n");
647         return -EINVAL;
648     }
649 
650     arg_pos += sizeof(unsigned int);
651     if (copy_from_user(&block_cmd52,
652                        (void*)arg_pos,
653                        sizeof(struct unifi_putest_block_cmd52_r))) {
654         unifi_error(priv,
655                     "cmd52r_block: Failed to get the cmd52 params\n");
656         return -EFAULT;
657     }
658 
659     unifi_trace(priv, UDBG2, "cmd52r_block: func=%d addr=0x%x len=0x%x ",
660                 block_cmd52.funcnum, block_cmd52.addr, block_cmd52.length);
661 
662     block_local_buffer = vmalloc(block_cmd52.length);
663     if (block_local_buffer == NULL) {
664         unifi_error(priv, "cmd52r_block: Failed to allocate buffer\n");
665         return -ENOMEM;
666     }
667 
668     CsrSdioClaim(priv->sdio);
669     r = unifi_card_readn(priv->card, block_cmd52.addr, block_local_buffer, block_cmd52.length);
670     CsrSdioRelease(priv->sdio);
671     if (r != CSR_RESULT_SUCCESS) {
672         unifi_error(priv, "cmd52r_block: unifi_readn failed\n");
673         return -EIO;
674     }
675 
676     if (copy_to_user((void*)block_cmd52.data,
677                      block_local_buffer,
678                      block_cmd52.length)) {
679         unifi_error(priv,
680                     "cmd52r_block: Failed to return the data\n");
681         return -EFAULT;
682     }
683 
684     return 0;
685 }
686