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