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