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