1 /*****************************************************************************
3 (c) Cambridge Silicon Radio Limited 2012
4 All rights reserved and confidential information of CSR
6 Refer to LICENSE.txt included with this source for details
9 *****************************************************************************/
12 * ---------------------------------------------------------------------------
13 * FILE: csr_wifi_hip_dump.c
16 * Routines for retrieving and buffering core status from the UniFi
18 * ---------------------------------------------------------------------------
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"
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 */
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 */
37 #define HIP_CDUMP_NUM_ZONES 7 /* Number of UniFi memory areas to capture */
39 /* Mini-coredump state */
40 typedef struct coredump_buf
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 */
47 u16 *zone[HIP_CDUMP_NUM_ZONES];
49 struct coredump_buf *next; /* circular list */
50 struct coredump_buf *prev; /* circular list */
53 /* Structure used to describe a zone of chip memory captured by mini-coredump */
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 */
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);
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 },
82 * ---------------------------------------------------------------------------
83 * unifi_coredump_request_at_next_reset
85 * Request that a mini-coredump is performed when the driver has
86 * completed resetting the UniFi device.
89 * card Pointer to card struct
90 * enable If non-zero, sets the request.
91 * If zero, cancels any pending request.
94 * CSR_RESULT_SUCCESS or CSR HIP error code
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 * ---------------------------------------------------------------------------
103 CsrResult unifi_coredump_request_at_next_reset(card_t *card, s8 enable)
111 unifi_trace(card->ospriv, UDBG2, "Mini-coredump requested after reset\n");
116 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
120 card->request_coredump_on_reset = enable?1 : 0;
121 r = CSR_RESULT_SUCCESS;
130 * ---------------------------------------------------------------------------
131 * unifi_coredump_handle_request
133 * Performs a coredump now, if one was requested, and clears the request.
136 * card Pointer to card struct
139 * CSR_RESULT_SUCCESS or CSR HIP error code
142 * ---------------------------------------------------------------------------
144 CsrResult unifi_coredump_handle_request(card_t *card)
146 CsrResult r = CSR_RESULT_SUCCESS;
152 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
156 if (card->request_coredump_on_reset == 1)
158 card->request_coredump_on_reset = 0;
159 r = unifi_coredump_capture(card, NULL);
169 * ---------------------------------------------------------------------------
170 * unifi_coredump_capture
172 * Capture the current status of the UniFi device.
173 * Various registers are buffered for future offline inspection.
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.
182 * CSR_RESULT_SUCCESS on success,
183 * CSR_RESULT_FAILURE SDIO error
184 * CSR_WIFI_HIP_RESULT_INVALID_VALUE Initialisation not complete
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 * ---------------------------------------------------------------------------
191 CsrResult unifi_coredump_capture(card_t *card, struct unifi_coredump_req *req)
193 CsrResult r = CSR_RESULT_SUCCESS;
194 static u16 dump_seq_no = 1;
195 CsrTime time_of_capture;
199 if (card->dump_next_write == NULL)
201 r = CSR_RESULT_SUCCESS;
205 /* Reject forced capture before initialisation has happened */
206 if (card->helper == NULL)
208 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
214 * Force a mini-coredump capture right now
216 time_of_capture = CsrTimeGet(NULL);
217 unifi_info(card->ospriv, "Mini-coredump capture at t=%u\n", time_of_capture);
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)
223 unifi_error(card->ospriv, "Failed to wake UniFi\n");
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)
233 unifi_error(card->ospriv, "Failed to stop UniFi XAPs\n");
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)
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;
249 /* Sequence no. of zero indicates slot not in use, so handle wrap */
250 if (dump_seq_no == 0)
255 unifi_trace(card->ospriv, UDBG3,
256 "Coredump (%p), SeqNo=%d, cur_read=%p, next_write=%p\n",
258 card->dump_cur_read->count,
259 card->dump_cur_read, card->dump_next_write);
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)
267 unifi_error(card->ospriv, "Failed to start UniFi XAPs\n");
274 } /* unifi_coredump_capture() */
278 * ---------------------------------------------------------------------------
279 * get_value_from_coredump
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
291 * >=0 Register value on success
292 * <0 Register out of range of any captured zones
295 * ---------------------------------------------------------------------------
297 static s32 get_value_from_coredump(const coredump_buffer *coreDump,
298 const unifi_coredump_space_t space,
299 const u16 offset_in_space)
305 const struct coredump_zone *def = &zonedef_table[0];
307 /* Search zone def table for a match with the requested memory space */
308 for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++, def++)
310 if (space == def->space)
312 zone_end_offset = def->offset + def->length;
314 /* Is the space offset contained in this zone? */
315 if (offset_in_space < zone_end_offset &&
316 offset_in_space >= def->offset)
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);
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);
335 * ---------------------------------------------------------------------------
336 * unifi_coredump_get_value
338 * Retrieve the value of a register buffered from a previous core dump,
339 * so that it may be reported back to application code.
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.
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
353 * ---------------------------------------------------------------------------
355 CsrResult unifi_coredump_get_value(card_t *card, struct unifi_coredump_req *req)
359 coredump_buffer *find_dump = NULL;
363 if (req == NULL || card == NULL)
365 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
369 if (card->dump_buf == NULL)
371 unifi_trace(card->ospriv, UDBG2, "No coredump buffers\n");
372 r = CSR_WIFI_HIP_RESULT_NOT_FOUND; /* Coredumping disabled */
375 if (card->dump_cur_read == NULL)
377 unifi_trace(card->ospriv, UDBG4, "No coredumps captured\n");
378 r = CSR_WIFI_HIP_RESULT_NOT_FOUND; /* No coredump yet captured */
382 /* Find the requested dump buffer */
386 find_dump = card->dump_cur_read;
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)
395 default: /* Number of steps back from current read position */
396 for (i = 0, find_dump = card->dump_cur_read;
398 i++, find_dump = find_dump->prev)
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)
408 /* Wrapped but still not found, index out of range */
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;
422 /* Check if the slot is actually filled with a core dump */
423 if (find_dump->count == 0)
425 unifi_trace(card->ospriv, UDBG4, "Not captured %d\n", req->index);
426 r = CSR_WIFI_HIP_RESULT_NOT_FOUND;
430 unifi_trace(card->ospriv, UDBG6, "Req index %d, found seq %d at step %d\n",
431 req->index, find_dump->count, i);
433 /* Find the appropriate entry in the buffer */
434 req->value = get_value_from_coredump(find_dump, req->space, (u16)req->offset);
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);
444 r = CSR_RESULT_SUCCESS;
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;
457 } /* unifi_coredump_get_value() */
461 * ---------------------------------------------------------------------------
462 * unifi_coredump_read_zone
464 * Captures a UniFi memory zone into a buffer on the host
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.
472 * CSR_RESULT_SUCCESS on success, or:
473 * CSR_RESULT_FAILURE SDIO error
474 * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
477 * It is assumed that the caller has already stopped the XAPs
478 * ---------------------------------------------------------------------------
480 static CsrResult unifi_coredump_read_zone(card_t *card, u16 *zonebuf, const struct coredump_zone *def)
486 if (zonebuf == NULL || def == NULL)
488 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
492 /* Select XAP CPU if necessary */
493 if (def->cpu != UNIFI_PROC_INVALID)
495 if (def->cpu != UNIFI_PROC_MAC && def->cpu != UNIFI_PROC_PHY)
497 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
500 r = unifi_set_proc_select(card, def->cpu);
501 if (r != CSR_RESULT_SUCCESS)
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);
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)
517 if (r != CSR_RESULT_SUCCESS)
519 unifi_error(card->ospriv, "Can't read UniFi shared data area\n");
530 * ---------------------------------------------------------------------------
531 * unifi_coredump_read_zones
533 * Walks through the table of on-chip memory zones defined in zonedef_table,
534 * and reads each of them from the UniFi chip
537 * card Pointer to card struct
538 * dump_buf Buffer into which register values will be dumped
541 * CSR_RESULT_SUCCESS on success, or:
542 * CSR_RESULT_FAILURE SDIO error
543 * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
546 * It is assumed that the caller has already stopped the XAPs
547 * ---------------------------------------------------------------------------
549 static CsrResult unifi_coredump_read_zones(card_t *card, coredump_buffer *dump_buf)
551 CsrResult r = CSR_RESULT_SUCCESS;
556 /* Walk the table of coredump zone definitions and read them from the chip */
558 (i < HIP_CDUMP_NUM_ZONES) && (r == 0);
561 r = unifi_coredump_read_zone(card, dump_buf->zone[i], &zonedef_table[i]);
570 * ---------------------------------------------------------------------------
571 * unifi_coredump_from_sdio
573 * Capture the status of the UniFi processors, over SDIO
576 * card Pointer to card struct
577 * reg_buffer Buffer into which register values will be dumped
580 * CSR_RESULT_SUCCESS on success, or:
581 * CSR_RESULT_FAILURE SDIO error
582 * CSR_WIFI_HIP_RESULT_INVALID_VALUE Parameter error
585 * ---------------------------------------------------------------------------
587 static CsrResult unifi_coredump_from_sdio(card_t *card, coredump_buffer *dump_buf)
595 if (dump_buf == NULL)
597 r = CSR_WIFI_HIP_RESULT_INVALID_VALUE;
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);
607 r = unifi_read_direct16(card, sdio_addr, &val);
608 if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
612 if (r != CSR_RESULT_SUCCESS)
614 unifi_error(card->ospriv, "Can't read GBL_CHIP_VERSION\n");
618 dump_buf->chip_ver = val;
619 dump_buf->fw_ver = card->build_id;
621 unifi_trace(card->ospriv, UDBG4, "chip_ver 0x%04x, fw_ver %u\n",
622 dump_buf->chip_ver, dump_buf->fw_ver);
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)
630 if (r != CSR_RESULT_SUCCESS)
632 unifi_error(card->ospriv, "Can't read UniFi memory areas\n");
639 } /* unifi_coredump_from_sdio() */
642 #ifndef UNIFI_DISABLE_COREDUMP
644 * ---------------------------------------------------------------------------
647 * Allocates a coredump linked-list node, and links it to the previous.
651 * prevnode Previous node to link into
654 * Pointer to valid coredump_buffer on success
655 * NULL on memory allocation failure
658 * Allocates "all or nothing"
659 * ---------------------------------------------------------------------------
662 coredump_buffer* new_coredump_node(void *ospriv, coredump_buffer *prevnode)
664 coredump_buffer *newnode = NULL;
669 /* Allocate node header */
670 newnode = kzalloc(sizeof(coredump_buffer), GFP_KERNEL);
676 /* Allocate chip memory zone capture buffers */
677 for (i = 0; i < HIP_CDUMP_NUM_ZONES; i++)
679 zone_size = sizeof(u16) * zonedef_table[i].length;
680 newzone = kzalloc(zone_size, GFP_KERNEL);
681 newnode->zone[i] = newzone;
684 unifi_error(ospriv, "Out of memory on coredump zone %d (%d words)\n",
685 i, zonedef_table[i].length);
690 /* Clean up if any zone alloc failed */
693 for (i = 0; newnode->zone[i] != NULL; i++)
695 kfree(newnode->zone[i]);
696 newnode->zone[i] = NULL;
700 /* Link to previous node */
701 newnode->prev = prevnode;
704 prevnode->next = newnode;
706 newnode->next = NULL;
712 #endif /* UNIFI_DISABLE_COREDUMP */
715 * ---------------------------------------------------------------------------
716 * unifi_coredump_init
718 * Allocates buffers for the automatic SDIO core dump
721 * card Pointer to card struct
722 * num_dump_buffers Number of buffers to reserve for coredumps
725 * CSR_RESULT_SUCCESS on success, or:
726 * CSR_WIFI_HIP_RESULT_NO_MEMORY memory allocation failed
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,
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 * ---------------------------------------------------------------------------
737 CsrResult unifi_coredump_init(card_t *card, u16 num_dump_buffers)
739 #ifndef UNIFI_DISABLE_COREDUMP
740 void *ospriv = card->ospriv;
741 coredump_buffer *prev = NULL;
742 coredump_buffer *newnode = NULL;
748 card->request_coredump_on_reset = 0;
749 card->dump_next_write = NULL;
750 card->dump_cur_read = NULL;
751 card->dump_buf = NULL;
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)
762 card->dump_buf = new_coredump_node(ospriv, NULL);
763 if (card->dump_buf == NULL)
767 prev = card->dump_buf;
768 newnode = card->dump_buf;
770 /* Add each subsequent node at tail */
771 for (i = 1; i < num_dump_buffers; i++)
773 newnode = new_coredump_node(ospriv, prev);
781 /* Link the first and last nodes to make the list circular */
782 card->dump_buf->prev = newnode;
783 newnode->next = card->dump_buf;
785 /* Set initial r/w access pointers */
786 card->dump_next_write = card->dump_buf;
787 card->dump_cur_read = NULL;
789 unifi_trace(ospriv, UDBG2, "Core dump configured (%d dumps max)\n", i);
794 return CSR_RESULT_SUCCESS;
796 #ifndef UNIFI_DISABLE_COREDUMP
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);
802 return CSR_WIFI_HIP_RESULT_NO_MEMORY;
804 } /* unifi_coreump_init() */
808 * ---------------------------------------------------------------------------
809 * unifi_coredump_free
811 * Free all memory dynamically allocated for core dump
814 * card Pointer to card struct
820 * ---------------------------------------------------------------------------
822 void unifi_coredump_free(card_t *card)
824 void *ospriv = card->ospriv;
825 coredump_buffer *node, *del_node;
830 unifi_trace(ospriv, UDBG2, "Core dump de-configured\n");
832 if (card->dump_buf == NULL)
837 node = card->dump_buf;
840 /* Free payload zones */
841 for (j = 0; j < HIP_CDUMP_NUM_ZONES; j++)
843 kfree(node->zone[j]);
844 node->zone[j] = NULL;
854 } while ((node != NULL) && (node != card->dump_buf));
856 unifi_trace(ospriv, UDBG3, "Freed %d coredump buffers\n", i);
858 card->dump_buf = NULL;
859 card->dump_next_write = NULL;
860 card->dump_cur_read = NULL;
863 } /* unifi_coredump_free() */