Merge remote-tracking branch 'upstream' into next
[cascardo/linux.git] / 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     CsrTime    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     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     {
116         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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  */
144 CsrResult unifi_coredump_handle_request(card_t *card)
145 {
146     CsrResult r = CSR_RESULT_SUCCESS;
147
148     func_enter();
149
150     if (card == NULL)
151     {
152         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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  */
191 CsrResult unifi_coredump_capture(card_t *card, struct unifi_coredump_req *req)
192 {
193     CsrResult r = CSR_RESULT_SUCCESS;
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     {
208         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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 */
220     r = unifi_set_host_state(card, UNIFI_HOST_STATE_AWAKE);
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");
230     r = unifi_card_stop_processor(card, UNIFI_PROC_BOTH);
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");
264     r = card_start_processor(card, UNIFI_PROC_BOTH);
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,
298                                         const unifi_coredump_space_t space,
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
322                 unifi_trace(NULL, UDBG6,
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  */
355 CsrResult unifi_coredump_get_value(card_t *card, struct unifi_coredump_req *req)
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     {
365         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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);
413                         r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
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);
426         r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
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     {
488         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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         {
497             r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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));
513     if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
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 {
551     CsrResult r = CSR_RESULT_SUCCESS;
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     {
597         r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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);
608         if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
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);
626     if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
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;
741     coredump_buffer *prev = NULL;
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();
802     return CSR_WIFI_HIP_RESULT_NO_MEMORY;
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  */
822 void unifi_coredump_free(card_t *card)
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