Root/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 */
40typedef 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 */
54struct 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
63static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf);
64static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf);
65static CsrResult unifi_coredump_read_zone(card_t *card, u16 *zone,
66                                          const struct coredump_zone *def);
67static 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 */
71static 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 */
103CsrResult 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 */
144CsrResult 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 */
191CsrResult 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
271done:
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 */
297static 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 */
355CsrResult 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
454done:
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 */
480static 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
523done:
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 */
549static 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 */
587static 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
636done:
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 */
661static
662coredump_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 */
737CsrResult 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
791done:
792#endif
793    func_exit();
794    return CSR_RESULT_SUCCESS;
795
796#ifndef UNIFI_DISABLE_COREDUMP
797fail:
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 */
822void 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
866

Archive Download this file



interactive