ahci_imx: depend on CONFIG_MFD_SYSCON
[linux-block.git] / drivers / staging / csr / putest.c
CommitLineData
635d2b00
GKH
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;
7e6f5794 27 u8 *arg_pos;
635d2b00
GKH
28 unsigned int cmd_param_size;
29 int r;
30 CsrResult csrResult;
31 unsigned char ret_buffer[32];
7e6f5794
GKH
32 u8 *ret_buffer_pos;
33 u8 retries;
635d2b00 34
7e6f5794 35 arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
635d2b00
GKH
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;
7e6f5794 80 ret_buffer_pos = (u8*)(((unifi_putest_command_t*)ret_buffer) + 1);
635d2b00
GKH
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;
7e6f5794 102 u8 *arg_pos;
635d2b00
GKH
103 unsigned int cmd_param_size;
104 CsrResult csrResult;
7e6f5794 105 u8 retries;
635d2b00 106
7e6f5794 107 arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
635d2b00
GKH
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;
7e6f5794 155 u8 *arg_pos;
635d2b00
GKH
156 unsigned int cmd_param_size;
157 int r;
158 CsrResult csrResult;
159 unsigned char ret_buffer[32];
7e6f5794 160 u8 *ret_buffer_pos;
635d2b00 161
7e6f5794 162 arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
635d2b00
GKH
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 }
95edd09e 183 CsrSdioClaim(priv->sdio);
635d2b00 184 csrResult = unifi_card_read16(priv->card, gp_r16_params.addr, &gp_r16_params.data);
95edd09e 185 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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;
7e6f5794 196 ret_buffer_pos = (u8*)(((unifi_putest_command_t*)ret_buffer) + 1);
635d2b00
GKH
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;
7e6f5794 217 u8 *arg_pos;
635d2b00
GKH
218 unsigned int cmd_param_size;
219 CsrResult csrResult;
220
7e6f5794 221 arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
635d2b00
GKH
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);
95edd09e 244 CsrSdioClaim(priv->sdio);
635d2b00 245 csrResult = unifi_card_write16(priv->card, gp_w16_params.addr, gp_w16_params.data);
95edd09e 246 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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);
95edd09e 270 csrResult = CsrSdioMaxBusClockFrequencySet(priv->sdio, sdio_clock_speed * 1000);
635d2b00
GKH
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) {
95edd09e 309 CsrSdioClaim(priv->sdio);
635d2b00 310 csrResult = unifi_start_processors(priv->card);
95edd09e 311 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 }
95edd09e 324 CsrSdioClaim(priv->sdio);
635d2b00 325 csrResult = unifi_init(priv->card);
95edd09e 326 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
95edd09e 343 CsrSdioClaim(priv->sdio);
635d2b00 344 csrResult = unifi_start_processors(priv->card);
95edd09e 345 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
95edd09e 438 CsrSdioClaim(priv->sdio);
635d2b00 439 csrResult = unifi_start_processors(priv->card);
95edd09e 440 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
95edd09e 448 CsrSdioClaim(priv->sdio);
635d2b00 449 csrResult = unifi_download(priv->card, 0x0c00);
95edd09e 450 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
786eeeb3 492 fw_buf = kmalloc(fw_length, GFP_KERNEL);
635d2b00
GKH
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");
55a27055 502 kfree(fw_buf);
635d2b00
GKH
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 */
95edd09e 518 CsrSdioClaim(priv->sdio);
635d2b00 519 csrResult = unifi_start_processors(priv->card);
95edd09e 520 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
95edd09e 528 CsrSdioClaim(priv->sdio);
635d2b00 529 csrResult = unifi_download(priv->card, 0x0c00);
95edd09e 530 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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;
55a27055 540 kfree(fw_buf);
635d2b00
GKH
541
542 return CsrHipResultToStatus(csrResult);
543}
544
545
546int unifi_putest_coredump_prepare(unifi_priv_t *priv, unsigned char *arg)
547{
8c87f69a 548 u16 data_u16;
95e326c2 549 s32 i;
635d2b00
GKH
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 */
95edd09e 599 CsrSdioClaim(priv->sdio);
635d2b00 600 r = unifi_card_hard_reset(priv->card);
95edd09e 601 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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 */
95edd09e 619 CsrSdioClaim(priv->sdio);
635d2b00 620 r = unifi_card_stop_processor(priv->card, UNIFI_PROC_BOTH);
95edd09e 621 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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;
7e6f5794 632 u8 *arg_pos;
635d2b00
GKH
633 unsigned int cmd_param_size;
634 CsrResult r;
7e6f5794 635 u8 *block_local_buffer;
635d2b00 636
7e6f5794 637 arg_pos = (u8*)(((unifi_putest_command_t*)arg) + 1);
635d2b00
GKH
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
95edd09e 668 CsrSdioClaim(priv->sdio);
635d2b00 669 r = unifi_card_readn(priv->card, block_cmd52.addr, block_local_buffer, block_cmd52.length);
95edd09e 670 CsrSdioRelease(priv->sdio);
635d2b00
GKH
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}