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