Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
csr_wifi_hip_dump.c
Go to the documentation of this file.
1 /*****************************************************************************
2 
3  (c) Cambridge Silicon Radio Limited 2012
4  All rights reserved and confidential information of CSR
5 
6  Refer to LICENSE.txt included with this source for details
7  on the license terms.
8 
9 *****************************************************************************/
10 
11 /*
12  * ---------------------------------------------------------------------------
13  * FILE: csr_wifi_hip_dump.c
14  *
15  * PURPOSE:
16  * Routines for retrieving and buffering core status from the UniFi
17  *
18  * ---------------------------------------------------------------------------
19  */
20 #include <linux/slab.h>
21 #include "csr_wifi_hip_unifi.h"
23 #include "csr_wifi_hip_card.h"
24 
25 /* Locations to capture in dump (XAP words) */
26 #define HIP_CDUMP_FIRST_CPUREG (0xFFE0) /* First CPU register */
27 #define HIP_CDUMP_FIRST_LO (0) /* Start of low address range */
28 #define HIP_CDUMP_FIRST_HI_MAC (0x3C00) /* Start of MAC high area */
29 #define HIP_CDUMP_FIRST_HI_PHY (0x1C00) /* Start of PHY high area */
30 #define HIP_CDUMP_FIRST_SH (0) /* Start of shared memory area */
31 
32 #define HIP_CDUMP_NCPUREGS (10) /* No. of 16-bit XAP registers */
33 #define HIP_CDUMP_NWORDS_LO (0x0100) /* Low area size in 16-bit words */
34 #define HIP_CDUMP_NWORDS_HI (0x0400) /* High area size in 16-bit words */
35 #define HIP_CDUMP_NWORDS_SH (0x0500) /* Shared memory area size, 16-bit words */
36 
37 #define HIP_CDUMP_NUM_ZONES 7 /* Number of UniFi memory areas to capture */
38 
39 /* Mini-coredump state */
40 typedef struct coredump_buf
41 {
42  u16 count; /* serial number of dump */
43  CsrTime timestamp; /* host's system time at capture */
44  s16 requestor; /* request: 0=auto dump, 1=manual */
48 
49  struct coredump_buf *next; /* circular list */
50  struct coredump_buf *prev; /* circular list */
52 
53 /* Structure used to describe a zone of chip memory captured by mini-coredump */
55 {
56  unifi_coredump_space_t space; /* XAP memory space this zone covers */
57  enum unifi_dbg_processors_select cpu; /* XAP CPU core selector */
58  u32 gp; /* Generic Pointer to memory zone on XAP */
59  u16 offset; /* 16-bit XAP word offset of zone in memory space */
60  u16 length; /* Length of zone in XAP words */
61 };
62 
63 static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf);
64 static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf);
65 static CsrResult unifi_coredump_read_zone(card_t *card, u16 *zone,
66  const struct coredump_zone *def);
67 static s32 get_value_from_coredump(const coredump_buffer *dump,
68  const unifi_coredump_space_t space, const u16 offset);
69 
70 /* Table of chip memory zones we capture on mini-coredump */
71 static const struct coredump_zone zonedef_table[HIP_CDUMP_NUM_ZONES] = {
79 };
80 
81 /*
82  * ---------------------------------------------------------------------------
83  * unifi_coredump_request_at_next_reset
84  *
85  * Request that a mini-coredump is performed when the driver has
86  * completed resetting the UniFi device.
87  *
88  * Arguments:
89  * card Pointer to card struct
90  * enable If non-zero, sets the request.
91  * If zero, cancels any pending request.
92  *
93  * Returns:
94  * CSR_RESULT_SUCCESS or CSR HIP error code
95  *
96  * Notes:
97  * This function is typically called once the driver has detected that
98  * the UniFi device has become unresponsive due to crash, or internal
99  * watchdog reset. The driver must reset it to regain communication and,
100  * immediately after that, the mini-coredump can be captured.
101  * ---------------------------------------------------------------------------
102  */
104 {
105  CsrResult r;
106 
107  func_enter();
108 
109  if (enable)
110  {
111  unifi_trace(card->ospriv, UDBG2, "Mini-coredump requested after reset\n");
112  }
113 
114  if (card == NULL)
115  {
117  }
118  else
119  {
120  card->request_coredump_on_reset = enable?1 : 0;
121  r = CSR_RESULT_SUCCESS;
122  }
123 
124  func_exit_r(r);
125  return r;
126 }
127 
128 
129 /*
130  * ---------------------------------------------------------------------------
131  * unifi_coredump_handle_request
132  *
133  * Performs a coredump now, if one was requested, and clears the request.
134  *
135  * Arguments:
136  * card Pointer to card struct
137  *
138  * Returns:
139  * CSR_RESULT_SUCCESS or CSR HIP error code
140  *
141  * Notes:
142  * ---------------------------------------------------------------------------
143  */
145 {
147 
148  func_enter();
149 
150  if (card == NULL)
151  {
153  }
154  else
155  {
156  if (card->request_coredump_on_reset == 1)
157  {
158  card->request_coredump_on_reset = 0;
159  r = unifi_coredump_capture(card, NULL);
160  }
161  }
162 
163  func_exit_r(r);
164  return r;
165 }
166 
167 
168 /*
169  * ---------------------------------------------------------------------------
170  * unifi_coredump_capture
171  *
172  * Capture the current status of the UniFi device.
173  * Various registers are buffered for future offline inspection.
174  *
175  * Arguments:
176  * card Pointer to card struct
177  * req Pointer to request struct, or NULL:
178  * A coredump requested manually by the user app
179  * will have a request struct pointer, an automatic
180  * coredump will have a NULL pointer.
181  * Returns:
182  * CSR_RESULT_SUCCESS on success,
183  * CSR_RESULT_FAILURE SDIO error
184  * CSR_WIFI_HIP_RESULT_INVALID_VALUE Initialisation not complete
185  *
186  * Notes:
187  * The result is a filled entry in the circular buffer of core dumps,
188  * values from which can be extracted to userland via an ioctl.
189  * ---------------------------------------------------------------------------
190  */
192 {
194  static u16 dump_seq_no = 1;
195  CsrTime time_of_capture;
196 
197  func_enter();
198 
199  if (card->dump_next_write == NULL)
200  {
201  r = CSR_RESULT_SUCCESS;
202  goto done;
203  }
204 
205  /* Reject forced capture before initialisation has happened */
206  if (card->helper == NULL)
207  {
209  goto done;
210  }
211 
212 
213  /*
214  * Force a mini-coredump capture right now
215  */
216  time_of_capture = CsrTimeGet(NULL);
217  unifi_info(card->ospriv, "Mini-coredump capture at t=%u\n", time_of_capture);
218 
219  /* Wake up the processors so we can talk to them */
221  if (r != CSR_RESULT_SUCCESS)
222  {
223  unifi_error(card->ospriv, "Failed to wake UniFi\n");
224  goto done;
225  }
226  CsrThreadSleep(20);
227 
228  /* Stop both XAPs */
229  unifi_trace(card->ospriv, UDBG4, "Stopping XAPs for coredump capture\n");
231  if (r != CSR_RESULT_SUCCESS)
232  {
233  unifi_error(card->ospriv, "Failed to stop UniFi XAPs\n");
234  goto done;
235  }
236 
237  /* Dump core into the next available slot in the circular list */
238  r = unifi_coredump_from_sdio(card, card->dump_next_write);
239  if (r == CSR_RESULT_SUCCESS)
240  {
241  /* Record whether the dump was manual or automatic */
242  card->dump_next_write->requestor = (req?1 : 0);
243  card->dump_next_write->timestamp = time_of_capture;
244  /* Advance to the next buffer */
245  card->dump_next_write->count = dump_seq_no++;
246  card->dump_cur_read = card->dump_next_write;
247  card->dump_next_write = card->dump_next_write->next;
248 
249  /* Sequence no. of zero indicates slot not in use, so handle wrap */
250  if (dump_seq_no == 0)
251  {
252  dump_seq_no = 1;
253  }
254 
255  unifi_trace(card->ospriv, UDBG3,
256  "Coredump (%p), SeqNo=%d, cur_read=%p, next_write=%p\n",
257  req,
258  card->dump_cur_read->count,
259  card->dump_cur_read, card->dump_next_write);
260  }
261 
262  /* Start both XAPs */
263  unifi_trace(card->ospriv, UDBG4, "Restart XAPs after coredump\n");
265  if (r != CSR_RESULT_SUCCESS)
266  {
267  unifi_error(card->ospriv, "Failed to start UniFi XAPs\n");
268  goto done;
269  }
270 
271 done:
272  func_exit_r(r);
273  return r;
274 } /* unifi_coredump_capture() */
275 
276 
277 /*
278  * ---------------------------------------------------------------------------
279  * get_value_from_coredump
280  *
281  *
282  *
283  * Arguments:
284  * dump Pointer to buffered coredump data
285  * offset_in_space XAP memory space to retrieve from the buffer (there
286  * may be more than one zone covering the same memory
287  * space, but starting from different offsets).
288  * offset Offset within the XAP memory space to be retrieved
289  *
290  * Returns:
291  * >=0 Register value on success
292  * <0 Register out of range of any captured zones
293  *
294  * Notes:
295  * ---------------------------------------------------------------------------
296  */
297 static s32 get_value_from_coredump(const coredump_buffer *coreDump,
299  const u16 offset_in_space)
300 {
301  s32 r = -1;
302  u16 offset_in_zone;
303  u32 zone_end_offset;
304  s32 i;
305  const struct coredump_zone *def = &zonedef_table[0];
306 
307  /* Search zone def table for a match with the requested memory space */
308  for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++, def++)
309  {
310  if (space == def->space)
311  {
312  zone_end_offset = def->offset + def->length;
313 
314  /* Is the space offset contained in this zone? */
315  if (offset_in_space < zone_end_offset &&
316  offset_in_space >= def->offset)
317  {
318  /* Calculate the offset of data within the zone buffer */
319  offset_in_zone = offset_in_space - def->offset;
320  r = (s32) * (coreDump->zone[i] + offset_in_zone);
321 
323  "sp %d, offs 0x%04x = 0x%04x (in z%d 0x%04x->0x%04x)\n",
324  space, offset_in_space, r,
325  i, def->offset, zone_end_offset - 1);
326  break;
327  }
328  }
329  }
330  return r;
331 }
332 
333 
334 /*
335  * ---------------------------------------------------------------------------
336  * unifi_coredump_get_value
337  *
338  * Retrieve the value of a register buffered from a previous core dump,
339  * so that it may be reported back to application code.
340  *
341  * Arguments:
342  * card Pointer to card struct
343  * req_reg Pointer to request parameter partially filled. This
344  * function puts in the values retrieved from the dump.
345  *
346  * Returns:
347  * CSR_RESULT_SUCCESS on success, or:
348  * CSR_WIFI_HIP_RESULT_INVALID_VALUE Null parameter error
349  * CSR_WIFI_HIP_RESULT_RANGE Register out of range
350  * CSR_WIFI_HIP_RESULT_NOT_FOUND Dump index not (yet) captured
351  *
352  * Notes:
353  * ---------------------------------------------------------------------------
354  */
356 {
357  CsrResult r;
358  s32 i = 0;
359  coredump_buffer *find_dump = NULL;
360 
361  func_enter();
362 
363  if (req == NULL || card == NULL)
364  {
366  goto done;
367  }
368  req->value = -1;
369  if (card->dump_buf == NULL)
370  {
371  unifi_trace(card->ospriv, UDBG2, "No coredump buffers\n");
372  r = CSR_WIFI_HIP_RESULT_NOT_FOUND; /* Coredumping disabled */
373  goto done;
374  }
375  if (card->dump_cur_read == NULL)
376  {
377  unifi_trace(card->ospriv, UDBG4, "No coredumps captured\n");
378  r = CSR_WIFI_HIP_RESULT_NOT_FOUND; /* No coredump yet captured */
379  goto done;
380  }
381 
382  /* Find the requested dump buffer */
383  switch (req->index)
384  {
385  case 0: /* Newest */
386  find_dump = card->dump_cur_read;
387  break;
388  case -1: /* Oldest: The next used slot forward */
389  for (find_dump = card->dump_cur_read->next;
390  (find_dump->count == 0) && (find_dump != card->dump_cur_read);
391  find_dump = card->dump_cur_read->next)
392  {
393  }
394  break;
395  default: /* Number of steps back from current read position */
396  for (i = 0, find_dump = card->dump_cur_read;
397  i < req->index;
398  i++, find_dump = find_dump->prev)
399  {
400  /* Walk the list for the index'th entry, but
401  * stop when about to wrap. */
402  unifi_trace(card->ospriv, UDBG6,
403  "%d: %d, @%p, p=%p, n=%p, cr=%p, h=%p\n",
404  i, find_dump->count, find_dump, find_dump->prev,
405  find_dump->next, card->dump_cur_read, card->dump_buf);
406  if (find_dump->prev == card->dump_cur_read)
407  {
408  /* Wrapped but still not found, index out of range */
409  if (i != req->index)
410  {
411  unifi_trace(card->ospriv, UDBG6,
412  "Dump index %d not found %d\n", req->index, i);
414  goto done;
415  }
416  break;
417  }
418  }
419  break;
420  }
421 
422  /* Check if the slot is actually filled with a core dump */
423  if (find_dump->count == 0)
424  {
425  unifi_trace(card->ospriv, UDBG4, "Not captured %d\n", req->index);
427  goto done;
428  }
429 
430  unifi_trace(card->ospriv, UDBG6, "Req index %d, found seq %d at step %d\n",
431  req->index, find_dump->count, i);
432 
433  /* Find the appropriate entry in the buffer */
434  req->value = get_value_from_coredump(find_dump, req->space, (u16)req->offset);
435  if (req->value < 0)
436  {
437  r = CSR_WIFI_HIP_RESULT_RANGE; /* Un-captured register */
438  unifi_trace(card->ospriv, UDBG4,
439  "Can't read space %d, reg 0x%x from coredump buffer %d\n",
440  req->space, req->offset, req->index);
441  }
442  else
443  {
444  r = CSR_RESULT_SUCCESS;
445  }
446 
447  /* Update the private request structure with the found values */
448  req->chip_ver = find_dump->chip_ver;
449  req->fw_ver = find_dump->fw_ver;
450  req->timestamp = find_dump->timestamp;
451  req->requestor = find_dump->requestor;
452  req->serial = find_dump->count;
453 
454 done:
455  func_exit_r(r);
456  return r;
457 } /* unifi_coredump_get_value() */
458 
459 
460 /*
461  * ---------------------------------------------------------------------------
462  * unifi_coredump_read_zone
463  *
464  * Captures a UniFi memory zone into a buffer on the host
465  *
466  * Arguments:
467  * card Pointer to card struct
468  * zonebuf Pointer to on-host buffer to dump the memory zone into
469  * def Pointer to description of the memory zone to read from UniFi.
470  *
471  * Returns:
472  * CSR_RESULT_SUCCESS on success, or:
473  * CSR_RESULT_FAILURE SDIO error
474  * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
475  *
476  * Notes:
477  * It is assumed that the caller has already stopped the XAPs
478  * ---------------------------------------------------------------------------
479  */
480 static CsrResult unifi_coredump_read_zone(card_t *card, u16 *zonebuf, const struct coredump_zone *def)
481 {
482  CsrResult r;
483 
484  func_enter();
485 
486  if (zonebuf == NULL || def == NULL)
487  {
489  goto done;
490  }
491 
492  /* Select XAP CPU if necessary */
493  if (def->cpu != UNIFI_PROC_INVALID)
494  {
495  if (def->cpu != UNIFI_PROC_MAC && def->cpu != UNIFI_PROC_PHY)
496  {
498  goto done;
499  }
500  r = unifi_set_proc_select(card, def->cpu);
501  if (r != CSR_RESULT_SUCCESS)
502  {
503  goto done;
504  }
505  }
506 
507  unifi_trace(card->ospriv, UDBG4,
508  "Dump sp %d, offs 0x%04x, 0x%04x words @GP=%08x CPU %d\n",
509  def->space, def->offset, def->length, def->gp, def->cpu);
510 
511  /* Read on-chip RAM (byte-wise) */
512  r = unifi_card_readn(card, def->gp, zonebuf, (u16)(def->length * 2));
514  {
515  goto done;
516  }
517  if (r != CSR_RESULT_SUCCESS)
518  {
519  unifi_error(card->ospriv, "Can't read UniFi shared data area\n");
520  goto done;
521  }
522 
523 done:
524  func_exit_r(r);
525  return r;
526 }
527 
528 
529 /*
530  * ---------------------------------------------------------------------------
531  * unifi_coredump_read_zones
532  *
533  * Walks through the table of on-chip memory zones defined in zonedef_table,
534  * and reads each of them from the UniFi chip
535  *
536  * Arguments:
537  * card Pointer to card struct
538  * dump_buf Buffer into which register values will be dumped
539  *
540  * Returns:
541  * CSR_RESULT_SUCCESS on success, or:
542  * CSR_RESULT_FAILURE SDIO error
543  * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
544  *
545  * Notes:
546  * It is assumed that the caller has already stopped the XAPs
547  * ---------------------------------------------------------------------------
548  */
549 static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf)
550 {
552  s32 i;
553 
554  func_enter();
555 
556  /* Walk the table of coredump zone definitions and read them from the chip */
557  for (i = 0;
558  (i < HIP_CDUMP_NUM_ZONES) && (r == 0);
559  i++)
560  {
561  r = unifi_coredump_read_zone(card, dump_buf->zone[i], &zonedef_table[i]);
562  }
563 
564  func_exit_r(r);
565  return r;
566 }
567 
568 
569 /*
570  * ---------------------------------------------------------------------------
571  * unifi_coredump_from_sdio
572  *
573  * Capture the status of the UniFi processors, over SDIO
574  *
575  * Arguments:
576  * card Pointer to card struct
577  * reg_buffer Buffer into which register values will be dumped
578  *
579  * Returns:
580  * CSR_RESULT_SUCCESS on success, or:
581  * CSR_RESULT_FAILURE SDIO error
582  * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
583  *
584  * Notes:
585  * ---------------------------------------------------------------------------
586  */
587 static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf)
588 {
589  u16 val;
590  CsrResult r;
591  u32 sdio_addr;
592 
593  func_enter();
594 
595  if (dump_buf == NULL)
596  {
598  goto done;
599  }
600 
601 
602  /* Chip and firmware version */
603  unifi_trace(card->ospriv, UDBG4, "Get chip version\n");
604  sdio_addr = 2 * ChipHelper_GBL_CHIP_VERSION(card->helper);
605  if (sdio_addr != 0)
606  {
607  r = unifi_read_direct16(card, sdio_addr, &val);
609  {
610  goto done;
611  }
612  if (r != CSR_RESULT_SUCCESS)
613  {
614  unifi_error(card->ospriv, "Can't read GBL_CHIP_VERSION\n");
615  goto done;
616  }
617  }
618  dump_buf->chip_ver = val;
619  dump_buf->fw_ver = card->build_id;
620 
621  unifi_trace(card->ospriv, UDBG4, "chip_ver 0x%04x, fw_ver %u\n",
622  dump_buf->chip_ver, dump_buf->fw_ver);
623 
624  /* Capture the memory zones required from UniFi */
625  r = unifi_coredump_read_zones(card, dump_buf);
627  {
628  goto done;
629  }
630  if (r != CSR_RESULT_SUCCESS)
631  {
632  unifi_error(card->ospriv, "Can't read UniFi memory areas\n");
633  goto done;
634  }
635 
636 done:
637  func_exit_r(r);
638  return r;
639 } /* unifi_coredump_from_sdio() */
640 
641 
642 #ifndef UNIFI_DISABLE_COREDUMP
643 /*
644  * ---------------------------------------------------------------------------
645  * new_coredump_node
646  *
647  * Allocates a coredump linked-list node, and links it to the previous.
648  *
649  * Arguments:
650  * ospriv OS context
651  * prevnode Previous node to link into
652  *
653  * Returns:
654  * Pointer to valid coredump_buffer on success
655  * NULL on memory allocation failure
656  *
657  * Notes:
658  * Allocates "all or nothing"
659  * ---------------------------------------------------------------------------
660  */
661 static
662 coredump_buffer* new_coredump_node(void *ospriv, coredump_buffer *prevnode)
663 {
664  coredump_buffer *newnode = NULL;
665  u16 *newzone = NULL;
666  s32 i;
667  u32 zone_size;
668 
669  /* Allocate node header */
670  newnode = kzalloc(sizeof(coredump_buffer), GFP_KERNEL);
671  if (newnode == NULL)
672  {
673  return NULL;
674  }
675 
676  /* Allocate chip memory zone capture buffers */
677  for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++)
678  {
679  zone_size = sizeof(u16) * zonedef_table[i].length;
680  newzone = kzalloc(zone_size, GFP_KERNEL);
681  newnode->zone[i] = newzone;
682  if (newzone == NULL)
683  {
684  unifi_error(ospriv, "Out of memory on coredump zone %d (%d words)\n",
685  i, zonedef_table[i].length);
686  break;
687  }
688  }
689 
690  /* Clean up if any zone alloc failed */
691  if (newzone == NULL)
692  {
693  for (i = 0; newnode->zone[i] != NULL; i++)
694  {
695  kfree(newnode->zone[i]);
696  newnode->zone[i] = NULL;
697  }
698  }
699 
700  /* Link to previous node */
701  newnode->prev = prevnode;
702  if (prevnode)
703  {
704  prevnode->next = newnode;
705  }
706  newnode->next = NULL;
707 
708  return newnode;
709 }
710 
711 
712 #endif /* UNIFI_DISABLE_COREDUMP */
713 
714 /*
715  * ---------------------------------------------------------------------------
716  * unifi_coredump_init
717  *
718  * Allocates buffers for the automatic SDIO core dump
719  *
720  * Arguments:
721  * card Pointer to card struct
722  * num_dump_buffers Number of buffers to reserve for coredumps
723  *
724  * Returns:
725  * CSR_RESULT_SUCCESS on success, or:
726  * CSR_WIFI_HIP_RESULT_NO_MEMORY memory allocation failed
727  *
728  * Notes:
729  * Allocates space in advance, to be used for the last n coredump buffers
730  * the intention being that the size is sufficient for at least one dump,
731  * probably several.
732  * It's probably advisable to have at least 2 coredump buffers to allow
733  * one to be enquired with the unifi_coredump tool, while leaving another
734  * free for capturing.
735  * ---------------------------------------------------------------------------
736  */
737 CsrResult unifi_coredump_init(card_t *card, u16 num_dump_buffers)
738 {
739 #ifndef UNIFI_DISABLE_COREDUMP
740  void *ospriv = card->ospriv;
742  coredump_buffer *newnode = NULL;
743  u32 i = 0;
744 #endif
745 
746  func_enter();
747 
748  card->request_coredump_on_reset = 0;
749  card->dump_next_write = NULL;
750  card->dump_cur_read = NULL;
751  card->dump_buf = NULL;
752 
753 #ifndef UNIFI_DISABLE_COREDUMP
754  unifi_trace(ospriv, UDBG1,
755  "Allocate buffers for %d core dumps\n", num_dump_buffers);
756  if (num_dump_buffers == 0)
757  {
758  goto done;
759  }
760 
761  /* Root node */
762  card->dump_buf = new_coredump_node(ospriv, NULL);
763  if (card->dump_buf == NULL)
764  {
765  goto fail;
766  }
767  prev = card->dump_buf;
768  newnode = card->dump_buf;
769 
770  /* Add each subsequent node at tail */
771  for (i = 1; i < num_dump_buffers; i++)
772  {
773  newnode = new_coredump_node(ospriv, prev);
774  if (newnode == NULL)
775  {
776  goto fail;
777  }
778  prev = newnode;
779  }
780 
781  /* Link the first and last nodes to make the list circular */
782  card->dump_buf->prev = newnode;
783  newnode->next = card->dump_buf;
784 
785  /* Set initial r/w access pointers */
786  card->dump_next_write = card->dump_buf;
787  card->dump_cur_read = NULL;
788 
789  unifi_trace(ospriv, UDBG2, "Core dump configured (%d dumps max)\n", i);
790 
791 done:
792 #endif
793  func_exit();
794  return CSR_RESULT_SUCCESS;
795 
796 #ifndef UNIFI_DISABLE_COREDUMP
797 fail:
798  /* Unwind what we allocated so far */
799  unifi_error(ospriv, "Out of memory allocating core dump node %d\n", i);
800  unifi_coredump_free(card);
801  func_exit();
803 #endif
804 } /* unifi_coreump_init() */
805 
806 
807 /*
808  * ---------------------------------------------------------------------------
809  * unifi_coredump_free
810  *
811  * Free all memory dynamically allocated for core dump
812  *
813  * Arguments:
814  * card Pointer to card struct
815  *
816  * Returns:
817  * None
818  *
819  * Notes:
820  * ---------------------------------------------------------------------------
821  */
823 {
824  void *ospriv = card->ospriv;
825  coredump_buffer *node, *del_node;
826  s16 i = 0;
827  s16 j;
828 
829  func_enter();
830  unifi_trace(ospriv, UDBG2, "Core dump de-configured\n");
831 
832  if (card->dump_buf == NULL)
833  {
834  return;
835  }
836 
837  node = card->dump_buf;
838  do
839  {
840  /* Free payload zones */
841  for (j = 0; j < HIP_CDUMP_NUM_ZONES; j++)
842  {
843  kfree(node->zone[j]);
844  node->zone[j] = NULL;
845  }
846 
847  /* Detach */
848  del_node = node;
849  node = node->next;
850 
851  /* Free header */
852  kfree(del_node);
853  i++;
854  } while ((node != NULL) && (node != card->dump_buf));
855 
856  unifi_trace(ospriv, UDBG3, "Freed %d coredump buffers\n", i);
857 
858  card->dump_buf = NULL;
859  card->dump_next_write = NULL;
860  card->dump_cur_read = NULL;
861 
862  func_exit();
863 } /* unifi_coredump_free() */
864 
865