1 /*
2 * DHD debugability support
3 *
4 * <<Broadcom-WL-IPTag/Open:>>
5 *
6 * Copyright (C) 1999-2019, Broadcom.
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions
18 * of the license of that module. An independent module is a module which is
19 * not derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
25 *
26 * $Id: dhd_debug.c 823976 2019-06-06 11:39:07Z $
27 */
28
29 #include <typedefs.h>
30 #include <osl.h>
31 #include <bcmutils.h>
32 #include <bcmendian.h>
33 #include <dngl_stats.h>
34 #include <dhd.h>
35 #include <dhd_dbg.h>
36 #include <dhd_dbg_ring.h>
37 #include <dhd_debug.h>
38 #include <dhd_mschdbg.h>
39 #include <dhd_bus.h>
40
41 #include <event_log.h>
42 #include <event_trace.h>
43 #include <msgtrace.h>
44
45 #define DHD_PKT_INFO DHD_ERROR
46 struct map_table {
47 uint16 fw_id;
48 uint16 host_id;
49 char *desc;
50 };
51
52 struct map_table event_map[] = {
53 {WLC_E_AUTH, WIFI_EVENT_AUTH_COMPLETE, "AUTH_COMPLETE"},
54 {WLC_E_ASSOC, WIFI_EVENT_ASSOC_COMPLETE, "ASSOC_COMPLETE"},
55 {TRACE_FW_AUTH_STARTED, WIFI_EVENT_FW_AUTH_STARTED, "AUTH STARTED"},
56 {TRACE_FW_ASSOC_STARTED, WIFI_EVENT_FW_ASSOC_STARTED, "ASSOC STARTED"},
57 {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_FW_RE_ASSOC_STARTED,
58 "REASSOC STARTED"},
59 {TRACE_G_SCAN_STARTED, WIFI_EVENT_G_SCAN_STARTED, "GSCAN STARTED"},
60 {WLC_E_PFN_SCAN_COMPLETE, WIFI_EVENT_G_SCAN_COMPLETE, "GSCAN COMPLETE"},
61 {WLC_E_DISASSOC, WIFI_EVENT_DISASSOCIATION_REQUESTED, "DIASSOC REQUESTED"},
62 {WLC_E_REASSOC, WIFI_EVENT_RE_ASSOCIATION_REQUESTED, "REASSOC REQUESTED"},
63 {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_REQUESTED, "ROAM REQUESTED"},
64 {WLC_E_BEACON_FRAME_RX, WIFI_EVENT_BEACON_RECEIVED, "BEACON Received"},
65 {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_SCAN_STARTED,
66 "ROAM SCAN STARTED"},
67 {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE,
68 "ROAM SCAN COMPLETED"},
69 {TRACE_ROAM_AUTH_STARTED, WIFI_EVENT_ROAM_AUTH_STARTED,
70 "ROAM AUTH STARTED"},
71 {WLC_E_AUTH, WIFI_EVENT_ROAM_AUTH_COMPLETE, "ROAM AUTH COMPLETED"},
72 {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_ROAM_ASSOC_STARTED,
73 "ROAM ASSOC STARTED"},
74 {WLC_E_ASSOC, WIFI_EVENT_ROAM_ASSOC_COMPLETE, "ROAM ASSOC COMPLETED"},
75 {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE,
76 "ROAM SCAN COMPLETED"},
77 {TRACE_BT_COEX_BT_SCO_START, WIFI_EVENT_BT_COEX_BT_SCO_START,
78 "BT SCO START"},
79 {TRACE_BT_COEX_BT_SCO_STOP, WIFI_EVENT_BT_COEX_BT_SCO_STOP, "BT SCO STOP"},
80 {TRACE_BT_COEX_BT_SCAN_START, WIFI_EVENT_BT_COEX_BT_SCAN_START,
81 "BT COEX SCAN START"},
82 {TRACE_BT_COEX_BT_SCAN_STOP, WIFI_EVENT_BT_COEX_BT_SCAN_STOP,
83 "BT COEX SCAN STOP"},
84 {TRACE_BT_COEX_BT_HID_START, WIFI_EVENT_BT_COEX_BT_HID_START,
85 "BT HID START"},
86 {TRACE_BT_COEX_BT_HID_STOP, WIFI_EVENT_BT_COEX_BT_HID_STOP, "BT HID STOP"},
87 {WLC_E_EAPOL_MSG, WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED,
88 "FW EAPOL PKT RECEIVED"},
89 {TRACE_FW_EAPOL_FRAME_TRANSMIT_START,
90 WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START, "FW EAPOL PKT TRANSMITED"},
91 {TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP,
92 WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP, "FW EAPOL PKT TX STOPPED"},
93 {TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE,
94 WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE, "BLOCK ACK NEGO COMPLETED"},
95 };
96
97 struct map_table event_tag_map[] = {
98 {TRACE_TAG_VENDOR_SPECIFIC, WIFI_TAG_VENDOR_SPECIFIC,
99 "VENDOR SPECIFIC DATA"},
100 {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"},
101 {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"},
102 {TRACE_TAG_SSID, WIFI_TAG_SSID, "SSID"},
103 {TRACE_TAG_STATUS, WIFI_TAG_STATUS, "STATUS"},
104 {TRACE_TAG_CHANNEL_SPEC, WIFI_TAG_CHANNEL_SPEC, "CHANSPEC"},
105 {TRACE_TAG_WAKE_LOCK_EVENT, WIFI_TAG_WAKE_LOCK_EVENT, "WAKELOCK EVENT"},
106 {TRACE_TAG_ADDR1, WIFI_TAG_ADDR1, "ADDR_1"},
107 {TRACE_TAG_ADDR2, WIFI_TAG_ADDR2, "ADDR_2"},
108 {TRACE_TAG_ADDR3, WIFI_TAG_ADDR3, "ADDR_3"},
109 {TRACE_TAG_ADDR4, WIFI_TAG_ADDR4, "ADDR_4"},
110 {TRACE_TAG_TSF, WIFI_TAG_TSF, "TSF"},
111 {TRACE_TAG_IE, WIFI_TAG_IE, "802.11 IE"},
112 {TRACE_TAG_INTERFACE, WIFI_TAG_INTERFACE, "INTERFACE"},
113 {TRACE_TAG_REASON_CODE, WIFI_TAG_REASON_CODE, "REASON CODE"},
114 {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"},
115 };
116
117 /* define log level per ring type */
118 struct log_level_table fw_verbose_level_map[] = {
119 {1, EVENT_LOG_TAG_PCI_ERROR, "PCI_ERROR"},
120 {1, EVENT_LOG_TAG_PCI_WARN, "PCI_WARN"},
121 {2, EVENT_LOG_TAG_PCI_INFO, "PCI_INFO"},
122 {3, EVENT_LOG_TAG_PCI_DBG, "PCI_DEBUG"},
123 {3, EVENT_LOG_TAG_BEACON_LOG, "BEACON_LOG"},
124 {2, EVENT_LOG_TAG_WL_ASSOC_LOG, "ASSOC_LOG"},
125 {2, EVENT_LOG_TAG_WL_ROAM_LOG, "ROAM_LOG"},
126 {1, EVENT_LOG_TAG_TRACE_WL_INFO, "WL INFO"},
127 {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, "BTCOEX INFO"},
128 {1, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"},
129 {1, EVENT_LOG_TAG_SCAN_ERROR, "SCAN_ERROR"},
130 {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, "SCAN_TRACE_LOW"},
131 {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, "SCAN_TRACE_HIGH"}};
132
133 /* reference tab table */
134 uint ref_tag_tbl[EVENT_LOG_TAG_MAX + 1] = {0};
135
136 typedef struct dhddbg_loglist_item {
137 dll_t list;
138 prcd_event_log_hdr_t prcd_log_hdr;
139 } loglist_item_t;
140
141 typedef struct dhbdbg_pending_item {
142 dll_t list;
143 dhd_dbg_ring_status_t ring_status;
144 dhd_dbg_ring_entry_t *ring_entry;
145 } pending_item_t;
146
147 /* trace log entry header user space processing */
148 struct tracelog_header {
149 int magic_num;
150 int buf_size;
151 int seq_num;
152 };
153 #define TRACE_LOG_MAGIC_NUMBER 0xEAE47C06
154
155 void print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr);
dhd_dbg_push_to_ring(dhd_pub_t * dhdp,int ring_id,dhd_dbg_ring_entry_t * hdr,void * data)156 int dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id,
157 dhd_dbg_ring_entry_t *hdr, void *data)
158 {
159 dhd_dbg_ring_t *ring;
160 int ret = 0;
161 uint32 pending_len = 0;
162
163 if (!dhdp || !dhdp->dbg) {
164 return BCME_BADADDR;
165 }
166
167 if (!VALID_RING(ring_id)) {
168 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
169 return BCME_RANGE;
170 }
171
172 ring = &dhdp->dbg->dbg_rings[ring_id];
173
174 ret = dhd_dbg_ring_push(ring, hdr, data);
175 if (ret != BCME_OK) {
176 return ret;
177 }
178
179 pending_len = dhd_dbg_ring_get_pending_len(ring);
180 dhd_dbg_ring_sched_pull(ring, pending_len, dhdp->dbg->pullreq,
181 dhdp->dbg->private, ring->id);
182
183 return ret;
184 }
185
dhd_dbg_get_ring_from_ring_id(dhd_pub_t * dhdp,int ring_id)186 dhd_dbg_ring_t *dhd_dbg_get_ring_from_ring_id(dhd_pub_t *dhdp, int ring_id)
187 {
188 if (!dhdp || !dhdp->dbg) {
189 return NULL;
190 }
191
192 if (!VALID_RING(ring_id)) {
193 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
194 return NULL;
195 }
196
197 return &dhdp->dbg->dbg_rings[ring_id];
198 }
199
dhd_dbg_pull_single_from_ring(dhd_pub_t * dhdp,int ring_id,void * data,uint32 buf_len,bool strip_header)200 int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data,
201 uint32 buf_len, bool strip_header)
202 {
203 dhd_dbg_ring_t *ring;
204
205 if (!dhdp || !dhdp->dbg) {
206 return 0;
207 }
208
209 if (!VALID_RING(ring_id)) {
210 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
211 return BCME_RANGE;
212 }
213
214 ring = &dhdp->dbg->dbg_rings[ring_id];
215
216 return dhd_dbg_ring_pull_single(ring, data, buf_len, strip_header);
217 }
218
dhd_dbg_pull_from_ring(dhd_pub_t * dhdp,int ring_id,void * data,uint32 buf_len)219 int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data,
220 uint32 buf_len)
221 {
222 dhd_dbg_ring_t *ring;
223
224 if (!dhdp || !dhdp->dbg) {
225 return 0;
226 }
227 if (!VALID_RING(ring_id)) {
228 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
229 return BCME_RANGE;
230 }
231 ring = &dhdp->dbg->dbg_rings[ring_id];
232 return dhd_dbg_ring_pull(ring, data, buf_len, FALSE);
233 }
234
dhd_dbg_msgtrace_seqchk(uint32 * prev,uint32 cur)235 static int dhd_dbg_msgtrace_seqchk(uint32 *prev, uint32 cur)
236 {
237 /* normal case including wrap around */
238 if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) {
239 goto done;
240 } else if (cur == *prev) {
241 DHD_EVENT(("%s duplicate trace\n", __FUNCTION__));
242 return -1;
243 } else if (cur > *prev) {
244 DHD_EVENT(("%s lost %d packets\n", __FUNCTION__, cur - *prev));
245 } else {
246 DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n", __FUNCTION__,
247 *prev, cur));
248 }
249 done:
250 *prev = cur;
251 return 0;
252 }
253
254 #ifndef MACOSX_DHD
dhd_dbg_msgtrace_msg_parser(void * event_data)255 static void dhd_dbg_msgtrace_msg_parser(void *event_data)
256 {
257 msgtrace_hdr_t *hdr;
258 char *data, *s;
259 static uint32 seqnum_prev = 0;
260
261 if (!event_data) {
262 DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
263 return;
264 }
265
266 hdr = (msgtrace_hdr_t *)event_data;
267 data = (char *)event_data + MSGTRACE_HDRLEN;
268
269 /* There are 2 bytes available at the end of data */
270 data[ntoh16(hdr->len)] = '\0';
271
272 if (ntoh32(hdr->discarded_bytes) || ntoh32(hdr->discarded_printf)) {
273 DHD_DBGIF(("WLC_E_TRACE: [Discarded traces in dongle -->"
274 "discarded_bytes %d discarded_printf %d]\n",
275 ntoh32(hdr->discarded_bytes),
276 ntoh32(hdr->discarded_printf)));
277 }
278
279 if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum))) {
280 return;
281 }
282
283 /* Display the trace buffer. Advance from
284 * \n to \n to avoid display big
285 * printf (issue with Linux printk )
286 */
287 while (*data != '\0' && (s = strstr(data, "\n")) != NULL) {
288 *s = '\0';
289 DHD_FWLOG(("[FWLOG] %s\n", data));
290 data = s + 1;
291 }
292 if (*data) {
293 DHD_FWLOG(("[FWLOG] %s", data));
294 }
295 }
296 #endif /* MACOSX_DHD */
297 #ifdef SHOW_LOGTRACE
298 #define DATA_UNIT_FOR_LOG_CNT 4
299
300 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
301 #pragma GCC diagnostic pop
302 #endif // endif
303
replace_percent_p_to_x(char * fmt)304 int replace_percent_p_to_x(char *fmt)
305 {
306 int p_to_x_done = FALSE;
307
308 while (*fmt != '\0') {
309 /* Skip characters will we see a % */
310 if (*fmt++ != '%') {
311 continue;
312 }
313
314 /*
315 * Skip any flags, field width and precision:
316 * Flags: Followed by %
317 * #, 0, -, ' ', +
318 */
319 if (*fmt == '#') {
320 fmt++;
321 }
322
323 if (*fmt == '0' || *fmt == '-' || *fmt == '+') {
324 fmt++;
325 }
326
327 /*
328 * Field width:
329 * An optional decimal digit string (with non-zero first digit)
330 * specifying a minimum field width
331 */
332 while (*fmt && bcm_isdigit(*fmt)) {
333 fmt++;
334 }
335
336 /*
337 * Precision:
338 * An optional precision, in the form of a period ('.') followed by an
339 * optional decimal digit string.
340 */
341 if (*fmt == '.') {
342 fmt++;
343 while (*fmt && bcm_isdigit(*fmt)) {
344 fmt++;
345 }
346 }
347
348 /* If %p is seen, change it to %x */
349 if (*fmt == 'p') {
350 *fmt = 'x';
351 p_to_x_done = TRUE;
352 }
353 if (*fmt) {
354 fmt++;
355 }
356 }
357
358 return p_to_x_done;
359 }
360
361 /* To identify format of types %Ns where N >= 0 is a number */
check_valid_string_format(char * curr_ptr)362 bool check_valid_string_format(char *curr_ptr)
363 {
364 char *next_ptr;
365 if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) {
366 /* Default %s format */
367 if (curr_ptr == next_ptr) {
368 return TRUE;
369 }
370
371 /* Verify each charater between '%' and 's' is a valid number */
372 while (curr_ptr < next_ptr) {
373 if (bcm_isdigit(*curr_ptr) == FALSE) {
374 return FALSE;
375 }
376 curr_ptr++;
377 }
378
379 return TRUE;
380 } else {
381 return FALSE;
382 }
383 }
384
385 /* To identify format of non string format types */
check_valid_non_string_format(char * curr_ptr)386 bool check_valid_non_string_format(char *curr_ptr)
387 {
388 char *next_ptr;
389 char *next_fmt_stptr;
390 char valid_fmt_types[17] = {'d', 'i', 'x', 'X', 'c', 'p', 'u', 'f', 'F',
391 'e', 'E', 'g', 'G', 'o', 'a', 'A', 'n'};
392 int i;
393 bool valid = FALSE;
394
395 /* Check for next % in the fmt str */
396 next_fmt_stptr = bcmstrstr(curr_ptr, "%");
397
398 for (next_ptr = curr_ptr; *next_ptr != '\0'; next_ptr++) {
399 for (i = 0;
400 i < (int)((sizeof(valid_fmt_types)) / sizeof(valid_fmt_types[0]));
401 i++) {
402 if (*next_ptr == valid_fmt_types[i]) {
403 /* Check whether format type found corresponds to current %
404 * and not the next one, if exists.
405 */
406 if ((next_fmt_stptr == NULL) ||
407 (next_fmt_stptr && (next_ptr < next_fmt_stptr))) {
408 /* Not validating for length/width fields in
409 * format specifier.
410 */
411 valid = TRUE;
412 }
413 goto done;
414 }
415 }
416 }
417
418 done:
419 return valid;
420 }
421
422 #define MAX_NO_OF_ARG 16
423 #define FMTSTR_SIZE 200
424 #define ROMSTR_SIZE 268
425 #define SIZE_LOC_STR 50
426 #define LOG_PRINT_CNT_MAX 16u
427 #define EL_PARSE_VER "V02"
428 #define EL_MSEC_PER_SEC 1000
429 #ifdef DHD_LOG_PRINT_RATE_LIMIT
430 #define MAX_LOG_PRINT_COUNT 100u
431 #define LOG_PRINT_THRESH (1u * USEC_PER_SEC)
432 #endif // endif
433
dhd_dbg_process_event_log_hdr(event_log_hdr_t * log_hdr,prcd_event_log_hdr_t * prcd_log_hdr)434 bool dhd_dbg_process_event_log_hdr(event_log_hdr_t *log_hdr,
435 prcd_event_log_hdr_t *prcd_log_hdr)
436 {
437 event_log_extended_hdr_t *ext_log_hdr;
438 uint16 event_log_fmt_num;
439 uint8 event_log_hdr_type;
440
441 /* Identify the type of event tag, payload type etc.. */
442 event_log_hdr_type = log_hdr->fmt_num & DHD_EVENT_LOG_HDR_MASK;
443 event_log_fmt_num = (log_hdr->fmt_num >> DHD_EVENT_LOG_FMT_NUM_OFFSET) &
444 DHD_EVENT_LOG_FMT_NUM_MASK;
445
446 switch (event_log_hdr_type) {
447 case DHD_OW_NB_EVENT_LOG_HDR:
448 prcd_log_hdr->ext_event_log_hdr = FALSE;
449 prcd_log_hdr->binary_payload = FALSE;
450 break;
451 case DHD_TW_NB_EVENT_LOG_HDR:
452 prcd_log_hdr->ext_event_log_hdr = TRUE;
453 prcd_log_hdr->binary_payload = FALSE;
454 break;
455 case DHD_BI_EVENT_LOG_HDR:
456 if (event_log_fmt_num == DHD_OW_BI_EVENT_FMT_NUM) {
457 prcd_log_hdr->ext_event_log_hdr = FALSE;
458 prcd_log_hdr->binary_payload = TRUE;
459 } else if (event_log_fmt_num == DHD_TW_BI_EVENT_FMT_NUM) {
460 prcd_log_hdr->ext_event_log_hdr = TRUE;
461 prcd_log_hdr->binary_payload = TRUE;
462 } else {
463 DHD_ERROR(("%s: invalid format number 0x%X\n", __FUNCTION__,
464 event_log_fmt_num));
465 return FALSE;
466 }
467 break;
468 case DHD_INVALID_EVENT_LOG_HDR:
469 default:
470 DHD_ERROR(("%s: invalid event log header type 0x%X\n", __FUNCTION__,
471 event_log_hdr_type));
472 return FALSE;
473 }
474
475 /* Parse extended and legacy event log headers and populate
476 * prcd_event_log_hdr_t */
477 if (prcd_log_hdr->ext_event_log_hdr) {
478 ext_log_hdr = (event_log_extended_hdr_t *)((uint8 *)log_hdr -
479 sizeof(event_log_hdr_t));
480 prcd_log_hdr->tag =
481 ((ext_log_hdr->extended_tag & DHD_TW_VALID_TAG_BITS_MASK)
482 << DHD_TW_EVENT_LOG_TAG_OFFSET) |
483 log_hdr->tag;
484 } else {
485 prcd_log_hdr->tag = log_hdr->tag;
486 }
487 prcd_log_hdr->count = log_hdr->count;
488 prcd_log_hdr->fmt_num_raw = log_hdr->fmt_num;
489 prcd_log_hdr->fmt_num = event_log_fmt_num;
490
491 /* update arm cycle */
492 /*
493 * For loegacy event tag :-
494 * |payload........|Timestamp| Tag
495 *
496 * For extended event tag:-
497 * |payload........|Timestamp|extended Tag| Tag.
498 *
499 */
500 prcd_log_hdr->armcycle =
501 prcd_log_hdr->ext_event_log_hdr
502 ? *(uint32 *)(log_hdr - EVENT_TAG_TIMESTAMP_EXT_OFFSET)
503 : *(uint32 *)(log_hdr - EVENT_TAG_TIMESTAMP_OFFSET);
504
505 /* update event log data pointer address */
506 prcd_log_hdr->log_ptr =
507 (uint32 *)log_hdr - log_hdr->count - prcd_log_hdr->ext_event_log_hdr;
508
509 /* handle error cases above this */
510 return TRUE;
511 }
512
dhd_dbg_verboselog_handler(dhd_pub_t * dhdp,prcd_event_log_hdr_t * plog_hdr,void * raw_event_ptr,uint32 logset,uint16 block,uint32 * data)513 static void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp,
514 prcd_event_log_hdr_t *plog_hdr,
515 void *raw_event_ptr, uint32 logset,
516 uint16 block, uint32 *data)
517 {
518 event_log_hdr_t *ts_hdr;
519 uint32 *log_ptr = plog_hdr->log_ptr;
520 char fmtstr_loc_buf[ROMSTR_SIZE] = {0};
521 uint32 rom_str_len = 0;
522 uint32 *ts_data;
523
524 if (!raw_event_ptr) {
525 return;
526 }
527
528 if (log_ptr < data) {
529 DHD_ERROR(
530 ("Invalid log pointer, logptr : %p data : %p \n", log_ptr, data));
531 return;
532 }
533
534 BCM_REFERENCE(ts_hdr);
535 BCM_REFERENCE(ts_data);
536
537 if (log_ptr > data) {
538 /* Get time stamp if it's updated */
539 ts_hdr = (event_log_hdr_t *)((char *)log_ptr - sizeof(event_log_hdr_t));
540 if (ts_hdr->tag == EVENT_LOG_TAG_TS) {
541 ts_data = (uint32 *)ts_hdr - ts_hdr->count;
542 if (ts_data >= data) {
543 DHD_MSGTRACE_LOG(("EVENT_LOG_TS[0x%08x]: SYS:%08x CPU:%08x\n",
544 ts_data[ts_hdr->count - 1], ts_data[0],
545 ts_data[1]));
546 }
547 }
548 }
549
550 if (plog_hdr->tag == EVENT_LOG_TAG_ROM_PRINTF) {
551 rom_str_len = (plog_hdr->count - 1) * sizeof(uint32);
552 if (rom_str_len >= (ROMSTR_SIZE - 1)) {
553 rom_str_len = ROMSTR_SIZE - 1;
554 }
555
556 /* copy all ascii data for ROM printf to local string */
557 memcpy(fmtstr_loc_buf, log_ptr, rom_str_len);
558 /* add end of line at last */
559 fmtstr_loc_buf[rom_str_len] = '\0';
560
561 DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s",
562 log_ptr[plog_hdr->count - 1], fmtstr_loc_buf));
563
564 /* Add newline if missing */
565 if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n') {
566 DHD_MSGTRACE_LOG(("\n"));
567 }
568
569 return;
570 }
571
572 if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE ||
573 plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE_TLV) {
574 wl_mschdbg_verboselog_handler(dhdp, raw_event_ptr, plog_hdr, log_ptr);
575 return;
576 }
577
578 /* print the message out in a logprint */
579 dhd_dbg_verboselog_printf(dhdp, plog_hdr, raw_event_ptr, log_ptr, logset,
580 block);
581 }
582
dhd_dbg_verboselog_printf(dhd_pub_t * dhdp,prcd_event_log_hdr_t * plog_hdr,void * raw_event_ptr,uint32 * log_ptr,uint32 logset,uint16 block)583 void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr,
584 void *raw_event_ptr, uint32 *log_ptr,
585 uint32 logset, uint16 block)
586 {
587 dhd_event_log_t *raw_event = (dhd_event_log_t *)raw_event_ptr;
588 uint16 count;
589 int log_level, id;
590 char fmtstr_loc_buf[ROMSTR_SIZE] = {0};
591 char(*str_buf)[SIZE_LOC_STR] = NULL;
592 char *str_tmpptr = NULL;
593 uint32 addr = 0;
594 typedef union {
595 uint32 val;
596 char *addr;
597 } u_arg;
598 u_arg arg[MAX_NO_OF_ARG] = {{0}};
599 char *c_ptr = NULL;
600 struct bcmstrbuf b;
601 #ifdef DHD_LOG_PRINT_RATE_LIMIT
602 static int log_print_count = 0;
603 static uint64 ts0 = 0;
604 uint64 ts1 = 0;
605 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
606
607 BCM_REFERENCE(arg);
608
609 #ifdef DHD_LOG_PRINT_RATE_LIMIT
610 if (!ts0) {
611 ts0 = OSL_SYSUPTIME_US();
612 }
613
614 ts1 = OSL_SYSUPTIME_US();
615 if (((ts1 - ts0) <= LOG_PRINT_THRESH) &&
616 (log_print_count >= MAX_LOG_PRINT_COUNT)) {
617 log_print_threshold = 1;
618 ts0 = 0;
619 log_print_count = 0;
620 DHD_ERROR(("%s: Log print water mark is reached,"
621 " console logs are dumped only to debug_dump file\n",
622 __FUNCTION__));
623 } else if ((ts1 - ts0) > LOG_PRINT_THRESH) {
624 log_print_threshold = 0;
625 ts0 = 0;
626 log_print_count = 0;
627 }
628
629 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
630 /* print the message out in a logprint. Logprint expects raw format number
631 */
632 if (!(raw_event->fmts)) {
633 if (dhdp->dbg) {
634 log_level = dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level;
635 for (id = 0; id < ARRAYSIZE(fw_verbose_level_map); id++) {
636 if ((fw_verbose_level_map[id].tag == plog_hdr->tag) &&
637 (fw_verbose_level_map[id].log_level > log_level)) {
638 return;
639 }
640 }
641 }
642
643 if (plog_hdr->binary_payload) {
644 DHD_ECNTR_LOG(
645 ("%06d.%03d EL:tag=%d len=%d fmt=0x%x",
646 (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
647 (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
648 plog_hdr->tag, plog_hdr->count, plog_hdr->fmt_num_raw));
649
650 for (count = 0; count < (plog_hdr->count - 1); count++) {
651 if (count && (count % LOG_PRINT_CNT_MAX == 0)) {
652 DHD_ECNTR_LOG(("\n\t%08x", log_ptr[count]));
653 } else {
654 DHD_ECNTR_LOG((" %08x", log_ptr[count]));
655 }
656 }
657 DHD_ECNTR_LOG(("\n"));
658 } else {
659 bcm_binit(&b, fmtstr_loc_buf, FMTSTR_SIZE);
660 bcm_bprintf(
661 &b, "%06d.%03d EL:%s:%u:%u %d %d 0x%x",
662 (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
663 (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
664 EL_PARSE_VER, logset, block, plog_hdr->tag, plog_hdr->count,
665 plog_hdr->fmt_num_raw);
666 for (count = 0; count < (plog_hdr->count - 1); count++) {
667 bcm_bprintf(&b, " %x", log_ptr[count]);
668 }
669
670 /* ensure preserve fw logs go to debug_dump only in case of
671 * customer4 */
672 if (logset < dhdp->event_log_max_sets &&
673 ((0x01u << logset) & dhdp->logset_prsrv_mask)) {
674 DHD_PRSRV_MEM(("%s\n", b.origbuf));
675 } else {
676 DHD_FWLOG(("%s\n", b.origbuf));
677 #ifdef DHD_LOG_PRINT_RATE_LIMIT
678 log_print_count++;
679 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
680 }
681 }
682 return;
683 }
684
685 str_buf = MALLOCZ(dhdp->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR));
686 if (!str_buf) {
687 DHD_ERROR(("%s: malloc failed str_buf\n", __FUNCTION__));
688 return;
689 }
690
691 if ((plog_hdr->fmt_num) < raw_event->num_fmts) {
692 if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) {
693 snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s",
694 raw_event->fmts[plog_hdr->fmt_num]);
695 plog_hdr->count++;
696 } else {
697 snprintf(fmtstr_loc_buf, FMTSTR_SIZE,
698 "CONSOLE_E:%u:%u %06d.%03d %s", logset, block,
699 (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
700 (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
701 raw_event->fmts[plog_hdr->fmt_num]);
702 }
703 c_ptr = fmtstr_loc_buf;
704 } else {
705 /* for ecounters, don't print the error as it will flood */
706 if ((plog_hdr->fmt_num != DHD_OW_BI_EVENT_FMT_NUM) &&
707 (plog_hdr->fmt_num != DHD_TW_BI_EVENT_FMT_NUM)) {
708 DHD_ERROR(("%s: fmt number: 0x%x out of range\n", __FUNCTION__,
709 plog_hdr->fmt_num));
710 } else {
711 DHD_INFO(("%s: fmt number: 0x%x out of range\n", __FUNCTION__,
712 plog_hdr->fmt_num));
713 }
714
715 goto exit;
716 }
717
718 if (plog_hdr->count > MAX_NO_OF_ARG) {
719 DHD_ERROR(("%s: plog_hdr->count(%d) out of range\n", __FUNCTION__,
720 plog_hdr->count));
721 goto exit;
722 }
723
724 /* print the format string which will be needed for debugging incorrect
725 * formats */
726 DHD_INFO(("%s: fmtstr_loc_buf = %s\n", __FUNCTION__, fmtstr_loc_buf));
727
728 /* Replace all %p to %x to handle 32 bit %p */
729 replace_percent_p_to_x(fmtstr_loc_buf);
730
731 for (count = 0; count < (plog_hdr->count - 1); count++) {
732 if (c_ptr != NULL) {
733 if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL) {
734 c_ptr++;
735 }
736 }
737
738 if (c_ptr != NULL) {
739 if (check_valid_string_format(c_ptr)) {
740 if ((raw_event->raw_sstr) &&
741 ((log_ptr[count] > raw_event->rodata_start) &&
742 (log_ptr[count] < raw_event->rodata_end))) {
743 /* ram static string */
744 addr = log_ptr[count] - raw_event->rodata_start;
745 str_tmpptr = raw_event->raw_sstr + addr;
746 memcpy(str_buf[count], str_tmpptr, SIZE_LOC_STR);
747 str_buf[count][SIZE_LOC_STR - 1] = '\0';
748 arg[count].addr = str_buf[count];
749 } else if ((raw_event->rom_raw_sstr) &&
750 ((log_ptr[count] > raw_event->rom_rodata_start) &&
751 (log_ptr[count] < raw_event->rom_rodata_end))) {
752 /* rom static string */
753 addr = log_ptr[count] - raw_event->rom_rodata_start;
754 str_tmpptr = raw_event->rom_raw_sstr + addr;
755 memcpy(str_buf[count], str_tmpptr, SIZE_LOC_STR);
756 str_buf[count][SIZE_LOC_STR - 1] = '\0';
757 arg[count].addr = str_buf[count];
758 } else {
759 /*
760 * Dynamic string OR
761 * No data for static string.
762 * So store all string's address as string.
763 */
764 snprintf(str_buf[count], SIZE_LOC_STR, "(s)0x%x",
765 log_ptr[count]);
766 arg[count].addr = str_buf[count];
767 }
768 } else if (check_valid_non_string_format(c_ptr)) {
769 /* Other than string format */
770 arg[count].val = log_ptr[count];
771 } else {
772 *(c_ptr - 1) = '\0';
773 break;
774 }
775 }
776 }
777
778 /* ensure preserve fw logs go to debug_dump only in case of customer4 */
779 if (logset < dhdp->event_log_max_sets &&
780 ((0x01u << logset) & dhdp->logset_prsrv_mask)) {
781 if (dhd_msg_level & DHD_EVENT_VAL) {
782 if (dhd_msg_level & DHD_PRSRV_MEM_VAL) {
783 printk(fmtstr_loc_buf, arg[0], arg[1], arg[0x2], arg[0x3], arg[0x4],
784 arg[0x5], arg[0x6], arg[0x7], arg[0x8], arg[0x9], arg[0xA], arg[0xB],
785 arg[0xC], arg[0xD], arg[0xE], arg[0xF]);
786 }
787 }
788 } else {
789 if (dhd_msg_level & DHD_FWLOG_VAL) {
790 printk(fmtstr_loc_buf, arg[0], arg[1], arg[0x2], arg[0x3], arg[0x4],
791 arg[0x5], arg[0x6], arg[0x7], arg[0x8], arg[0x9], arg[0xA], arg[0xB],
792 arg[0xC], arg[0xD], arg[0xE], arg[0xF]);
793 }
794 #ifdef DHD_LOG_PRINT_RATE_LIMIT
795 log_print_count++;
796 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
797 }
798
799 exit:
800 MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
801 }
802
dhd_dbg_msgtrace_log_parser(dhd_pub_t * dhdp,void * event_data,void * raw_event_ptr,uint datalen,bool msgtrace_hdr_present,uint32 msgtrace_seqnum)803 void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
804 void *raw_event_ptr, uint datalen,
805 bool msgtrace_hdr_present,
806 uint32 msgtrace_seqnum)
807 {
808 msgtrace_hdr_t *hdr;
809 char *data, *tmpdata;
810 const uint32 log_hdr_len = sizeof(event_log_hdr_t);
811 uint32 log_pyld_len;
812 static uint32 seqnum_prev = 0;
813 event_log_hdr_t *log_hdr;
814 bool msg_processed = FALSE;
815 prcd_event_log_hdr_t prcd_log_hdr;
816 prcd_event_log_hdr_t *plog_hdr;
817 dll_t list_head, *cur;
818 loglist_item_t *log_item;
819 dhd_dbg_ring_entry_t msg_hdr;
820 char *logbuf;
821 struct tracelog_header *logentry_header;
822 uint ring_data_len = 0;
823 bool ecntr_pushed = FALSE;
824 bool rtt_pushed = FALSE;
825 bool dll_inited = FALSE;
826 uint32 logset = 0;
827 uint16 block = 0;
828 bool event_log_max_sets_queried;
829 uint32 event_log_max_sets;
830 uint min_expected_len = 0;
831 uint16 len_chk = 0;
832
833 BCM_REFERENCE(ecntr_pushed);
834 BCM_REFERENCE(rtt_pushed);
835 BCM_REFERENCE(len_chk);
836
837 /* store event_logset_queried and event_log_max_sets in local variables
838 * to avoid race conditions as they were set from different
839 * contexts(preinit)
840 */
841 event_log_max_sets_queried = dhdp->event_log_max_sets_queried;
842 /* Make sure queried is read first with wmb and then max_sets,
843 * as it is done in reverse order during preinit ioctls.
844 */
845 OSL_SMP_WMB();
846 event_log_max_sets = dhdp->event_log_max_sets;
847
848 if (msgtrace_hdr_present) {
849 min_expected_len = (MSGTRACE_HDRLEN + EVENT_LOG_BLOCK_LEN);
850 } else {
851 min_expected_len = EVENT_LOG_BLOCK_LEN;
852 }
853
854 /* log trace event consists of:
855 * msgtrace header
856 * event log block header
857 * event log payload
858 */
859 if (!event_data || (datalen <= min_expected_len)) {
860 DHD_ERROR(("%s: Not processing due to invalid event_data : %p or "
861 "length : %d\n",
862 __FUNCTION__, event_data, datalen));
863 if (event_data && msgtrace_hdr_present) {
864 prhex("event_data dump", event_data, datalen);
865 tmpdata = (char *)event_data + MSGTRACE_HDRLEN;
866 if (tmpdata) {
867 DHD_ERROR(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
868 ltoh16(*((uint16 *)(tmpdata + 0x2))),
869 ltoh32(*((uint32 *)(tmpdata + 0x4))),
870 ltoh16(*((uint16 *)(tmpdata)))));
871 }
872 } else if (!event_data) {
873 DHD_ERROR(
874 ("%s: event_data is NULL, cannot dump prhex\n", __FUNCTION__));
875 }
876 return;
877 }
878
879 if (msgtrace_hdr_present) {
880 hdr = (msgtrace_hdr_t *)event_data;
881 data = (char *)event_data + MSGTRACE_HDRLEN;
882 datalen -= MSGTRACE_HDRLEN;
883 msgtrace_seqnum = ntoh32(hdr->seqnum);
884 } else {
885 data = (char *)event_data;
886 }
887
888 if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, msgtrace_seqnum)) {
889 return;
890 }
891
892 /* Save the whole message to event log ring */
893 memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t));
894 logbuf = VMALLOC(dhdp->osh, sizeof(*logentry_header) + datalen);
895 if (logbuf == NULL) {
896 return;
897 }
898 logentry_header = (struct tracelog_header *)logbuf;
899 logentry_header->magic_num = TRACE_LOG_MAGIC_NUMBER;
900 logentry_header->buf_size = datalen;
901 logentry_header->seq_num = msgtrace_seqnum;
902 msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
903
904 ring_data_len = datalen + sizeof(*logentry_header);
905
906 if ((sizeof(*logentry_header) + datalen) > PAYLOAD_MAX_LEN) {
907 DHD_ERROR(("%s:Payload len=%u exceeds max len\n", __FUNCTION__,
908 ((uint)sizeof(*logentry_header) + datalen)));
909 goto exit;
910 }
911
912 msg_hdr.len = sizeof(*logentry_header) + datalen;
913 memcpy(logbuf + sizeof(*logentry_header), data, datalen);
914 DHD_DBGIF(("%s: datalen %d %d\n", __FUNCTION__, msg_hdr.len, datalen));
915 dhd_dbg_push_to_ring(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf);
916
917 /* Print sequence number, originating set and length of received
918 * event log buffer. Refer to event log buffer structure in
919 * event_log.h
920 */
921 DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
922 ltoh16(*((uint16 *)(data + 0x2))),
923 ltoh32(*((uint32 *)(data + 0x4))),
924 ltoh16(*((uint16 *)(data)))));
925
926 logset = ltoh32(*((uint32 *)(data + 0x4)));
927 if (logset >= event_log_max_sets) {
928 DHD_ERROR(("%s logset: %d max: %d out of range queried: %d\n",
929 __FUNCTION__, logset, event_log_max_sets,
930 event_log_max_sets_queried));
931 #ifdef DHD_FW_COREDUMP
932 if (event_log_max_sets_queried) {
933 DHD_ERROR(("%s: collect socram for DUMP_TYPE_LOGSET_BEYOND_RANGE\n",
934 __FUNCTION__));
935 dhdp->memdump_type = DUMP_TYPE_LOGSET_BEYOND_RANGE;
936 dhd_bus_mem_dump(dhdp);
937 }
938 #endif /* DHD_FW_COREDUMP */
939 }
940
941 block = ltoh16(*((uint16 *)(data + 0x2)));
942
943 data += EVENT_LOG_BLOCK_HDRLEN;
944 datalen -= EVENT_LOG_BLOCK_HDRLEN;
945
946 /* start parsing from the tail of packet
947 * Sameple format of a meessage
948 * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639
949 * 001d3c54 00000064 00000064 035d6d89 0c580439
950 * 0x0c580439 -- 39 is tag, 04 is count, 580c is format number
951 * all these uint32 values comes in reverse order as group as EL data
952 * while decoding we can only parse from last to first
953 * |<- datalen ->|
954 * |----(payload and maybe more logs)----|event_log_hdr_t|
955 * data log_hdr
956 */
957 dll_init(&list_head);
958 dll_inited = TRUE;
959
960 while (datalen > log_hdr_len) {
961 log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len);
962 memset(&prcd_log_hdr, 0, sizeof(prcd_log_hdr));
963 if (!dhd_dbg_process_event_log_hdr(log_hdr, &prcd_log_hdr)) {
964 DHD_ERROR(
965 ("%s: Error while parsing event log header\n", __FUNCTION__));
966 }
967
968 /* skip zero padding at end of frame */
969 if (prcd_log_hdr.tag == EVENT_LOG_TAG_NULL) {
970 datalen -= log_hdr_len;
971 continue;
972 }
973 /* Check argument count (for non-ecounter events only),
974 * any event log should contain at least
975 * one argument (4 bytes) for arm cycle count and up to 16
976 * arguments except EVENT_LOG_TAG_STATS which could use the
977 * whole payload of 256 words
978 */
979 if (prcd_log_hdr.count == 0) {
980 break;
981 }
982 /* Both tag_stats and proxd are binary payloads so skip
983 * argument count check for these.
984 */
985 if ((prcd_log_hdr.tag != EVENT_LOG_TAG_STATS) &&
986 (prcd_log_hdr.tag != EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
987 (prcd_log_hdr.tag != EVENT_LOG_TAG_ROAM_ENHANCED_LOG) &&
988 (prcd_log_hdr.count > MAX_NO_OF_ARG)) {
989 break;
990 }
991
992 log_pyld_len = (prcd_log_hdr.count + prcd_log_hdr.ext_event_log_hdr) *
993 DATA_UNIT_FOR_LOG_CNT;
994 /* log data should not cross the event data boundary */
995 if ((uint32)((char *)log_hdr - data) < log_pyld_len) {
996 break;
997 }
998 /* skip 4 bytes time stamp packet */
999 if (prcd_log_hdr.tag == EVENT_LOG_TAG_TS) {
1000 datalen -= (log_pyld_len + log_hdr_len);
1001 continue;
1002 }
1003 if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) {
1004 DHD_ERROR(("%s allocating log list item failed\n", __FUNCTION__));
1005 break;
1006 }
1007
1008 log_item->prcd_log_hdr.tag = prcd_log_hdr.tag;
1009 log_item->prcd_log_hdr.count = prcd_log_hdr.count;
1010 log_item->prcd_log_hdr.fmt_num = prcd_log_hdr.fmt_num;
1011 log_item->prcd_log_hdr.fmt_num_raw = prcd_log_hdr.fmt_num_raw;
1012 log_item->prcd_log_hdr.armcycle = prcd_log_hdr.armcycle;
1013 log_item->prcd_log_hdr.log_ptr = prcd_log_hdr.log_ptr;
1014 log_item->prcd_log_hdr.payload_len = prcd_log_hdr.payload_len;
1015 log_item->prcd_log_hdr.ext_event_log_hdr =
1016 prcd_log_hdr.ext_event_log_hdr;
1017 log_item->prcd_log_hdr.binary_payload = prcd_log_hdr.binary_payload;
1018
1019 dll_insert(&log_item->list, &list_head);
1020 datalen -= (log_pyld_len + log_hdr_len);
1021 }
1022
1023 while (!dll_empty(&list_head)) {
1024 msg_processed = FALSE;
1025 cur = dll_head_p(&list_head);
1026 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1027 #pragma GCC diagnostic push
1028 #pragma GCC diagnostic ignored "-Wcast-qual"
1029 #endif // endif
1030 log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
1031 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1032 #pragma GCC diagnostic pop
1033 #endif // endif
1034
1035 plog_hdr = &log_item->prcd_log_hdr;
1036
1037 #if defined(EWP_ECNTRS_LOGGING) && defined(DHD_LOG_DUMP)
1038 /* Ecounter tag can be time_data or log_stats+binary paloaod */
1039 if ((plog_hdr->tag == EVENT_LOG_TAG_ECOUNTERS_TIME_DATA) ||
1040 ((plog_hdr->tag == EVENT_LOG_TAG_STATS) &&
1041 (plog_hdr->binary_payload))) {
1042 if (!ecntr_pushed && dhd_log_dump_ecntr_enabled()) {
1043 /*
1044 * check msg hdr len before pushing.
1045 * FW msg_hdr.len includes length of event log hdr,
1046 * logentry header and payload.
1047 */
1048 len_chk = (sizeof(*logentry_header) + sizeof(*log_hdr) +
1049 PAYLOAD_ECNTR_MAX_LEN);
1050 /* account extended event log header(extended_event_log_hdr) */
1051 if (plog_hdr->ext_event_log_hdr) {
1052 len_chk += sizeof(*log_hdr);
1053 }
1054 if (msg_hdr.len > len_chk) {
1055 DHD_ERROR(("%s: EVENT_LOG_VALIDATION_FAILS: "
1056 "msg_hdr.len=%u, max allowed for ecntrs=%u\n",
1057 __FUNCTION__, msg_hdr.len, len_chk));
1058 goto exit;
1059 }
1060 dhd_dbg_ring_push(dhdp->ecntr_dbg_ring, &msg_hdr, logbuf);
1061 ecntr_pushed = TRUE;
1062 }
1063 }
1064 #endif /* EWP_ECNTRS_LOGGING && DHD_LOG_DUMP */
1065
1066 if (plog_hdr->tag == EVENT_LOG_TAG_ROAM_ENHANCED_LOG) {
1067 print_roam_enhanced_log(plog_hdr);
1068 msg_processed = TRUE;
1069 }
1070 #if defined(EWP_RTT_LOGGING) && defined(DHD_LOG_DUMP)
1071 if ((plog_hdr->tag == EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
1072 plog_hdr->binary_payload) {
1073 if (!rtt_pushed && dhd_log_dump_rtt_enabled()) {
1074 /*
1075 * check msg hdr len before pushing.
1076 * FW msg_hdr.len includes length of event log hdr,
1077 * logentry header and payload.
1078 */
1079 len_chk = (sizeof(*logentry_header) + sizeof(*log_hdr) +
1080 PAYLOAD_RTT_MAX_LEN);
1081 /* account extended event log header(extended_event_log_hdr) */
1082 if (plog_hdr->ext_event_log_hdr) {
1083 len_chk += sizeof(*log_hdr);
1084 }
1085 if (msg_hdr.len > len_chk) {
1086 DHD_ERROR(("%s: EVENT_LOG_VALIDATION_FAILS: "
1087 "msg_hdr.len=%u, max allowed for ecntrs=%u\n",
1088 __FUNCTION__, msg_hdr.len, len_chk));
1089 goto exit;
1090 }
1091 dhd_dbg_ring_push(dhdp->rtt_dbg_ring, &msg_hdr, logbuf);
1092 rtt_pushed = TRUE;
1093 }
1094 }
1095 #endif /* EWP_RTT_LOGGING && DHD_LOG_DUMP */
1096
1097 if (!msg_processed) {
1098 dhd_dbg_verboselog_handler(dhdp, plog_hdr, raw_event_ptr, logset,
1099 block, (uint32 *)data);
1100 }
1101 dll_delete(cur);
1102 MFREE(dhdp->osh, log_item, sizeof(*log_item));
1103 }
1104 BCM_REFERENCE(log_hdr);
1105
1106 exit:
1107 while (dll_inited && (!dll_empty(&list_head))) {
1108 cur = dll_head_p(&list_head);
1109 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1110 #pragma GCC diagnostic push
1111 #pragma GCC diagnostic ignored "-Wcast-qual"
1112 #endif // endif
1113 log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
1114 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1115 #pragma GCC diagnostic pop
1116 #endif // endif
1117 dll_delete(cur);
1118 MFREE(dhdp->osh, log_item, sizeof(*log_item));
1119 }
1120 VMFREE(dhdp->osh, logbuf, ring_data_len);
1121 }
1122 #else /* !SHOW_LOGTRACE */
dhd_dbg_verboselog_handler(dhd_pub_t * dhdp,prcd_event_log_hdr_t * plog_hdr,void * raw_event_ptr,uint32 logset,uint16 block,uint32 * data)1123 static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp,
1124 prcd_event_log_hdr_t *plog_hdr,
1125 void *raw_event_ptr,
1126 uint32 logset, uint16 block,
1127 uint32 *data)
1128 {};
dhd_dbg_msgtrace_log_parser(dhd_pub_t * dhdp,void * event_data,void * raw_event_ptr,uint datalen,bool msgtrace_hdr_present,uint32 msgtrace_seqnum)1129 INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
1130 void *raw_event_ptr, uint datalen,
1131 bool msgtrace_hdr_present,
1132 uint32 msgtrace_seqnum)
1133 {};
1134 #endif /* SHOW_LOGTRACE */
1135 #ifndef MACOSX_DHD
dhd_dbg_trace_evnt_handler(dhd_pub_t * dhdp,void * event_data,void * raw_event_ptr,uint datalen)1136 void dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
1137 void *raw_event_ptr, uint datalen)
1138 {
1139 msgtrace_hdr_t *hdr;
1140
1141 hdr = (msgtrace_hdr_t *)event_data;
1142
1143 if (hdr->version != MSGTRACE_VERSION) {
1144 DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n",
1145 __FUNCTION__, MSGTRACE_VERSION, hdr->version));
1146 return;
1147 }
1148
1149 if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG) {
1150 dhd_dbg_msgtrace_msg_parser(event_data);
1151 } else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG) {
1152 dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen,
1153 TRUE, 0);
1154 }
1155 }
1156
1157 #endif /* MACOSX_DHD */
1158
1159 /*
1160 * dhd_dbg_set_event_log_tag : modify the state of an event log tag
1161 */
dhd_dbg_set_event_log_tag(dhd_pub_t * dhdp,uint16 tag,uint8 set)1162 void dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set)
1163 {
1164 wl_el_tag_params_t pars;
1165 char *cmd = "event_log_tag_control";
1166 char iovbuf[WLC_IOCTL_SMLEN] = {0};
1167 int ret;
1168
1169 memset(&pars, 0, sizeof(pars));
1170 pars.tag = tag;
1171 pars.set = set;
1172 pars.flags = EVENT_LOG_TAG_FLAG_LOG;
1173
1174 if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf,
1175 sizeof(iovbuf))) {
1176 DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__));
1177 return;
1178 }
1179
1180 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1181 if (ret) {
1182 DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret));
1183 }
1184 }
1185
dhd_dbg_set_configuration(dhd_pub_t * dhdp,int ring_id,int log_level,int flags,uint32 threshold)1186 int dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level,
1187 int flags, uint32 threshold)
1188 {
1189 dhd_dbg_ring_t *ring;
1190 uint8 set = 1;
1191 int i, array_len = 0;
1192 struct log_level_table *log_level_tbl = NULL;
1193
1194 if (!dhdp || !dhdp->dbg) {
1195 return BCME_BADADDR;
1196 }
1197
1198 if (!VALID_RING(ring_id)) {
1199 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
1200 return BCME_RANGE;
1201 }
1202
1203 ring = &dhdp->dbg->dbg_rings[ring_id];
1204 dhd_dbg_ring_config(ring, log_level, threshold);
1205
1206 if (log_level > 0) {
1207 set = TRUE;
1208 }
1209
1210 if (ring->id == FW_VERBOSE_RING_ID) {
1211 log_level_tbl = fw_verbose_level_map;
1212 array_len = ARRAYSIZE(fw_verbose_level_map);
1213 }
1214
1215 for (i = 0; i < array_len; i++) {
1216 if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) {
1217 /* clear the reference per ring */
1218 ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id);
1219 } else {
1220 /* set the reference per ring */
1221 ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id);
1222 }
1223 set = (ref_tag_tbl[log_level_tbl[i].tag]) ? 1 : 0;
1224 DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__,
1225 log_level_tbl[i].desc, (set) ? "SET" : "CLEAR", ring->name));
1226 dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set);
1227 }
1228 return BCME_OK;
1229 }
1230
__dhd_dbg_get_ring_status(dhd_dbg_ring_t * ring,dhd_dbg_ring_status_t * get_ring_status)1231 int __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring,
1232 dhd_dbg_ring_status_t *get_ring_status)
1233 {
1234 dhd_dbg_ring_status_t ring_status;
1235 int ret = BCME_OK;
1236
1237 if (ring == NULL) {
1238 return BCME_BADADDR;
1239 }
1240
1241 bzero(&ring_status, sizeof(dhd_dbg_ring_status_t));
1242 RING_STAT_TO_STATUS(ring, ring_status);
1243 *get_ring_status = ring_status;
1244
1245 return ret;
1246 }
1247
1248 /*
1249 * dhd_dbg_get_ring_status : get the ring status from the coresponding ring
1250 * buffer Return: An error code or 0 on success.
1251 */
1252
dhd_dbg_get_ring_status(dhd_pub_t * dhdp,int ring_id,dhd_dbg_ring_status_t * dbg_ring_status)1253 int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id,
1254 dhd_dbg_ring_status_t *dbg_ring_status)
1255 {
1256 int ret = BCME_OK;
1257 int id = 0;
1258 dhd_dbg_t *dbg;
1259 dhd_dbg_ring_t *dbg_ring;
1260 if (!dhdp || !dhdp->dbg) {
1261 return BCME_BADADDR;
1262 }
1263 dbg = dhdp->dbg;
1264
1265 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
1266 dbg_ring = &dbg->dbg_rings[id];
1267 if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) {
1268 __dhd_dbg_get_ring_status(dbg_ring, dbg_ring_status);
1269 break;
1270 }
1271 }
1272 if (!VALID_RING(id)) {
1273 DHD_ERROR(
1274 ("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id));
1275 ret = BCME_NOTFOUND;
1276 }
1277 return ret;
1278 }
1279
1280 #ifdef SHOW_LOGTRACE
dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t * ring,trace_buf_info_t * trace_buf_info)1281 void dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t *ring,
1282 trace_buf_info_t *trace_buf_info)
1283 {
1284 dhd_dbg_ring_status_t ring_status;
1285 uint32 rlen = 0;
1286
1287 rlen = dhd_dbg_ring_pull_single(ring, trace_buf_info->buf,
1288 TRACE_LOG_BUF_MAX_SIZE, TRUE);
1289
1290 trace_buf_info->size = rlen;
1291 trace_buf_info->availability = NEXT_BUF_NOT_AVAIL;
1292 if (rlen == 0) {
1293 trace_buf_info->availability = BUF_NOT_AVAILABLE;
1294 return;
1295 }
1296
1297 __dhd_dbg_get_ring_status(ring, &ring_status);
1298
1299 if (ring_status.written_bytes != ring_status.read_bytes) {
1300 trace_buf_info->availability = NEXT_BUF_AVAIL;
1301 }
1302 }
1303 #endif /* SHOW_LOGTRACE */
1304
1305 /*
1306 * dhd_dbg_find_ring_id : return ring_id based on ring_name
1307 * Return: An invalid ring id for failure or valid ring id on success.
1308 */
1309
dhd_dbg_find_ring_id(dhd_pub_t * dhdp,char * ring_name)1310 int dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name)
1311 {
1312 int id;
1313 dhd_dbg_t *dbg;
1314 dhd_dbg_ring_t *ring;
1315
1316 if (!dhdp || !dhdp->dbg) {
1317 return BCME_BADADDR;
1318 }
1319
1320 dbg = dhdp->dbg;
1321 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
1322 ring = &dbg->dbg_rings[id];
1323 if (!strncmp((char *)ring->name, ring_name, sizeof(ring->name) - 1)) {
1324 break;
1325 }
1326 }
1327 return id;
1328 }
1329
1330 /*
1331 * dhd_dbg_get_priv : get the private data of dhd dbugability module
1332 * Return : An NULL on failure or valid data address
1333 */
dhd_dbg_get_priv(dhd_pub_t * dhdp)1334 void *dhd_dbg_get_priv(dhd_pub_t *dhdp)
1335 {
1336 if (!dhdp || !dhdp->dbg) {
1337 return NULL;
1338 }
1339 return dhdp->dbg->private;
1340 }
1341
1342 /*
1343 * dhd_dbg_start : start and stop All of Ring buffers
1344 * Return: An error code or 0 on success.
1345 */
dhd_dbg_start(dhd_pub_t * dhdp,bool start)1346 int dhd_dbg_start(dhd_pub_t *dhdp, bool start)
1347 {
1348 int ret = BCME_OK;
1349 int ring_id;
1350 dhd_dbg_t *dbg;
1351 dhd_dbg_ring_t *dbg_ring;
1352 if (!dhdp) {
1353 return BCME_BADARG;
1354 }
1355 dbg = dhdp->dbg;
1356
1357 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
1358 ring_id++) {
1359 dbg_ring = &dbg->dbg_rings[ring_id];
1360 if (!start) {
1361 if (VALID_RING(dbg_ring->id)) {
1362 dhd_dbg_ring_start(dbg_ring);
1363 }
1364 }
1365 }
1366 return ret;
1367 }
1368
1369 /*
1370 * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer
1371 *
1372 * Return: An error code or 0 on success.
1373 */
1374
dhd_dbg_send_urgent_evt(dhd_pub_t * dhdp,const void * data,const uint32 len)1375 int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len)
1376 {
1377 dhd_dbg_t *dbg;
1378 int ret = BCME_OK;
1379 if (!dhdp || !dhdp->dbg) {
1380 return BCME_BADADDR;
1381 }
1382
1383 dbg = dhdp->dbg;
1384 if (dbg->urgent_notifier) {
1385 dbg->urgent_notifier(dhdp, data, len);
1386 }
1387 return ret;
1388 }
1389
1390 #if defined(DBG_PKT_MON)
__dhd_dbg_pkt_hash(uintptr_t pkt,uint32 pktid)1391 uint32 __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid)
1392 {
1393 uint32 __pkt;
1394 uint32 __pktid;
1395
1396 __pkt = ((int)pkt) >= 0 ? (0x2 * pkt) : (-0x2 * pkt - 1);
1397 __pktid = ((int)pktid) >= 0 ? (0x2 * pktid) : (-0x2 * pktid - 1);
1398
1399 return (__pkt >= __pktid ? (__pkt * __pkt + __pkt + __pktid)
1400 : (__pkt + __pktid * __pktid));
1401 }
1402
1403 #define __TIMESPEC_TO_US(ts) \
1404 (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC))
1405
__dhd_dbg_driver_ts_usec(void)1406 uint32 __dhd_dbg_driver_ts_usec(void)
1407 {
1408 struct osl_timespec ts;
1409
1410 osl_get_monotonic_boottime(&ts);
1411 return ((uint32)(__TIMESPEC_TO_US(ts)));
1412 }
1413
__dhd_dbg_map_tx_status_to_pkt_fate(uint16 status)1414 wifi_tx_packet_fate __dhd_dbg_map_tx_status_to_pkt_fate(uint16 status)
1415 {
1416 wifi_tx_packet_fate pkt_fate;
1417
1418 switch (status) {
1419 case WLFC_CTL_PKTFLAG_DISCARD:
1420 pkt_fate = TX_PKT_FATE_ACKED;
1421 break;
1422 case WLFC_CTL_PKTFLAG_D11SUPPRESS:
1423 /* intensional fall through */
1424 case WLFC_CTL_PKTFLAG_WLSUPPRESS:
1425 pkt_fate = TX_PKT_FATE_FW_QUEUED;
1426 break;
1427 case WLFC_CTL_PKTFLAG_TOSSED_BYWLC:
1428 pkt_fate = TX_PKT_FATE_FW_DROP_INVALID;
1429 break;
1430 case WLFC_CTL_PKTFLAG_DISCARD_NOACK:
1431 pkt_fate = TX_PKT_FATE_SENT;
1432 break;
1433 case WLFC_CTL_PKTFLAG_EXPIRED:
1434 pkt_fate = TX_PKT_FATE_FW_DROP_EXPTIME;
1435 break;
1436 default:
1437 pkt_fate = TX_PKT_FATE_FW_DROP_OTHER;
1438 break;
1439 }
1440
1441 return pkt_fate;
1442 }
1443 #endif // endif
1444
1445 #ifdef DBG_PKT_MON
__dhd_dbg_free_tx_pkts(dhd_pub_t * dhdp,dhd_dbg_tx_info_t * tx_pkts,uint16 pkt_count)1446 static int __dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts,
1447 uint16 pkt_count)
1448 {
1449 uint16 count;
1450
1451 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1452 count = 0;
1453 while ((count < pkt_count) && tx_pkts) {
1454 if (tx_pkts->info.pkt) {
1455 PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE);
1456 }
1457 tx_pkts++;
1458 count++;
1459 }
1460
1461 return BCME_OK;
1462 }
1463
__dhd_dbg_free_rx_pkts(dhd_pub_t * dhdp,dhd_dbg_rx_info_t * rx_pkts,uint16 pkt_count)1464 static int __dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts,
1465 uint16 pkt_count)
1466 {
1467 uint16 count;
1468
1469 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1470 count = 0;
1471 while ((count < pkt_count) && rx_pkts) {
1472 if (rx_pkts->info.pkt) {
1473 PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE);
1474 }
1475 rx_pkts++;
1476 count++;
1477 }
1478
1479 return BCME_OK;
1480 }
1481
__dhd_dbg_dump_pkt_info(dhd_pub_t * dhdp,dhd_dbg_pkt_info_t * info)1482 void __dhd_dbg_dump_pkt_info(dhd_pub_t *dhdp, dhd_dbg_pkt_info_t *info)
1483 {
1484 if (DHD_PKT_MON_DUMP_ON()) {
1485 DHD_PKT_MON(("payload type = %d\n", info->payload_type));
1486 DHD_PKT_MON(("driver ts = %u\n", info->driver_ts));
1487 DHD_PKT_MON(("firmware ts = %u\n", info->firmware_ts));
1488 DHD_PKT_MON(("packet hash = %u\n", info->pkt_hash));
1489 DHD_PKT_MON(("packet length = %zu\n", info->pkt_len));
1490 DHD_PKT_MON(("packet address = %p\n", info->pkt));
1491 DHD_PKT_MON(("packet data = \n"));
1492 if (DHD_PKT_MON_ON()) {
1493 prhex(NULL, PKTDATA(dhdp->osh, info->pkt), info->pkt_len);
1494 }
1495 }
1496 }
1497
__dhd_dbg_dump_tx_pkt_info(dhd_pub_t * dhdp,dhd_dbg_tx_info_t * tx_pkt,uint16 count)1498 void __dhd_dbg_dump_tx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkt,
1499 uint16 count)
1500 {
1501 if (DHD_PKT_MON_DUMP_ON()) {
1502 DHD_PKT_MON(("\nTX (count: %d)\n", ++count));
1503 DHD_PKT_MON(("packet fate = %d\n", tx_pkt->fate));
1504 __dhd_dbg_dump_pkt_info(dhdp, &tx_pkt->info);
1505 }
1506 }
1507
__dhd_dbg_dump_rx_pkt_info(dhd_pub_t * dhdp,dhd_dbg_rx_info_t * rx_pkt,uint16 count)1508 void __dhd_dbg_dump_rx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkt,
1509 uint16 count)
1510 {
1511 if (DHD_PKT_MON_DUMP_ON()) {
1512 DHD_PKT_MON(("\nRX (count: %d)\n", ++count));
1513 DHD_PKT_MON(("packet fate = %d\n", rx_pkt->fate));
1514 __dhd_dbg_dump_pkt_info(dhdp, &rx_pkt->info);
1515 }
1516 }
1517
dhd_dbg_attach_pkt_monitor(dhd_pub_t * dhdp,dbg_mon_tx_pkts_t tx_pkt_mon,dbg_mon_tx_status_t tx_status_mon,dbg_mon_rx_pkts_t rx_pkt_mon)1518 int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp, dbg_mon_tx_pkts_t tx_pkt_mon,
1519 dbg_mon_tx_status_t tx_status_mon,
1520 dbg_mon_rx_pkts_t rx_pkt_mon)
1521 {
1522 dhd_dbg_tx_report_t *tx_report = NULL;
1523 dhd_dbg_rx_report_t *rx_report = NULL;
1524 dhd_dbg_tx_info_t *tx_pkts = NULL;
1525 dhd_dbg_rx_info_t *rx_pkts = NULL;
1526 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1527 dhd_dbg_pkt_mon_state_t tx_status_state;
1528 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1529 uint32 alloc_len;
1530 int ret = BCME_OK;
1531 unsigned long flags;
1532
1533 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1534 if (!dhdp || !dhdp->dbg) {
1535 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1536 (dhdp ? dhdp->dbg : NULL)));
1537 return -EINVAL;
1538 }
1539
1540 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1541 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1542 tx_status_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1543 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1544
1545 if (PKT_MON_ATTACHED(tx_pkt_state) || PKT_MON_ATTACHED(tx_status_state) ||
1546 PKT_MON_ATTACHED(rx_pkt_state)) {
1547 DHD_PKT_MON(("%s(): packet monitor is already attached, "
1548 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1549 __FUNCTION__, tx_pkt_state, tx_status_state,
1550 rx_pkt_state));
1551 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1552 /* return success as the intention was to initialize packet monitor */
1553 return BCME_OK;
1554 }
1555
1556 /* allocate and initialize tx packet monitoring */
1557 alloc_len = sizeof(*tx_report);
1558 tx_report = (dhd_dbg_tx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
1559 if (unlikely(!tx_report)) {
1560 DHD_ERROR(("%s(): could not allocate memory for - "
1561 "dhd_dbg_tx_report_t\n",
1562 __FUNCTION__));
1563 ret = -ENOMEM;
1564 goto fail;
1565 }
1566
1567 alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
1568 tx_pkts = (dhd_dbg_tx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
1569 if (unlikely(!tx_pkts)) {
1570 DHD_ERROR(("%s(): could not allocate memory for - "
1571 "dhd_dbg_tx_info_t\n",
1572 __FUNCTION__));
1573 ret = -ENOMEM;
1574 goto fail;
1575 }
1576 dhdp->dbg->pkt_mon.tx_report = tx_report;
1577 dhdp->dbg->pkt_mon.tx_report->tx_pkts = tx_pkts;
1578 dhdp->dbg->pkt_mon.tx_pkt_mon = tx_pkt_mon;
1579 dhdp->dbg->pkt_mon.tx_status_mon = tx_status_mon;
1580 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_ATTACHED;
1581 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_ATTACHED;
1582
1583 /* allocate and initialze rx packet monitoring */
1584 alloc_len = sizeof(*rx_report);
1585 rx_report = (dhd_dbg_rx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
1586 if (unlikely(!rx_report)) {
1587 DHD_ERROR(("%s(): could not allocate memory for - "
1588 "dhd_dbg_rx_report_t\n",
1589 __FUNCTION__));
1590 ret = -ENOMEM;
1591 goto fail;
1592 }
1593
1594 alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
1595 rx_pkts = (dhd_dbg_rx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
1596 if (unlikely(!rx_pkts)) {
1597 DHD_ERROR(("%s(): could not allocate memory for - "
1598 "dhd_dbg_rx_info_t\n",
1599 __FUNCTION__));
1600 ret = -ENOMEM;
1601 goto fail;
1602 }
1603 dhdp->dbg->pkt_mon.rx_report = rx_report;
1604 dhdp->dbg->pkt_mon.rx_report->rx_pkts = rx_pkts;
1605 dhdp->dbg->pkt_mon.rx_pkt_mon = rx_pkt_mon;
1606 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_ATTACHED;
1607
1608 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1609 DHD_PKT_MON(("%s(): packet monitor attach succeeded\n", __FUNCTION__));
1610 return ret;
1611
1612 fail:
1613 /* tx packet monitoring */
1614 if (tx_pkts) {
1615 alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
1616 MFREE(dhdp->osh, tx_pkts, alloc_len);
1617 }
1618 if (tx_report) {
1619 alloc_len = sizeof(*tx_report);
1620 MFREE(dhdp->osh, tx_report, alloc_len);
1621 }
1622 dhdp->dbg->pkt_mon.tx_report = NULL;
1623 dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
1624 dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
1625 dhdp->dbg->pkt_mon.tx_status_mon = NULL;
1626 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
1627 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
1628
1629 /* rx packet monitoring */
1630 if (rx_pkts) {
1631 alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
1632 MFREE(dhdp->osh, rx_pkts, alloc_len);
1633 }
1634 if (rx_report) {
1635 alloc_len = sizeof(*rx_report);
1636 MFREE(dhdp->osh, rx_report, alloc_len);
1637 }
1638 dhdp->dbg->pkt_mon.rx_report = NULL;
1639 dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
1640 dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
1641 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
1642
1643 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1644 DHD_ERROR(("%s(): packet monitor attach failed\n", __FUNCTION__));
1645 return ret;
1646 }
1647
dhd_dbg_start_pkt_monitor(dhd_pub_t * dhdp)1648 int dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
1649 {
1650 dhd_dbg_tx_report_t *tx_report;
1651 dhd_dbg_rx_report_t *rx_report;
1652 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1653 dhd_dbg_pkt_mon_state_t tx_status_state;
1654 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1655 unsigned long flags;
1656
1657 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1658 if (!dhdp || !dhdp->dbg) {
1659 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1660 (dhdp ? dhdp->dbg : NULL)));
1661 return -EINVAL;
1662 }
1663
1664 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1665 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1666 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1667 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1668
1669 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
1670 PKT_MON_DETACHED(rx_pkt_state)) {
1671 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
1672 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1673 __FUNCTION__, tx_pkt_state, tx_status_state,
1674 rx_pkt_state));
1675 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1676 return -EINVAL;
1677 }
1678
1679 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTING;
1680 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTING;
1681 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTING;
1682
1683 tx_report = dhdp->dbg->pkt_mon.tx_report;
1684 rx_report = dhdp->dbg->pkt_mon.rx_report;
1685 if (!tx_report || !rx_report) {
1686 DHD_PKT_MON(("%s(): tx_report=%p, rx_report=%p\n", __FUNCTION__,
1687 tx_report, rx_report));
1688 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1689 return -EINVAL;
1690 }
1691
1692 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1693 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1694 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1695
1696 /* Safe to free packets as state pkt_state is STARTING */
1697 __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, tx_report->pkt_pos);
1698
1699 __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, rx_report->pkt_pos);
1700
1701 /* reset array postion */
1702 tx_report->pkt_pos = 0;
1703 tx_report->status_pos = 0;
1704 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTED;
1705 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTED;
1706
1707 rx_report->pkt_pos = 0;
1708 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTED;
1709 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1710
1711 DHD_PKT_MON(("%s(): packet monitor started\n", __FUNCTION__));
1712 return BCME_OK;
1713 }
1714
dhd_dbg_monitor_tx_pkts(dhd_pub_t * dhdp,void * pkt,uint32 pktid)1715 int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid)
1716 {
1717 dhd_dbg_tx_report_t *tx_report;
1718 dhd_dbg_tx_info_t *tx_pkts;
1719 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1720 uint32 pkt_hash, driver_ts;
1721 uint16 pkt_pos;
1722 unsigned long flags;
1723
1724 if (!dhdp || !dhdp->dbg) {
1725 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1726 (dhdp ? dhdp->dbg : NULL)));
1727 return -EINVAL;
1728 }
1729
1730 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1731 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1732 if (PKT_MON_STARTED(tx_pkt_state)) {
1733 tx_report = dhdp->dbg->pkt_mon.tx_report;
1734 pkt_pos = tx_report->pkt_pos;
1735
1736 if (!PKT_MON_PKT_FULL(pkt_pos)) {
1737 tx_pkts = tx_report->tx_pkts;
1738 pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
1739 driver_ts = __dhd_dbg_driver_ts_usec();
1740
1741 tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
1742 tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
1743 tx_pkts[pkt_pos].info.pkt_hash = pkt_hash;
1744 tx_pkts[pkt_pos].info.driver_ts = driver_ts;
1745 tx_pkts[pkt_pos].info.firmware_ts = 0U;
1746 tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
1747 tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED;
1748
1749 tx_report->pkt_pos++;
1750 } else {
1751 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
1752 DHD_PKT_MON(("%s(): tx pkt logging stopped, reached "
1753 "max limit\n",
1754 __FUNCTION__));
1755 }
1756 }
1757
1758 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1759 return BCME_OK;
1760 }
1761
dhd_dbg_monitor_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)1762 int dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
1763 uint16 status)
1764 {
1765 dhd_dbg_tx_report_t *tx_report;
1766 dhd_dbg_tx_info_t *tx_pkt;
1767 dhd_dbg_pkt_mon_state_t tx_status_state;
1768 wifi_tx_packet_fate pkt_fate;
1769 uint32 pkt_hash, temp_hash;
1770 uint16 pkt_pos, status_pos;
1771 int16 count;
1772 bool found = FALSE;
1773 unsigned long flags;
1774
1775 if (!dhdp || !dhdp->dbg) {
1776 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1777 (dhdp ? dhdp->dbg : NULL)));
1778 return -EINVAL;
1779 }
1780
1781 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1782 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1783 if (PKT_MON_STARTED(tx_status_state)) {
1784 tx_report = dhdp->dbg->pkt_mon.tx_report;
1785 pkt_pos = tx_report->pkt_pos;
1786 status_pos = tx_report->status_pos;
1787
1788 if (!PKT_MON_STATUS_FULL(pkt_pos, status_pos)) {
1789 pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
1790 pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status);
1791
1792 /* best bet (in-order tx completion) */
1793 count = status_pos;
1794 tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + status_pos);
1795 while ((count < pkt_pos) && tx_pkt) {
1796 temp_hash = tx_pkt->info.pkt_hash;
1797 if (temp_hash == pkt_hash) {
1798 tx_pkt->fate = pkt_fate;
1799 tx_report->status_pos++;
1800 found = TRUE;
1801 break;
1802 }
1803 tx_pkt++;
1804 count++;
1805 }
1806
1807 /* search until beginning (handles out-of-order completion) */
1808 if (!found) {
1809 count = status_pos - 1;
1810 tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + count);
1811 while ((count >= 0) && tx_pkt) {
1812 temp_hash = tx_pkt->info.pkt_hash;
1813 if (temp_hash == pkt_hash) {
1814 tx_pkt->fate = pkt_fate;
1815 tx_report->status_pos++;
1816 found = TRUE;
1817 break;
1818 }
1819 tx_pkt--;
1820 count--;
1821 }
1822
1823 if (!found) {
1824 /* still couldn't match tx_status */
1825 DHD_ERROR(("%s(): couldn't match tx_status, pkt_pos=%u, "
1826 "status_pos=%u, pkt_fate=%u\n",
1827 __FUNCTION__, pkt_pos, status_pos, pkt_fate));
1828 }
1829 }
1830 } else {
1831 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
1832 DHD_PKT_MON(("%s(): tx_status logging stopped, reached "
1833 "max limit\n",
1834 __FUNCTION__));
1835 }
1836 }
1837
1838 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1839 return BCME_OK;
1840 }
1841
dhd_dbg_monitor_rx_pkts(dhd_pub_t * dhdp,void * pkt)1842 int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt)
1843 {
1844 dhd_dbg_rx_report_t *rx_report;
1845 dhd_dbg_rx_info_t *rx_pkts;
1846 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1847 uint32 driver_ts;
1848 uint16 pkt_pos;
1849 unsigned long flags;
1850
1851 if (!dhdp || !dhdp->dbg) {
1852 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1853 (dhdp ? dhdp->dbg : NULL)));
1854 return -EINVAL;
1855 }
1856
1857 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1858 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1859 if (PKT_MON_STARTED(rx_pkt_state)) {
1860 rx_report = dhdp->dbg->pkt_mon.rx_report;
1861 pkt_pos = rx_report->pkt_pos;
1862
1863 if (!PKT_MON_PKT_FULL(pkt_pos)) {
1864 rx_pkts = rx_report->rx_pkts;
1865 driver_ts = __dhd_dbg_driver_ts_usec();
1866
1867 rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
1868 rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
1869 rx_pkts[pkt_pos].info.pkt_hash = 0U;
1870 rx_pkts[pkt_pos].info.driver_ts = driver_ts;
1871 rx_pkts[pkt_pos].info.firmware_ts = 0U;
1872 rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
1873 rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS;
1874
1875 rx_report->pkt_pos++;
1876 } else {
1877 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
1878 DHD_PKT_MON(("%s(): rx pkt logging stopped, reached "
1879 "max limit\n",
1880 __FUNCTION__));
1881 }
1882 }
1883
1884 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1885 return BCME_OK;
1886 }
1887
dhd_dbg_stop_pkt_monitor(dhd_pub_t * dhdp)1888 int dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp)
1889 {
1890 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1891 dhd_dbg_pkt_mon_state_t tx_status_state;
1892 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1893 unsigned long flags;
1894
1895 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1896 if (!dhdp || !dhdp->dbg) {
1897 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1898 (dhdp ? dhdp->dbg : NULL)));
1899 return -EINVAL;
1900 }
1901
1902 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1903 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1904 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1905 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1906
1907 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
1908 PKT_MON_DETACHED(rx_pkt_state)) {
1909 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
1910 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1911 __FUNCTION__, tx_pkt_state, tx_status_state,
1912 rx_pkt_state));
1913 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1914 return -EINVAL;
1915 }
1916 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
1917 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
1918 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
1919 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1920
1921 DHD_PKT_MON(("%s(): packet monitor stopped\n", __FUNCTION__));
1922 return BCME_OK;
1923 }
1924
1925 #define __COPY_TO_USER(to, from, n) \
1926 do { \
1927 int __ret; \
1928 __ret = copy_to_user((void __user *)(to), (void *)(from), \
1929 (unsigned long)(n)); \
1930 if (unlikely(__ret)) { \
1931 DHD_ERROR(("%s():%d: copy_to_user failed, ret=%d\n", __FUNCTION__, \
1932 __LINE__, __ret)); \
1933 return __ret; \
1934 } \
1935 } while (0);
1936
dhd_dbg_monitor_get_tx_pkts(dhd_pub_t * dhdp,void __user * user_buf,uint16 req_count,uint16 * resp_count)1937 int dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
1938 uint16 req_count, uint16 *resp_count)
1939 {
1940 dhd_dbg_tx_report_t *tx_report;
1941 dhd_dbg_tx_info_t *tx_pkt;
1942 wifi_tx_report_t *ptr;
1943 compat_wifi_tx_report_t *cptr;
1944 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1945 dhd_dbg_pkt_mon_state_t tx_status_state;
1946 uint16 pkt_count, count;
1947 unsigned long flags;
1948
1949 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
1950 BCM_REFERENCE(ptr);
1951 BCM_REFERENCE(cptr);
1952
1953 if (!dhdp || !dhdp->dbg) {
1954 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
1955 (dhdp ? dhdp->dbg : NULL)));
1956 return -EINVAL;
1957 }
1958
1959 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1960 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1961 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1962 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state)) {
1963 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
1964 "tx_pkt_state=%d, tx_status_state=%d\n",
1965 __FUNCTION__, tx_pkt_state, tx_status_state));
1966 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1967 return -EINVAL;
1968 }
1969
1970 count = 0;
1971 tx_report = dhdp->dbg->pkt_mon.tx_report;
1972 tx_pkt = tx_report->tx_pkts;
1973 pkt_count = MIN(req_count, tx_report->status_pos);
1974
1975 #ifdef CONFIG_COMPAT
1976 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
1977 if (in_compat_syscall())
1978 #else
1979 if (is_compat_task())
1980 #endif
1981 {
1982 cptr = (compat_wifi_tx_report_t *)user_buf;
1983 while ((count < pkt_count) && tx_pkt && cptr) {
1984 compat_wifi_tx_report_t *comp_ptr = compat_ptr((uintptr_t)cptr);
1985 compat_dhd_dbg_pkt_info_t compat_tx_pkt;
1986 __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count);
1987 __COPY_TO_USER(&comp_ptr->fate, &tx_pkt->fate,
1988 sizeof(tx_pkt->fate));
1989
1990 compat_tx_pkt.payload_type = tx_pkt->info.payload_type;
1991 compat_tx_pkt.pkt_len = tx_pkt->info.pkt_len;
1992 compat_tx_pkt.driver_ts = tx_pkt->info.driver_ts;
1993 compat_tx_pkt.firmware_ts = tx_pkt->info.firmware_ts;
1994 compat_tx_pkt.pkt_hash = tx_pkt->info.pkt_hash;
1995 __COPY_TO_USER(&comp_ptr->frame_inf.payload_type,
1996 &compat_tx_pkt.payload_type,
1997 OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash));
1998 __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii,
1999 PKTDATA(dhdp->osh, tx_pkt->info.pkt),
2000 tx_pkt->info.pkt_len);
2001
2002 cptr++;
2003 tx_pkt++;
2004 count++;
2005 }
2006 } else
2007 #endif /* CONFIG_COMPAT */
2008 {
2009 ptr = (wifi_tx_report_t *)user_buf;
2010 while ((count < pkt_count) && tx_pkt && ptr) {
2011 __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count);
2012 __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate));
2013 __COPY_TO_USER(&ptr->frame_inf.payload_type,
2014 &tx_pkt->info.payload_type,
2015 OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
2016 __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
2017 PKTDATA(dhdp->osh, tx_pkt->info.pkt),
2018 tx_pkt->info.pkt_len);
2019
2020 ptr++;
2021 tx_pkt++;
2022 count++;
2023 }
2024 }
2025 *resp_count = pkt_count;
2026
2027 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2028 if (!pkt_count) {
2029 DHD_ERROR(("%s(): no tx_status in tx completion messages, "
2030 "make sure that 'd11status' is enabled in firmware, "
2031 "status_pos=%u\n",
2032 __FUNCTION__, pkt_count));
2033 }
2034
2035 return BCME_OK;
2036 }
2037
dhd_dbg_monitor_get_rx_pkts(dhd_pub_t * dhdp,void __user * user_buf,uint16 req_count,uint16 * resp_count)2038 int dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
2039 uint16 req_count, uint16 *resp_count)
2040 {
2041 dhd_dbg_rx_report_t *rx_report;
2042 dhd_dbg_rx_info_t *rx_pkt;
2043 wifi_rx_report_t *ptr;
2044 compat_wifi_rx_report_t *cptr;
2045 dhd_dbg_pkt_mon_state_t rx_pkt_state;
2046 uint16 pkt_count, count;
2047 unsigned long flags;
2048
2049 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
2050 BCM_REFERENCE(ptr);
2051 BCM_REFERENCE(cptr);
2052
2053 if (!dhdp || !dhdp->dbg) {
2054 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
2055 (dhdp ? dhdp->dbg : NULL)));
2056 return -EINVAL;
2057 }
2058
2059 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
2060 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
2061 if (PKT_MON_DETACHED(rx_pkt_state)) {
2062 DHD_PKT_MON(("%s(): packet fetch is not allowed , "
2063 "rx_pkt_state=%d\n",
2064 __FUNCTION__, rx_pkt_state));
2065 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2066 return -EINVAL;
2067 }
2068
2069 count = 0;
2070 rx_report = dhdp->dbg->pkt_mon.rx_report;
2071 rx_pkt = rx_report->rx_pkts;
2072 pkt_count = MIN(req_count, rx_report->pkt_pos);
2073
2074 #ifdef CONFIG_COMPAT
2075 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2076 if (in_compat_syscall())
2077 #else
2078 if (is_compat_task())
2079 #endif
2080 {
2081 cptr = (compat_wifi_rx_report_t *)user_buf;
2082 while ((count < pkt_count) && rx_pkt && cptr) {
2083 compat_wifi_rx_report_t *comp_ptr = compat_ptr((uintptr_t)cptr);
2084 compat_dhd_dbg_pkt_info_t compat_rx_pkt;
2085 __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count);
2086 __COPY_TO_USER(&comp_ptr->fate, &rx_pkt->fate,
2087 sizeof(rx_pkt->fate));
2088
2089 compat_rx_pkt.payload_type = rx_pkt->info.payload_type;
2090 compat_rx_pkt.pkt_len = rx_pkt->info.pkt_len;
2091 compat_rx_pkt.driver_ts = rx_pkt->info.driver_ts;
2092 compat_rx_pkt.firmware_ts = rx_pkt->info.firmware_ts;
2093 compat_rx_pkt.pkt_hash = rx_pkt->info.pkt_hash;
2094 __COPY_TO_USER(&comp_ptr->frame_inf.payload_type,
2095 &compat_rx_pkt.payload_type,
2096 OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash));
2097 __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii,
2098 PKTDATA(dhdp->osh, rx_pkt->info.pkt),
2099 rx_pkt->info.pkt_len);
2100
2101 cptr++;
2102 rx_pkt++;
2103 count++;
2104 }
2105 } else
2106 #endif /* CONFIG_COMPAT */
2107 {
2108 ptr = (wifi_rx_report_t *)user_buf;
2109 while ((count < pkt_count) && rx_pkt && ptr) {
2110 __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count);
2111
2112 __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate));
2113 __COPY_TO_USER(&ptr->frame_inf.payload_type,
2114 &rx_pkt->info.payload_type,
2115 OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
2116 __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
2117 PKTDATA(dhdp->osh, rx_pkt->info.pkt),
2118 rx_pkt->info.pkt_len);
2119
2120 ptr++;
2121 rx_pkt++;
2122 count++;
2123 }
2124 }
2125
2126 *resp_count = pkt_count;
2127 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2128
2129 return BCME_OK;
2130 }
2131
dhd_dbg_detach_pkt_monitor(dhd_pub_t * dhdp)2132 int dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp)
2133 {
2134 dhd_dbg_tx_report_t *tx_report;
2135 dhd_dbg_rx_report_t *rx_report;
2136 dhd_dbg_pkt_mon_state_t tx_pkt_state;
2137 dhd_dbg_pkt_mon_state_t tx_status_state;
2138 dhd_dbg_pkt_mon_state_t rx_pkt_state;
2139 unsigned long flags;
2140
2141 DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
2142 if (!dhdp || !dhdp->dbg) {
2143 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, dhdp,
2144 (dhdp ? dhdp->dbg : NULL)));
2145 return -EINVAL;
2146 }
2147
2148 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
2149 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
2150 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
2151 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
2152
2153 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
2154 PKT_MON_DETACHED(rx_pkt_state)) {
2155 DHD_PKT_MON(("%s(): packet monitor is already detached, "
2156 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
2157 __FUNCTION__, tx_pkt_state, tx_status_state,
2158 rx_pkt_state));
2159 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2160 return -EINVAL;
2161 }
2162
2163 tx_report = dhdp->dbg->pkt_mon.tx_report;
2164 rx_report = dhdp->dbg->pkt_mon.rx_report;
2165
2166 /* free and de-initalize tx packet monitoring */
2167 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
2168 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
2169 if (tx_report) {
2170 if (tx_report->tx_pkts) {
2171 __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts,
2172 tx_report->pkt_pos);
2173 MFREE(dhdp->osh, tx_report->tx_pkts,
2174 (sizeof(*tx_report->tx_pkts) * MAX_FATE_LOG_LEN));
2175 dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
2176 }
2177 MFREE(dhdp->osh, tx_report, sizeof(*tx_report));
2178 dhdp->dbg->pkt_mon.tx_report = NULL;
2179 }
2180 dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
2181 dhdp->dbg->pkt_mon.tx_status_mon = NULL;
2182
2183 /* free and de-initalize rx packet monitoring */
2184 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
2185 if (rx_report) {
2186 if (rx_report->rx_pkts) {
2187 __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts,
2188 rx_report->pkt_pos);
2189 MFREE(dhdp->osh, rx_report->rx_pkts,
2190 (sizeof(*rx_report->rx_pkts) * MAX_FATE_LOG_LEN));
2191 dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
2192 }
2193 MFREE(dhdp->osh, rx_report, sizeof(*rx_report));
2194 dhdp->dbg->pkt_mon.rx_report = NULL;
2195 }
2196 dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
2197
2198 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2199 DHD_PKT_MON(("%s(): packet monitor detach succeeded\n", __FUNCTION__));
2200 return BCME_OK;
2201 }
2202 #endif /* DBG_PKT_MON */
2203
2204 #if defined(DBG_PKT_MON)
dhd_dbg_process_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)2205 bool dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
2206 uint16 status)
2207 {
2208 bool pkt_fate = TRUE;
2209 if (dhdp->d11_tx_status) {
2210 pkt_fate = (status == WLFC_CTL_PKTFLAG_DISCARD) ? TRUE : FALSE;
2211 DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status);
2212 }
2213 return pkt_fate;
2214 }
2215 #else /* DBG_PKT_MON || DHD_PKT_LOGGING */
dhd_dbg_process_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)2216 bool dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
2217 uint16 status)
2218 {
2219 return TRUE;
2220 }
2221 #endif // endif
2222
2223 #define EL_LOG_STR_LEN 512
2224
print_roam_enhanced_log(prcd_event_log_hdr_t * plog_hdr)2225 void print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr)
2226 {
2227 prsv_periodic_log_hdr_t *hdr = (prsv_periodic_log_hdr_t *)plog_hdr->log_ptr;
2228 char chanspec_buf[CHANSPEC_STR_LEN];
2229
2230 if (hdr->version != ROAM_LOG_VER_1) {
2231 DHD_ERROR(("ROAM_LOG ENHANCE: version is not matched\n"));
2232 goto default_print;
2233 return;
2234 }
2235
2236 switch (hdr->id) {
2237 case ROAM_LOG_SCANSTART: {
2238 roam_log_trig_v1_t *log = (roam_log_trig_v1_t *)plog_hdr->log_ptr;
2239 DHD_ERROR(("ROAM_LOG_SCANSTART time: %d,"
2240 " version:%d reason: %d rssi:%d cu:%d result:%d\n",
2241 plog_hdr->armcycle, log->hdr.version, log->reason,
2242 log->rssi, log->current_cu, log->result));
2243 if (log->reason == WLC_E_REASON_DEAUTH ||
2244 log->reason == WLC_E_REASON_DISASSOC) {
2245 DHD_ERROR((" ROAM_LOG_PRT_ROAM: RCVD reason:%d\n",
2246 log->prt_roam.rcvd_reason));
2247 } else if (log->reason == WLC_E_REASON_BSSTRANS_REQ) {
2248 DHD_ERROR((" ROAM_LOG_BSS_REQ: mode:%d candidate:%d token:%d "
2249 "duration disassoc:%d valid:%d term:%d\n",
2250 log->bss_trans.req_mode, log->bss_trans.nbrlist_size,
2251 log->bss_trans.token, log->bss_trans.disassoc_dur,
2252 log->bss_trans.validity_dur,
2253 log->bss_trans.bss_term_dur));
2254 }
2255 break;
2256 }
2257 case ROAM_LOG_SCAN_CMPLT: {
2258 int i;
2259 roam_log_scan_cmplt_v1_t *log =
2260 (roam_log_scan_cmplt_v1_t *)plog_hdr->log_ptr;
2261
2262 DHD_ERROR(("ROAM_LOG_SCAN_CMPL: time:%d version:%d"
2263 "is_full:%d scan_count:%d score_delta:%d",
2264 plog_hdr->armcycle, log->hdr.version, log->full_scan,
2265 log->scan_count, log->score_delta));
2266 DHD_ERROR(
2267 (" ROAM_LOG_CUR_AP: " MACDBG "rssi:%d score:%d channel:%s\n",
2268 MAC2STRDBG((uint8 *)&log->cur_info.addr), log->cur_info.rssi,
2269 log->cur_info.score,
2270 wf_chspec_ntoa_ex(log->cur_info.chanspec, chanspec_buf)));
2271 for (i = 0; i < log->scan_list_size; i++) {
2272 DHD_ERROR((
2273 " ROAM_LOG_CANDIDATE %d: " MACDBG
2274 "rssi:%d score:%d channel:%s TPUT:%dkbps\n",
2275 i, MAC2STRDBG((uint8 *)&log->scan_list[i].addr),
2276 log->scan_list[i].rssi, log->scan_list[i].score,
2277 wf_chspec_ntoa_ex(log->scan_list[i].chanspec, chanspec_buf),
2278 log->scan_list[i].estm_tput != ROAM_LOG_INVALID_TPUT
2279 ? log->scan_list[i].estm_tput
2280 : 0));
2281 }
2282 break;
2283 }
2284 case ROAM_LOG_ROAM_CMPLT: {
2285 roam_log_cmplt_v1_t *log = (roam_log_cmplt_v1_t *)plog_hdr->log_ptr;
2286 DHD_ERROR(("ROAM_LOG_ROAM_CMPL: time: %d, version:%d"
2287 "status: %d reason: %d channel:%s retry:%d " MACDBG "\n",
2288 plog_hdr->armcycle, log->hdr.version, log->status,
2289 log->reason,
2290 wf_chspec_ntoa_ex(log->chanspec, chanspec_buf),
2291 log->retry, MAC2STRDBG((uint8 *)&log->addr)));
2292 break;
2293 }
2294 case ROAM_LOG_NBR_REQ: {
2295 roam_log_nbrreq_v1_t *log =
2296 (roam_log_nbrreq_v1_t *)plog_hdr->log_ptr;
2297 DHD_ERROR(("ROAM_LOG_NBR_REQ: time: %d, version:%d token:%d\n",
2298 plog_hdr->armcycle, log->hdr.version, log->token));
2299 break;
2300 }
2301 case ROAM_LOG_NBR_REP: {
2302 roam_log_nbrrep_v1_t *log =
2303 (roam_log_nbrrep_v1_t *)plog_hdr->log_ptr;
2304 DHD_ERROR(("ROAM_LOG_NBR_REP: time:%d, veresion:%d chan_num:%d\n",
2305 plog_hdr->armcycle, log->hdr.version, log->channel_num));
2306 break;
2307 }
2308 case ROAM_LOG_BCN_REQ: {
2309 roam_log_bcnrpt_req_v1_t *log =
2310 (roam_log_bcnrpt_req_v1_t *)plog_hdr->log_ptr;
2311 DHD_ERROR(("ROAM_LOG_BCN_REQ: time:%d, version:%d ret:%d"
2312 "class:%d num_chan:%d ",
2313 plog_hdr->armcycle, log->hdr.version, log->result,
2314 log->reg, log->channel));
2315 DHD_ERROR(("ROAM_LOG_BCN_REQ: mode:%d is_wild:%d duration:%d"
2316 "ssid_len:%d\n",
2317 log->mode, log->bssid_wild, log->duration,
2318 log->ssid_len));
2319 break;
2320 }
2321 case ROAM_LOG_BCN_REP: {
2322 roam_log_bcnrpt_rep_v1_t *log =
2323 (roam_log_bcnrpt_rep_v1_t *)plog_hdr->log_ptr;
2324 DHD_ERROR(("ROAM_LOG_BCN_REP: time:%d, verseion:%d count:%d\n",
2325 plog_hdr->armcycle, log->hdr.version, log->count));
2326 break;
2327 }
2328 default:
2329 goto default_print;
2330 }
2331
2332 return;
2333
2334 default_print : {
2335 uint32 *ptr = (uint32 *)plog_hdr->log_ptr;
2336 int i;
2337 int loop_cnt = hdr->length / sizeof(uint32);
2338 struct bcmstrbuf b;
2339 char pr_buf[EL_LOG_STR_LEN] = {0};
2340
2341 bcm_binit(&b, pr_buf, EL_LOG_STR_LEN);
2342 bcm_bprintf(&b, "ROAM_LOG_UNKNOWN ID:%d ver:%d armcycle:%d", hdr->id,
2343 hdr->version, plog_hdr->armcycle);
2344 for (i = 0; i < loop_cnt && b.size > 0; i++) {
2345 bcm_bprintf(&b, " %x", *ptr);
2346 ptr++;
2347 }
2348 DHD_ERROR(("%s\n", b.origbuf));
2349 }
2350 }
2351
2352 /*
2353 * dhd_dbg_attach: initialziation of dhd dbugability module
2354 *
2355 * Return: An error code or 0 on success.
2356 */
dhd_dbg_attach(dhd_pub_t * dhdp,dbg_pullreq_t os_pullreq,dbg_urgent_noti_t os_urgent_notifier,void * os_priv)2357 int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
2358 dbg_urgent_noti_t os_urgent_notifier, void *os_priv)
2359 {
2360 dhd_dbg_t *dbg = NULL;
2361 dhd_dbg_ring_t *ring = NULL;
2362 int ret = BCME_ERROR, ring_id = 0;
2363 void *buf = NULL;
2364
2365 dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t));
2366 if (!dbg) {
2367 return BCME_NOMEM;
2368 }
2369
2370 #ifdef CONFIG_DHD_USE_STATIC_BUF
2371 buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_FW_VERBOSE_RING,
2372 FW_VERBOSE_RING_SIZE);
2373 #else
2374 buf = MALLOCZ(dhdp->osh, FW_VERBOSE_RING_SIZE);
2375 #endif
2376 if (!buf) {
2377 goto error;
2378 }
2379 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID],
2380 FW_VERBOSE_RING_ID, (uint8 *)FW_VERBOSE_RING_NAME,
2381 FW_VERBOSE_RING_SIZE, buf, FALSE);
2382 if (ret) {
2383 goto error;
2384 }
2385
2386 #ifdef CONFIG_DHD_USE_STATIC_BUF
2387 buf =
2388 DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE);
2389 #else
2390 buf = MALLOCZ(dhdp->osh, DHD_EVENT_RING_SIZE);
2391 #endif
2392 if (!buf) {
2393 goto error;
2394 }
2395 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID],
2396 DHD_EVENT_RING_ID, (uint8 *)DHD_EVENT_RING_NAME,
2397 DHD_EVENT_RING_SIZE, buf, FALSE);
2398 if (ret) {
2399 goto error;
2400 }
2401
2402 dbg->private = os_priv;
2403 dbg->pullreq = os_pullreq;
2404 dbg->urgent_notifier = os_urgent_notifier;
2405 dhdp->dbg = dbg;
2406
2407 return BCME_OK;
2408
2409 error:
2410 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
2411 ring_id++) {
2412 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
2413 ring = &dbg->dbg_rings[ring_id];
2414 dhd_dbg_ring_deinit(dhdp, ring);
2415 if (ring->ring_buf) {
2416 #ifndef CONFIG_DHD_USE_STATIC_BUF
2417 MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
2418 #endif
2419 ring->ring_buf = NULL;
2420 }
2421 ring->ring_size = 0;
2422 }
2423 }
2424 MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
2425
2426 return ret;
2427 }
2428
2429 /*
2430 * dhd_dbg_detach: clean up dhd dbugability module
2431 */
dhd_dbg_detach(dhd_pub_t * dhdp)2432 void dhd_dbg_detach(dhd_pub_t *dhdp)
2433 {
2434 int ring_id;
2435 dhd_dbg_ring_t *ring = NULL;
2436 dhd_dbg_t *dbg;
2437
2438 if (!dhdp->dbg) {
2439 return;
2440 }
2441 dbg = dhdp->dbg;
2442 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
2443 ring_id++) {
2444 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
2445 ring = &dbg->dbg_rings[ring_id];
2446 dhd_dbg_ring_deinit(dhdp, ring);
2447 if (ring->ring_buf) {
2448 #ifndef CONFIG_DHD_USE_STATIC_BUF
2449 MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
2450 #endif
2451 ring->ring_buf = NULL;
2452 }
2453 ring->ring_size = 0;
2454 }
2455 }
2456 MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
2457 }
2458