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