Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
putest.c
Go to the documentation of this file.
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"
20 
21 #define UNIFI_PROC_BOTH 3
22 
23 
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 */
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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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);
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);
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 
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 }