Root/drivers/staging/csr/putest.c

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
24int 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
99int 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
152int 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
214int 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
256int 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
282int 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
337int 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
381int 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... */
458free_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
467int 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
537free_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
546int 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
629int 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

Archive Download this file



interactive