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 if (dhd_msg_level & DHD_EVENT_VAL) {
836 if (dhd_msg_level & DHD_PRSRV_MEM_VAL)
837 printk(fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3],
838 arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10],
839 arg[11], arg[12], arg[13], arg[14], arg[15]);
840 }
841 } else {
842 if (dhd_msg_level & DHD_FWLOG_VAL) {
843 printk(fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3],
844 arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10],
845 arg[11], arg[12], arg[13], arg[14], arg[15]);
846 }
847 #ifdef DHD_LOG_PRINT_RATE_LIMIT
848 log_print_count++;
849 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
850 }
851
852 exit:
853 MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
854 }
855
856 #if defined(EWP_BCM_TRACE) || defined(EWP_RTT_LOGGING) || \
857 defined(EWP_ECNTRS_LOGGING)
858 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)859 dhd_dbg_send_evtlog_to_ring(prcd_event_log_hdr_t *plog_hdr,
860 dhd_dbg_ring_entry_t *msg_hdr, dhd_dbg_ring_t *ring,
861 uint16 max_payload_len, uint8 *logbuf)
862 {
863 event_log_hdr_t *log_hdr;
864 struct tracelog_header *logentry_header;
865 uint16 len_chk = 0;
866
867 BCM_REFERENCE(log_hdr);
868 BCM_REFERENCE(logentry_header);
869 /*
870 * check msg hdr len before pushing.
871 * FW msg_hdr.len includes length of event log hdr,
872 * logentry header and payload.
873 */
874 len_chk = (sizeof(*logentry_header) + sizeof(*log_hdr) +
875 max_payload_len);
876 /* account extended event log header(extended_event_log_hdr) */
877 if (plog_hdr->ext_event_log_hdr) {
878 len_chk += sizeof(*log_hdr);
879 }
880 if (msg_hdr->len > len_chk) {
881 DHD_ERROR(("%s: EVENT_LOG_VALIDATION_FAILS: "
882 "msg_hdr->len=%u, max allowed for %s=%u\n",
883 __FUNCTION__, msg_hdr->len, ring->name, len_chk));
884 return BCME_ERROR;
885 }
886 dhd_dbg_ring_push(ring, msg_hdr, logbuf);
887 return BCME_OK;
888 }
889 #endif /* EWP_BCM_TRACE || EWP_RTT_LOGGING || EWP_ECNTRS_LOGGING */
890
891 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)892 dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
893 void *raw_event_ptr, uint datalen, bool msgtrace_hdr_present,
894 uint32 msgtrace_seqnum)
895 {
896 msgtrace_hdr_t *hdr;
897 char *data, *tmpdata;
898 const uint32 log_hdr_len = sizeof(event_log_hdr_t);
899 uint32 log_pyld_len;
900 static uint32 seqnum_prev = 0;
901 event_log_hdr_t *log_hdr;
902 bool msg_processed = FALSE;
903 prcd_event_log_hdr_t prcd_log_hdr;
904 prcd_event_log_hdr_t *plog_hdr;
905 dll_t list_head, *cur;
906 loglist_item_t *log_item;
907 dhd_dbg_ring_entry_t msg_hdr;
908 char *logbuf;
909 struct tracelog_header *logentry_header;
910 uint ring_data_len = 0;
911 bool ecntr_pushed = FALSE;
912 bool rtt_pushed = FALSE;
913 bool bcm_trace_pushed = FALSE;
914 bool dll_inited = FALSE;
915 uint32 logset = 0;
916 uint16 block = 0;
917 bool event_log_max_sets_queried;
918 uint32 event_log_max_sets;
919 uint min_expected_len = 0;
920 uint16 len_chk = 0;
921
922 BCM_REFERENCE(ecntr_pushed);
923 BCM_REFERENCE(rtt_pushed);
924 BCM_REFERENCE(bcm_trace_pushed);
925 BCM_REFERENCE(len_chk);
926
927 /* store event_logset_queried and event_log_max_sets in local variables
928 * to avoid race conditions as they were set from different contexts(preinit)
929 */
930 event_log_max_sets_queried = dhdp->event_log_max_sets_queried;
931 /* Make sure queried is read first with wmb and then max_sets,
932 * as it is done in reverse order during preinit ioctls.
933 */
934 OSL_SMP_WMB();
935 event_log_max_sets = dhdp->event_log_max_sets;
936
937 if (msgtrace_hdr_present)
938 min_expected_len = (MSGTRACE_HDRLEN + EVENT_LOG_BLOCK_LEN);
939 else
940 min_expected_len = EVENT_LOG_BLOCK_LEN;
941
942 /* log trace event consists of:
943 * msgtrace header
944 * event log block header
945 * event log payload
946 */
947 if (!event_data || (datalen <= min_expected_len)) {
948 DHD_ERROR(("%s: Not processing due to invalid event_data : %p or length : %d\n",
949 __FUNCTION__, event_data, datalen));
950 if (event_data && msgtrace_hdr_present) {
951 prhex("event_data dump", event_data, datalen);
952 tmpdata = (char *)event_data + MSGTRACE_HDRLEN;
953 if (tmpdata) {
954 DHD_ERROR(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
955 ltoh16(*((uint16 *)(tmpdata+2))),
956 ltoh32(*((uint32 *)(tmpdata + 4))),
957 ltoh16(*((uint16 *)(tmpdata)))));
958 }
959 } else if (!event_data) {
960 DHD_ERROR(("%s: event_data is NULL, cannot dump prhex\n", __FUNCTION__));
961 }
962
963 return;
964 }
965
966 if (msgtrace_hdr_present) {
967 hdr = (msgtrace_hdr_t *)event_data;
968 data = (char *)event_data + MSGTRACE_HDRLEN;
969 datalen -= MSGTRACE_HDRLEN;
970 msgtrace_seqnum = ntoh32(hdr->seqnum);
971 } else {
972 data = (char *)event_data;
973 }
974
975 if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, msgtrace_seqnum))
976 return;
977
978 /* Save the whole message to event log ring */
979 memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t));
980 logbuf = VMALLOC(dhdp->osh, sizeof(*logentry_header) + datalen);
981 if (logbuf == NULL)
982 return;
983 logentry_header = (struct tracelog_header *)logbuf;
984 logentry_header->magic_num = TRACE_LOG_MAGIC_NUMBER;
985 logentry_header->buf_size = datalen;
986 logentry_header->seq_num = msgtrace_seqnum;
987 msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
988
989 ring_data_len = datalen + sizeof(*logentry_header);
990
991 if ((sizeof(*logentry_header) + datalen) > PAYLOAD_MAX_LEN) {
992 DHD_ERROR(("%s:Payload len=%u exceeds max len\n", __FUNCTION__,
993 ((uint)sizeof(*logentry_header) + datalen)));
994 goto exit;
995 }
996
997 msg_hdr.len = sizeof(*logentry_header) + datalen;
998 memcpy(logbuf + sizeof(*logentry_header), data, datalen);
999 DHD_DBGIF(("%s: datalen %d %d\n", __FUNCTION__, msg_hdr.len, datalen));
1000 #ifndef DHD_DEBUGABILITY_LOG_DUMP_RING
1001 dhd_dbg_push_to_ring(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf);
1002 #endif
1003 /* Print sequence number, originating set and length of received
1004 * event log buffer. Refer to event log buffer structure in
1005 * event_log.h
1006 */
1007 DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
1008 ltoh16(*((uint16 *)(data+2))), ltoh32(*((uint32 *)(data + 4))),
1009 ltoh16(*((uint16 *)(data)))));
1010
1011 logset = ltoh32(*((uint32 *)(data + 4)));
1012
1013 if (logset >= event_log_max_sets) {
1014 DHD_ERROR(("%s logset: %d max: %d out of range queried: %d\n",
1015 __FUNCTION__, logset, event_log_max_sets, event_log_max_sets_queried));
1016 #ifdef DHD_FW_COREDUMP
1017 if (event_log_max_sets_queried) {
1018 DHD_ERROR(("%s: collect socram for DUMP_TYPE_LOGSET_BEYOND_RANGE\n",
1019 __FUNCTION__));
1020 dhdp->memdump_type = DUMP_TYPE_LOGSET_BEYOND_RANGE;
1021 dhd_bus_mem_dump(dhdp);
1022 }
1023 #endif /* DHD_FW_COREDUMP */
1024 }
1025
1026 block = ltoh16(*((uint16 *)(data + 2)));
1027
1028 data += EVENT_LOG_BLOCK_HDRLEN;
1029 datalen -= EVENT_LOG_BLOCK_HDRLEN;
1030
1031 /* start parsing from the tail of packet
1032 * Sameple format of a meessage
1033 * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639
1034 * 001d3c54 00000064 00000064 035d6d89 0c580439
1035 * 0x0c580439 -- 39 is tag, 04 is count, 580c is format number
1036 * all these uint32 values comes in reverse order as group as EL data
1037 * while decoding we can only parse from last to first
1038 * |<- datalen ->|
1039 * |----(payload and maybe more logs)----|event_log_hdr_t|
1040 * data log_hdr
1041 */
1042 dll_init(&list_head);
1043 dll_inited = TRUE;
1044
1045 while (datalen > log_hdr_len) {
1046 log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len);
1047 memset(&prcd_log_hdr, 0, sizeof(prcd_log_hdr));
1048 if (!dhd_dbg_process_event_log_hdr(log_hdr, &prcd_log_hdr)) {
1049 DHD_ERROR(("%s: Error while parsing event log header\n",
1050 __FUNCTION__));
1051 }
1052
1053 /* skip zero padding at end of frame */
1054 if (prcd_log_hdr.tag == EVENT_LOG_TAG_NULL) {
1055 datalen -= log_hdr_len;
1056 continue;
1057 }
1058 /* Check argument count (for non-ecounter events only),
1059 * any event log should contain at least
1060 * one argument (4 bytes) for arm cycle count and up to 16
1061 * arguments except EVENT_LOG_TAG_STATS which could use the
1062 * whole payload of 256 words
1063 */
1064 if (prcd_log_hdr.count == 0) {
1065 break;
1066 }
1067 /* Both tag_stats and proxd are binary payloads so skip
1068 * argument count check for these.
1069 */
1070 if ((prcd_log_hdr.tag != EVENT_LOG_TAG_STATS) &&
1071 (prcd_log_hdr.tag != EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
1072 (prcd_log_hdr.tag != EVENT_LOG_TAG_ROAM_ENHANCED_LOG) &&
1073 (prcd_log_hdr.tag != EVENT_LOG_TAG_BCM_TRACE) &&
1074 (prcd_log_hdr.count > MAX_NO_OF_ARG)) {
1075 break;
1076 }
1077
1078 log_pyld_len = (prcd_log_hdr.count + prcd_log_hdr.ext_event_log_hdr) *
1079 DATA_UNIT_FOR_LOG_CNT;
1080 /* log data should not cross the event data boundary */
1081 if ((uint32)((char *)log_hdr - data) < log_pyld_len) {
1082 break;
1083 }
1084 /* skip 4 bytes time stamp packet */
1085 if (prcd_log_hdr.tag == EVENT_LOG_TAG_TS ||
1086 prcd_log_hdr.tag == EVENT_LOG_TAG_ENHANCED_TS) {
1087 datalen -= (log_pyld_len + log_hdr_len);
1088 continue;
1089 }
1090 if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) {
1091 DHD_ERROR(("%s allocating log list item failed\n",
1092 __FUNCTION__));
1093 break;
1094 }
1095
1096 log_item->prcd_log_hdr.tag = prcd_log_hdr.tag;
1097 log_item->prcd_log_hdr.count = prcd_log_hdr.count;
1098 log_item->prcd_log_hdr.fmt_num = prcd_log_hdr.fmt_num;
1099 log_item->prcd_log_hdr.fmt_num_raw = prcd_log_hdr.fmt_num_raw;
1100 log_item->prcd_log_hdr.armcycle = prcd_log_hdr.armcycle;
1101 log_item->prcd_log_hdr.log_ptr = prcd_log_hdr.log_ptr;
1102 log_item->prcd_log_hdr.payload_len = prcd_log_hdr.payload_len;
1103 log_item->prcd_log_hdr.ext_event_log_hdr = prcd_log_hdr.ext_event_log_hdr;
1104 log_item->prcd_log_hdr.binary_payload = prcd_log_hdr.binary_payload;
1105
1106 dll_insert(&log_item->list, &list_head);
1107 datalen -= (log_pyld_len + log_hdr_len);
1108 }
1109
1110 while (!dll_empty(&list_head)) {
1111 msg_processed = FALSE;
1112 cur = dll_head_p(&list_head);
1113
1114 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1115 log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
1116 GCC_DIAGNOSTIC_POP();
1117
1118 plog_hdr = &log_item->prcd_log_hdr;
1119 #if defined(EWP_ECNTRS_LOGGING) && defined(DHD_LOG_DUMP)
1120 /* Ecounter tag can be time_data or log_stats+binary paloaod */
1121 if ((plog_hdr->tag == EVENT_LOG_TAG_ECOUNTERS_TIME_DATA) ||
1122 ((plog_hdr->tag == EVENT_LOG_TAG_STATS) &&
1123 (plog_hdr->binary_payload))) {
1124 if (!ecntr_pushed && dhd_log_dump_ecntr_enabled()) {
1125 if (dhd_dbg_send_evtlog_to_ring(plog_hdr, &msg_hdr,
1126 dhdp->ecntr_dbg_ring,
1127 PAYLOAD_ECNTR_MAX_LEN, logbuf) != BCME_OK) {
1128 goto exit;
1129 }
1130 ecntr_pushed = TRUE;
1131 }
1132 }
1133 #endif /* EWP_ECNTRS_LOGGING && DHD_LOG_DUMP */
1134
1135 if (plog_hdr->tag == EVENT_LOG_TAG_ROAM_ENHANCED_LOG) {
1136 print_roam_enhanced_log(plog_hdr);
1137 msg_processed = TRUE;
1138 }
1139 #if defined(EWP_RTT_LOGGING) && defined(DHD_LOG_DUMP)
1140 if ((plog_hdr->tag == EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
1141 plog_hdr->binary_payload) {
1142 if (!rtt_pushed && dhd_log_dump_rtt_enabled()) {
1143 if (dhd_dbg_send_evtlog_to_ring(plog_hdr, &msg_hdr,
1144 dhdp->rtt_dbg_ring,
1145 PAYLOAD_RTT_MAX_LEN, logbuf) != BCME_OK) {
1146 goto exit;
1147 }
1148 rtt_pushed = TRUE;
1149 }
1150 }
1151 #endif /* EWP_RTT_LOGGING && DHD_LOG_DUMP */
1152
1153 #ifdef EWP_BCM_TRACE
1154 if ((logset == EVENT_LOG_SET_BCM_TRACE) && !bcm_trace_pushed &&
1155 plog_hdr->binary_payload) {
1156 if (dhd_dbg_send_evtlog_to_ring(plog_hdr, &msg_hdr,
1157 dhdp->bcm_trace_dbg_ring,
1158 PAYLOAD_BCM_TRACE_MAX_LEN, logbuf) != BCME_OK) {
1159 goto exit;
1160 }
1161 bcm_trace_pushed = TRUE;
1162 }
1163 #endif /* EWP_BCM_TRACE */
1164
1165 #if defined (DHD_EVENT_LOG_FILTER)
1166 if (plog_hdr->tag == EVENT_LOG_TAG_STATS) {
1167 dhd_event_log_filter_event_handler(dhdp, plog_hdr, plog_hdr->log_ptr);
1168 }
1169 #endif /* DHD_EVENT_LOG_FILTER */
1170 if (!msg_processed) {
1171 dhd_dbg_verboselog_handler(dhdp, plog_hdr, raw_event_ptr,
1172 logset, block, (uint32 *)data);
1173 }
1174 dll_delete(cur);
1175 MFREE(dhdp->osh, log_item, sizeof(*log_item));
1176
1177 }
1178 BCM_REFERENCE(log_hdr);
1179 exit:
1180 while (dll_inited && (!dll_empty(&list_head))) {
1181 cur = dll_head_p(&list_head);
1182
1183 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1184 log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
1185 GCC_DIAGNOSTIC_POP();
1186
1187 dll_delete(cur);
1188 MFREE(dhdp->osh, log_item, sizeof(*log_item));
1189 }
1190
1191 VMFREE(dhdp->osh, logbuf, ring_data_len);
1192 }
1193 #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)1194 static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp,
1195 prcd_event_log_hdr_t *plog_hdr, void *raw_event_ptr, uint32 logset, uint16 block,
1196 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)1197 INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp,
1198 void *event_data, void *raw_event_ptr, uint datalen,
1199 bool msgtrace_hdr_present, uint32 msgtrace_seqnum) {};
1200 #endif /* SHOW_LOGTRACE */
1201 void
dhd_dbg_trace_evnt_handler(dhd_pub_t * dhdp,void * event_data,void * raw_event_ptr,uint datalen)1202 dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
1203 void *raw_event_ptr, uint datalen)
1204 {
1205 msgtrace_hdr_t *hdr;
1206
1207 hdr = (msgtrace_hdr_t *)event_data;
1208
1209 if (hdr->version != MSGTRACE_VERSION) {
1210 DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n",
1211 __FUNCTION__, MSGTRACE_VERSION, hdr->version));
1212 return;
1213 }
1214
1215 if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG)
1216 dhd_dbg_msgtrace_msg_parser(event_data);
1217 else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG)
1218 dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen, TRUE, 0);
1219 }
1220
1221 #ifdef BTLOG
1222 void
dhd_dbg_bt_log_handler(dhd_pub_t * dhdp,void * data,uint datalen)1223 dhd_dbg_bt_log_handler(dhd_pub_t *dhdp, void *data, uint datalen)
1224 {
1225 dhd_dbg_ring_entry_t msg_hdr;
1226 int ret;
1227
1228 /* push to ring */
1229 memset(&msg_hdr, 0, sizeof(msg_hdr));
1230 msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
1231 msg_hdr.len = datalen;
1232 ret = dhd_dbg_push_to_ring(dhdp, BT_LOG_RING_ID, &msg_hdr, data);
1233 if (ret != BCME_OK) {
1234 DHD_ERROR(("%s ring push failed %d\n", __FUNCTION__, ret));
1235 }
1236 }
1237 #endif /* BTLOG */
1238
1239 /*
1240 * dhd_dbg_set_event_log_tag : modify the state of an event log tag
1241 */
1242 void
dhd_dbg_set_event_log_tag(dhd_pub_t * dhdp,uint16 tag,uint8 set)1243 dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set)
1244 {
1245 wl_el_tag_params_t pars;
1246 char *cmd = "event_log_tag_control";
1247 char iovbuf[WLC_IOCTL_SMLEN] = { 0 };
1248 int ret;
1249
1250 memset(&pars, 0, sizeof(pars));
1251 pars.tag = tag;
1252 pars.set = set;
1253 pars.flags = EVENT_LOG_TAG_FLAG_LOG;
1254
1255 if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) {
1256 DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__));
1257 return;
1258 }
1259
1260 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1261 if (ret) {
1262 // DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret));
1263 }
1264 }
1265
1266 int
dhd_dbg_set_configuration(dhd_pub_t * dhdp,int ring_id,int log_level,int flags,uint32 threshold)1267 dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags, uint32 threshold)
1268 {
1269 dhd_dbg_ring_t *ring;
1270 uint8 set = 1;
1271 int i, array_len = 0;
1272 struct log_level_table *log_level_tbl = NULL;
1273 if (!dhdp || !dhdp->dbg)
1274 return BCME_BADADDR;
1275
1276 if (!VALID_RING(ring_id)) {
1277 DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
1278 return BCME_RANGE;
1279 }
1280
1281 ring = &dhdp->dbg->dbg_rings[ring_id];
1282 dhd_dbg_ring_config(ring, log_level, threshold);
1283
1284 if (log_level > 0)
1285 set = TRUE;
1286
1287 if (ring->id == FW_VERBOSE_RING_ID) {
1288 log_level_tbl = fw_verbose_level_map;
1289 array_len = ARRAYSIZE(fw_verbose_level_map);
1290 }
1291
1292 for (i = 0; i < array_len; i++) {
1293 if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) {
1294 /* clear the reference per ring */
1295 ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id);
1296 } else {
1297 /* set the reference per ring */
1298 ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id);
1299 }
1300 set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0;
1301 DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__,
1302 log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name));
1303 dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set);
1304 }
1305 return BCME_OK;
1306 }
1307
1308 int
__dhd_dbg_get_ring_status(dhd_dbg_ring_t * ring,dhd_dbg_ring_status_t * get_ring_status)1309 __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring, dhd_dbg_ring_status_t *get_ring_status)
1310 {
1311 dhd_dbg_ring_status_t ring_status;
1312 int ret = BCME_OK;
1313
1314 if (ring == NULL) {
1315 return BCME_BADADDR;
1316 }
1317
1318 bzero(&ring_status, sizeof(dhd_dbg_ring_status_t));
1319 RING_STAT_TO_STATUS(ring, ring_status);
1320 *get_ring_status = ring_status;
1321
1322 return ret;
1323 }
1324
1325 /*
1326 * dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer
1327 * Return: An error code or 0 on success.
1328 */
1329
1330 int
dhd_dbg_get_ring_status(dhd_pub_t * dhdp,int ring_id,dhd_dbg_ring_status_t * dbg_ring_status)1331 dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status)
1332 {
1333 int ret = BCME_OK;
1334 int id = 0;
1335 dhd_dbg_t *dbg;
1336 dhd_dbg_ring_t *dbg_ring;
1337 if (!dhdp || !dhdp->dbg)
1338 return BCME_BADADDR;
1339 dbg = dhdp->dbg;
1340
1341 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
1342 dbg_ring = &dbg->dbg_rings[id];
1343 if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) {
1344 __dhd_dbg_get_ring_status(dbg_ring, dbg_ring_status);
1345 break;
1346 }
1347 }
1348 if (!VALID_RING(id)) {
1349 DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id));
1350 ret = BCME_NOTFOUND;
1351 }
1352 return ret;
1353 }
1354
1355 #ifdef SHOW_LOGTRACE
1356 void
dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t * ring,trace_buf_info_t * trace_buf_info)1357 dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t *ring, trace_buf_info_t *trace_buf_info)
1358 {
1359 dhd_dbg_ring_status_t ring_status;
1360 uint32 rlen = 0;
1361
1362 rlen = dhd_dbg_ring_pull_single(ring, trace_buf_info->buf, TRACE_LOG_BUF_MAX_SIZE, TRUE);
1363
1364 trace_buf_info->size = rlen;
1365 trace_buf_info->availability = NEXT_BUF_NOT_AVAIL;
1366 if (rlen == 0) {
1367 trace_buf_info->availability = BUF_NOT_AVAILABLE;
1368 return;
1369 }
1370
1371 __dhd_dbg_get_ring_status(ring, &ring_status);
1372
1373 if (ring_status.written_bytes != ring_status.read_bytes) {
1374 trace_buf_info->availability = NEXT_BUF_AVAIL;
1375 }
1376 }
1377 #endif /* SHOW_LOGTRACE */
1378
1379 /*
1380 * dhd_dbg_find_ring_id : return ring_id based on ring_name
1381 * Return: An invalid ring id for failure or valid ring id on success.
1382 */
1383
1384 int
dhd_dbg_find_ring_id(dhd_pub_t * dhdp,char * ring_name)1385 dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name)
1386 {
1387 int id;
1388 dhd_dbg_t *dbg;
1389 dhd_dbg_ring_t *ring;
1390
1391 if (!dhdp || !dhdp->dbg)
1392 return BCME_BADADDR;
1393
1394 dbg = dhdp->dbg;
1395 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
1396 ring = &dbg->dbg_rings[id];
1397 if (!strncmp((char *)ring->name, ring_name, sizeof(ring->name) - 1))
1398 break;
1399 }
1400 return id;
1401 }
1402
1403 /*
1404 * dhd_dbg_get_priv : get the private data of dhd dbugability module
1405 * Return : An NULL on failure or valid data address
1406 */
1407 void *
dhd_dbg_get_priv(dhd_pub_t * dhdp)1408 dhd_dbg_get_priv(dhd_pub_t *dhdp)
1409 {
1410 if (!dhdp || !dhdp->dbg)
1411 return NULL;
1412 return dhdp->dbg->private;
1413 }
1414
1415 /*
1416 * dhd_dbg_start : start and stop All of Ring buffers
1417 * Return: An error code or 0 on success.
1418 */
1419 int
dhd_dbg_start(dhd_pub_t * dhdp,bool start)1420 dhd_dbg_start(dhd_pub_t *dhdp, bool start)
1421 {
1422 int ret = BCME_OK;
1423 int ring_id;
1424 dhd_dbg_t *dbg;
1425 dhd_dbg_ring_t *dbg_ring;
1426 if (!dhdp)
1427 return BCME_BADARG;
1428 dbg = dhdp->dbg;
1429
1430 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
1431 dbg_ring = &dbg->dbg_rings[ring_id];
1432 if (!start) {
1433 if (VALID_RING(dbg_ring->id)) {
1434 dhd_dbg_ring_start(dbg_ring);
1435 }
1436 }
1437 }
1438 return ret;
1439 }
1440
1441 /*
1442 * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer
1443 *
1444 * Return: An error code or 0 on success.
1445 */
1446
1447 int
dhd_dbg_send_urgent_evt(dhd_pub_t * dhdp,const void * data,const uint32 len)1448 dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len)
1449 {
1450 dhd_dbg_t *dbg;
1451 int ret = BCME_OK;
1452 if (!dhdp || !dhdp->dbg)
1453 return BCME_BADADDR;
1454
1455 dbg = dhdp->dbg;
1456 if (dbg->urgent_notifier) {
1457 dbg->urgent_notifier(dhdp, data, len);
1458 }
1459 return ret;
1460 }
1461
1462 #if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING)
1463 uint32
__dhd_dbg_pkt_hash(uintptr_t pkt,uint32 pktid)1464 __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid)
1465 {
1466 uint32 __pkt;
1467 uint32 __pktid;
1468
1469 __pkt = ((int)pkt) >= 0 ? (2 * pkt) : (-2 * pkt - 1);
1470 __pktid = ((int)pktid) >= 0 ? (2 * pktid) : (-2 * pktid - 1);
1471
1472 return (__pkt >= __pktid ? (__pkt * __pkt + __pkt + __pktid) :
1473 (__pkt + __pktid * __pktid));
1474 }
1475
1476 #define __TIMESPEC_TO_US(ts) \
1477 (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC))
1478
1479 uint32
__dhd_dbg_driver_ts_usec(void)1480 __dhd_dbg_driver_ts_usec(void)
1481 {
1482 struct osl_timespec ts;
1483
1484 osl_get_monotonic_boottime(&ts);
1485 return ((uint32)(__TIMESPEC_TO_US(ts)));
1486 }
1487
1488 wifi_tx_packet_fate
__dhd_dbg_map_tx_status_to_pkt_fate(uint16 status)1489 __dhd_dbg_map_tx_status_to_pkt_fate(uint16 status)
1490 {
1491 wifi_tx_packet_fate pkt_fate;
1492
1493 switch (status) {
1494 case WLFC_CTL_PKTFLAG_DISCARD:
1495 pkt_fate = TX_PKT_FATE_ACKED;
1496 break;
1497 case WLFC_CTL_PKTFLAG_D11SUPPRESS:
1498 /* intensional fall through */
1499 case WLFC_CTL_PKTFLAG_WLSUPPRESS:
1500 pkt_fate = TX_PKT_FATE_FW_QUEUED;
1501 break;
1502 case WLFC_CTL_PKTFLAG_TOSSED_BYWLC:
1503 pkt_fate = TX_PKT_FATE_FW_DROP_INVALID;
1504 break;
1505 case WLFC_CTL_PKTFLAG_DISCARD_NOACK:
1506 pkt_fate = TX_PKT_FATE_SENT;
1507 break;
1508 case WLFC_CTL_PKTFLAG_EXPIRED:
1509 pkt_fate = TX_PKT_FATE_FW_DROP_EXPTIME;
1510 break;
1511 #ifndef OEM_ANDROID
1512 case WLFC_CTL_PKTFLAG_MKTFREE:
1513 pkt_fate = TX_PKT_FATE_FW_PKT_FREE;
1514 break;
1515 #endif /* !OEM_ANDROID */
1516 default:
1517 pkt_fate = TX_PKT_FATE_FW_DROP_OTHER;
1518 break;
1519 }
1520
1521 return pkt_fate;
1522 }
1523 #endif /* DBG_PKT_MON || DHD_PKT_LOGGING */
1524
1525 #ifdef DBG_PKT_MON
1526 static int
__dhd_dbg_free_tx_pkts(dhd_pub_t * dhdp,dhd_dbg_tx_info_t * tx_pkts,uint16 pkt_count)1527 __dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts,
1528 uint16 pkt_count)
1529 {
1530 uint16 count;
1531
1532 count = 0;
1533 while ((count < pkt_count) && tx_pkts) {
1534 if (tx_pkts->info.pkt) {
1535 PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE);
1536 }
1537 tx_pkts++;
1538 count++;
1539 }
1540
1541 return BCME_OK;
1542 }
1543
1544 static int
__dhd_dbg_free_rx_pkts(dhd_pub_t * dhdp,dhd_dbg_rx_info_t * rx_pkts,uint16 pkt_count)1545 __dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts,
1546 uint16 pkt_count)
1547 {
1548 uint16 count;
1549
1550 count = 0;
1551 while ((count < pkt_count) && rx_pkts) {
1552 if (rx_pkts->info.pkt) {
1553 PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE);
1554 }
1555 rx_pkts++;
1556 count++;
1557 }
1558
1559 return BCME_OK;
1560 }
1561
1562 void
__dhd_dbg_dump_pkt_info(dhd_pub_t * dhdp,dhd_dbg_pkt_info_t * info)1563 __dhd_dbg_dump_pkt_info(dhd_pub_t *dhdp, dhd_dbg_pkt_info_t *info)
1564 {
1565 if (DHD_PKT_MON_DUMP_ON()) {
1566 DHD_PKT_MON(("payload type = %d\n", info->payload_type));
1567 DHD_PKT_MON(("driver ts = %u\n", info->driver_ts));
1568 DHD_PKT_MON(("firmware ts = %u\n", info->firmware_ts));
1569 DHD_PKT_MON(("packet hash = %u\n", info->pkt_hash));
1570 DHD_PKT_MON(("packet length = %zu\n", info->pkt_len));
1571 DHD_PKT_MON(("packet address = %p\n", info->pkt));
1572 DHD_PKT_MON(("packet data = \n"));
1573 if (DHD_PKT_MON_ON()) {
1574 prhex(NULL, PKTDATA(dhdp->osh, info->pkt), info->pkt_len);
1575 }
1576 }
1577 }
1578
1579 void
__dhd_dbg_dump_tx_pkt_info(dhd_pub_t * dhdp,dhd_dbg_tx_info_t * tx_pkt,uint16 count)1580 __dhd_dbg_dump_tx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkt,
1581 uint16 count)
1582 {
1583 if (DHD_PKT_MON_DUMP_ON()) {
1584 DHD_PKT_MON(("\nTX (count: %d)\n", ++count));
1585 DHD_PKT_MON(("packet fate = %d\n", tx_pkt->fate));
1586 __dhd_dbg_dump_pkt_info(dhdp, &tx_pkt->info);
1587 }
1588 }
1589
1590 void
__dhd_dbg_dump_rx_pkt_info(dhd_pub_t * dhdp,dhd_dbg_rx_info_t * rx_pkt,uint16 count)1591 __dhd_dbg_dump_rx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkt,
1592 uint16 count)
1593 {
1594 if (DHD_PKT_MON_DUMP_ON()) {
1595 DHD_PKT_MON(("\nRX (count: %d)\n", ++count));
1596 DHD_PKT_MON(("packet fate = %d\n", rx_pkt->fate));
1597 __dhd_dbg_dump_pkt_info(dhdp, &rx_pkt->info);
1598 }
1599 }
1600
1601 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)1602 dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp,
1603 dbg_mon_tx_pkts_t tx_pkt_mon,
1604 dbg_mon_tx_status_t tx_status_mon,
1605 dbg_mon_rx_pkts_t rx_pkt_mon)
1606 {
1607
1608 dhd_dbg_tx_report_t *tx_report = NULL;
1609 dhd_dbg_rx_report_t *rx_report = NULL;
1610 dhd_dbg_tx_info_t *tx_pkts = NULL;
1611 dhd_dbg_rx_info_t *rx_pkts = NULL;
1612 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1613 dhd_dbg_pkt_mon_state_t tx_status_state;
1614 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1615 uint32 alloc_len;
1616 int ret = BCME_OK;
1617 unsigned long flags;
1618
1619 if (!dhdp || !dhdp->dbg) {
1620 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1621 dhdp, (dhdp ? dhdp->dbg : NULL)));
1622 return -EINVAL;
1623 }
1624
1625 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1626 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1627 tx_status_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1628 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1629
1630 if (PKT_MON_ATTACHED(tx_pkt_state) || PKT_MON_ATTACHED(tx_status_state) ||
1631 PKT_MON_ATTACHED(rx_pkt_state)) {
1632 DHD_PKT_MON(("%s(): packet monitor is already attached, "
1633 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1634 __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
1635 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1636 /* return success as the intention was to initialize packet monitor */
1637 return BCME_OK;
1638 }
1639
1640 /* allocate and initialize tx packet monitoring */
1641 alloc_len = sizeof(*tx_report);
1642 tx_report = (dhd_dbg_tx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
1643 if (unlikely(!tx_report)) {
1644 DHD_ERROR(("%s(): could not allocate memory for - "
1645 "dhd_dbg_tx_report_t\n", __FUNCTION__));
1646 ret = -ENOMEM;
1647 goto fail;
1648 }
1649
1650 alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
1651 tx_pkts = (dhd_dbg_tx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
1652 if (unlikely(!tx_pkts)) {
1653 DHD_ERROR(("%s(): could not allocate memory for - "
1654 "dhd_dbg_tx_info_t\n", __FUNCTION__));
1655 ret = -ENOMEM;
1656 goto fail;
1657 }
1658 dhdp->dbg->pkt_mon.tx_report = tx_report;
1659 dhdp->dbg->pkt_mon.tx_report->tx_pkts = tx_pkts;
1660 dhdp->dbg->pkt_mon.tx_pkt_mon = tx_pkt_mon;
1661 dhdp->dbg->pkt_mon.tx_status_mon = tx_status_mon;
1662 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_ATTACHED;
1663 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_ATTACHED;
1664
1665 /* allocate and initialze rx packet monitoring */
1666 alloc_len = sizeof(*rx_report);
1667 rx_report = (dhd_dbg_rx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
1668 if (unlikely(!rx_report)) {
1669 DHD_ERROR(("%s(): could not allocate memory for - "
1670 "dhd_dbg_rx_report_t\n", __FUNCTION__));
1671 ret = -ENOMEM;
1672 goto fail;
1673 }
1674
1675 alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
1676 rx_pkts = (dhd_dbg_rx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
1677 if (unlikely(!rx_pkts)) {
1678 DHD_ERROR(("%s(): could not allocate memory for - "
1679 "dhd_dbg_rx_info_t\n", __FUNCTION__));
1680 ret = -ENOMEM;
1681 goto fail;
1682 }
1683 dhdp->dbg->pkt_mon.rx_report = rx_report;
1684 dhdp->dbg->pkt_mon.rx_report->rx_pkts = rx_pkts;
1685 dhdp->dbg->pkt_mon.rx_pkt_mon = rx_pkt_mon;
1686 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_ATTACHED;
1687
1688 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1689 DHD_PKT_MON(("%s(): packet monitor attach succeeded\n", __FUNCTION__));
1690 return ret;
1691
1692 fail:
1693 /* tx packet monitoring */
1694 if (tx_pkts) {
1695 alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
1696 MFREE(dhdp->osh, tx_pkts, alloc_len);
1697 }
1698 if (tx_report) {
1699 alloc_len = sizeof(*tx_report);
1700 MFREE(dhdp->osh, tx_report, alloc_len);
1701 }
1702 dhdp->dbg->pkt_mon.tx_report = NULL;
1703 dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
1704 dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
1705 dhdp->dbg->pkt_mon.tx_status_mon = NULL;
1706 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
1707 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
1708
1709 /* rx packet monitoring */
1710 if (rx_pkts) {
1711 alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
1712 MFREE(dhdp->osh, rx_pkts, alloc_len);
1713 }
1714 if (rx_report) {
1715 alloc_len = sizeof(*rx_report);
1716 MFREE(dhdp->osh, rx_report, alloc_len);
1717 }
1718 dhdp->dbg->pkt_mon.rx_report = NULL;
1719 dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
1720 dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
1721 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
1722
1723 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1724 DHD_ERROR(("%s(): packet monitor attach failed\n", __FUNCTION__));
1725 return ret;
1726 }
1727
1728 int
dhd_dbg_start_pkt_monitor(dhd_pub_t * dhdp)1729 dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
1730 {
1731 dhd_dbg_tx_report_t *tx_report;
1732 dhd_dbg_rx_report_t *rx_report;
1733 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1734 dhd_dbg_pkt_mon_state_t tx_status_state;
1735 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1736 unsigned long flags;
1737
1738 if (!dhdp || !dhdp->dbg) {
1739 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1740 dhdp, (dhdp ? dhdp->dbg : NULL)));
1741 return -EINVAL;
1742 }
1743
1744 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1745 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1746 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1747 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1748
1749 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
1750 PKT_MON_DETACHED(rx_pkt_state)) {
1751 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
1752 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1753 __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
1754 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1755 return -EINVAL;
1756 }
1757
1758 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTING;
1759 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTING;
1760 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTING;
1761
1762 tx_report = dhdp->dbg->pkt_mon.tx_report;
1763 rx_report = dhdp->dbg->pkt_mon.rx_report;
1764 if (!tx_report || !rx_report) {
1765 DHD_PKT_MON(("%s(): tx_report=%p, rx_report=%p\n",
1766 __FUNCTION__, tx_report, rx_report));
1767 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1768 return -EINVAL;
1769 }
1770
1771 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1772 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1773 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1774
1775 /* Safe to free packets as state pkt_state is STARTING */
1776 __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, tx_report->pkt_pos);
1777
1778 __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, rx_report->pkt_pos);
1779
1780 /* reset array postion */
1781 tx_report->pkt_pos = 0;
1782 tx_report->status_pos = 0;
1783 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTED;
1784 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTED;
1785
1786 rx_report->pkt_pos = 0;
1787 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTED;
1788 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1789
1790 DHD_PKT_MON(("%s(): packet monitor started\n", __FUNCTION__));
1791 return BCME_OK;
1792 }
1793
1794 int
dhd_dbg_monitor_tx_pkts(dhd_pub_t * dhdp,void * pkt,uint32 pktid)1795 dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid)
1796 {
1797 dhd_dbg_tx_report_t *tx_report;
1798 dhd_dbg_tx_info_t *tx_pkts;
1799 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1800 uint32 pkt_hash, driver_ts;
1801 uint16 pkt_pos;
1802 unsigned long flags;
1803
1804 if (!dhdp || !dhdp->dbg) {
1805 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1806 dhdp, (dhdp ? dhdp->dbg : NULL)));
1807 return -EINVAL;
1808 }
1809
1810 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1811 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1812 if (PKT_MON_STARTED(tx_pkt_state)) {
1813 tx_report = dhdp->dbg->pkt_mon.tx_report;
1814 pkt_pos = tx_report->pkt_pos;
1815
1816 if (!PKT_MON_PKT_FULL(pkt_pos)) {
1817 tx_pkts = tx_report->tx_pkts;
1818 pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
1819 driver_ts = __dhd_dbg_driver_ts_usec();
1820
1821 tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
1822 tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
1823 tx_pkts[pkt_pos].info.pkt_hash = pkt_hash;
1824 tx_pkts[pkt_pos].info.driver_ts = driver_ts;
1825 tx_pkts[pkt_pos].info.firmware_ts = 0U;
1826 tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
1827 tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED;
1828
1829 tx_report->pkt_pos++;
1830 } else {
1831 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
1832 DHD_PKT_MON(("%s(): tx pkt logging stopped, reached "
1833 "max limit\n", __FUNCTION__));
1834 }
1835 }
1836
1837 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1838 return BCME_OK;
1839 }
1840
1841 int
dhd_dbg_monitor_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)1842 dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
1843 uint16 status)
1844 {
1845 dhd_dbg_tx_report_t *tx_report;
1846 dhd_dbg_tx_info_t *tx_pkt;
1847 dhd_dbg_pkt_mon_state_t tx_status_state;
1848 wifi_tx_packet_fate pkt_fate;
1849 uint32 pkt_hash, temp_hash;
1850 uint16 pkt_pos, status_pos;
1851 int16 count;
1852 bool found = FALSE;
1853 unsigned long flags;
1854
1855 if (!dhdp || !dhdp->dbg) {
1856 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1857 dhdp, (dhdp ? dhdp->dbg : NULL)));
1858 return -EINVAL;
1859 }
1860
1861 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1862 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1863 if (PKT_MON_STARTED(tx_status_state)) {
1864 tx_report = dhdp->dbg->pkt_mon.tx_report;
1865 pkt_pos = tx_report->pkt_pos;
1866 status_pos = tx_report->status_pos;
1867
1868 if (!PKT_MON_STATUS_FULL(pkt_pos, status_pos)) {
1869 pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
1870 pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status);
1871
1872 /* best bet (in-order tx completion) */
1873 count = status_pos;
1874 tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + status_pos);
1875 while ((count < pkt_pos) && tx_pkt) {
1876 temp_hash = tx_pkt->info.pkt_hash;
1877 if (temp_hash == pkt_hash) {
1878 tx_pkt->fate = pkt_fate;
1879 tx_report->status_pos++;
1880 found = TRUE;
1881 break;
1882 }
1883 tx_pkt++;
1884 count++;
1885 }
1886
1887 /* search until beginning (handles out-of-order completion) */
1888 if (!found) {
1889 count = status_pos - 1;
1890 tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + count);
1891 while ((count >= 0) && tx_pkt) {
1892 temp_hash = tx_pkt->info.pkt_hash;
1893 if (temp_hash == pkt_hash) {
1894 tx_pkt->fate = pkt_fate;
1895 tx_report->status_pos++;
1896 found = TRUE;
1897 break;
1898 }
1899 tx_pkt--;
1900 count--;
1901 }
1902
1903 if (!found) {
1904 /* still couldn't match tx_status */
1905 DHD_INFO(("%s(): couldn't match tx_status, pkt_pos=%u, "
1906 "status_pos=%u, pkt_fate=%u\n", __FUNCTION__,
1907 pkt_pos, status_pos, pkt_fate));
1908 }
1909 }
1910 } else {
1911 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
1912 DHD_PKT_MON(("%s(): tx_status logging stopped, reached "
1913 "max limit\n", __FUNCTION__));
1914 }
1915 }
1916
1917 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1918 return BCME_OK;
1919 }
1920
1921 int
dhd_dbg_monitor_rx_pkts(dhd_pub_t * dhdp,void * pkt)1922 dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt)
1923 {
1924 dhd_dbg_rx_report_t *rx_report;
1925 dhd_dbg_rx_info_t *rx_pkts;
1926 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1927 uint32 driver_ts;
1928 uint16 pkt_pos;
1929 unsigned long flags;
1930
1931 if (!dhdp || !dhdp->dbg) {
1932 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1933 dhdp, (dhdp ? dhdp->dbg : NULL)));
1934 return -EINVAL;
1935 }
1936
1937 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1938 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1939 if (PKT_MON_STARTED(rx_pkt_state)) {
1940 rx_report = dhdp->dbg->pkt_mon.rx_report;
1941 pkt_pos = rx_report->pkt_pos;
1942
1943 if (!PKT_MON_PKT_FULL(pkt_pos)) {
1944 rx_pkts = rx_report->rx_pkts;
1945 driver_ts = __dhd_dbg_driver_ts_usec();
1946
1947 rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
1948 rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
1949 rx_pkts[pkt_pos].info.pkt_hash = 0U;
1950 rx_pkts[pkt_pos].info.driver_ts = driver_ts;
1951 rx_pkts[pkt_pos].info.firmware_ts = 0U;
1952 rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
1953 rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS;
1954
1955 rx_report->pkt_pos++;
1956 } else {
1957 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
1958 DHD_PKT_MON(("%s(): rx pkt logging stopped, reached "
1959 "max limit\n", __FUNCTION__));
1960 }
1961 }
1962
1963 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1964 return BCME_OK;
1965 }
1966
1967 int
dhd_dbg_stop_pkt_monitor(dhd_pub_t * dhdp)1968 dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp)
1969 {
1970 dhd_dbg_pkt_mon_state_t tx_pkt_state;
1971 dhd_dbg_pkt_mon_state_t tx_status_state;
1972 dhd_dbg_pkt_mon_state_t rx_pkt_state;
1973 unsigned long flags;
1974
1975 if (!dhdp || !dhdp->dbg) {
1976 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
1977 dhdp, (dhdp ? dhdp->dbg : NULL)));
1978 return -EINVAL;
1979 }
1980
1981 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
1982 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
1983 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
1984 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
1985
1986 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
1987 PKT_MON_DETACHED(rx_pkt_state)) {
1988 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
1989 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
1990 __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
1991 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1992 return -EINVAL;
1993 }
1994 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
1995 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
1996 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
1997 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
1998
1999 DHD_PKT_MON(("%s(): packet monitor stopped\n", __FUNCTION__));
2000 return BCME_OK;
2001 }
2002
2003 #define __COPY_TO_USER(to, from, n) \
2004 do { \
2005 int __ret; \
2006 __ret = copy_to_user((void __user *)(to), (void *)(from), \
2007 (unsigned long)(n)); \
2008 if (unlikely(__ret)) { \
2009 DHD_ERROR(("%s():%d: copy_to_user failed, ret=%d\n", \
2010 __FUNCTION__, __LINE__, __ret)); \
2011 return __ret; \
2012 } \
2013 } while (0);
2014
2015 int
dhd_dbg_monitor_get_tx_pkts(dhd_pub_t * dhdp,void __user * user_buf,uint16 req_count,uint16 * resp_count)2016 dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
2017 uint16 req_count, uint16 *resp_count)
2018 {
2019 dhd_dbg_tx_report_t *tx_report;
2020 dhd_dbg_tx_info_t *tx_pkt;
2021 wifi_tx_report_t *ptr;
2022 compat_wifi_tx_report_t *cptr;
2023 dhd_dbg_pkt_mon_state_t tx_pkt_state;
2024 dhd_dbg_pkt_mon_state_t tx_status_state;
2025 uint16 pkt_count, count;
2026 unsigned long flags;
2027
2028 BCM_REFERENCE(ptr);
2029 BCM_REFERENCE(cptr);
2030
2031 if (!dhdp || !dhdp->dbg) {
2032 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
2033 dhdp, (dhdp ? dhdp->dbg : NULL)));
2034 return -EINVAL;
2035 }
2036
2037 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
2038 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
2039 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
2040 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state)) {
2041 DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
2042 "tx_pkt_state=%d, tx_status_state=%d\n", __FUNCTION__,
2043 tx_pkt_state, tx_status_state));
2044 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2045 return -EINVAL;
2046 }
2047
2048 count = 0;
2049 tx_report = dhdp->dbg->pkt_mon.tx_report;
2050 tx_pkt = tx_report->tx_pkts;
2051 pkt_count = MIN(req_count, tx_report->status_pos);
2052
2053 #ifdef CONFIG_COMPAT
2054 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2055 if (in_compat_syscall())
2056 #else
2057 if (is_compat_task())
2058 #endif
2059 {
2060 cptr = (compat_wifi_tx_report_t *)user_buf;
2061 while ((count < pkt_count) && tx_pkt && cptr) {
2062 compat_wifi_tx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr);
2063 compat_dhd_dbg_pkt_info_t compat_tx_pkt;
2064 __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count);
2065 __COPY_TO_USER(&comp_ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate));
2066
2067 compat_tx_pkt.payload_type = tx_pkt->info.payload_type;
2068 compat_tx_pkt.pkt_len = tx_pkt->info.pkt_len;
2069 compat_tx_pkt.driver_ts = tx_pkt->info.driver_ts;
2070 compat_tx_pkt.firmware_ts = tx_pkt->info.firmware_ts;
2071 compat_tx_pkt.pkt_hash = tx_pkt->info.pkt_hash;
2072 __COPY_TO_USER(&comp_ptr->frame_inf.payload_type,
2073 &compat_tx_pkt.payload_type,
2074 OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash));
2075 __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii,
2076 PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len);
2077
2078 cptr++;
2079 tx_pkt++;
2080 count++;
2081 }
2082 } else
2083 #endif /* CONFIG_COMPAT */
2084 {
2085 ptr = (wifi_tx_report_t *)user_buf;
2086 while ((count < pkt_count) && tx_pkt && ptr) {
2087 __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count);
2088 __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate));
2089 __COPY_TO_USER(&ptr->frame_inf.payload_type,
2090 &tx_pkt->info.payload_type,
2091 OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
2092 __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
2093 PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len);
2094
2095 ptr++;
2096 tx_pkt++;
2097 count++;
2098 }
2099 }
2100 *resp_count = pkt_count;
2101
2102 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2103 if (!pkt_count) {
2104 DHD_ERROR(("%s(): no tx_status in tx completion messages, "
2105 "make sure that 'd11status' is enabled in firmware, "
2106 "status_pos=%u\n", __FUNCTION__, pkt_count));
2107 }
2108
2109 return BCME_OK;
2110 }
2111
2112 int
dhd_dbg_monitor_get_rx_pkts(dhd_pub_t * dhdp,void __user * user_buf,uint16 req_count,uint16 * resp_count)2113 dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
2114 uint16 req_count, uint16 *resp_count)
2115 {
2116 dhd_dbg_rx_report_t *rx_report;
2117 dhd_dbg_rx_info_t *rx_pkt;
2118 wifi_rx_report_t *ptr;
2119 compat_wifi_rx_report_t *cptr;
2120 dhd_dbg_pkt_mon_state_t rx_pkt_state;
2121 uint16 pkt_count, count;
2122 unsigned long flags;
2123
2124 BCM_REFERENCE(ptr);
2125 BCM_REFERENCE(cptr);
2126
2127 if (!dhdp || !dhdp->dbg) {
2128 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
2129 dhdp, (dhdp ? dhdp->dbg : NULL)));
2130 return -EINVAL;
2131 }
2132
2133 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
2134 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
2135 if (PKT_MON_DETACHED(rx_pkt_state)) {
2136 DHD_PKT_MON(("%s(): packet fetch is not allowed , "
2137 "rx_pkt_state=%d\n", __FUNCTION__, rx_pkt_state));
2138 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2139 return -EINVAL;
2140 }
2141
2142 count = 0;
2143 rx_report = dhdp->dbg->pkt_mon.rx_report;
2144 rx_pkt = rx_report->rx_pkts;
2145 pkt_count = MIN(req_count, rx_report->pkt_pos);
2146
2147 #ifdef CONFIG_COMPAT
2148 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2149 if (in_compat_syscall())
2150 #else
2151 if (is_compat_task())
2152 #endif
2153 {
2154 cptr = (compat_wifi_rx_report_t *)user_buf;
2155 while ((count < pkt_count) && rx_pkt && cptr) {
2156 compat_wifi_rx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr);
2157 compat_dhd_dbg_pkt_info_t compat_rx_pkt;
2158 __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count);
2159 __COPY_TO_USER(&comp_ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate));
2160
2161 compat_rx_pkt.payload_type = rx_pkt->info.payload_type;
2162 compat_rx_pkt.pkt_len = rx_pkt->info.pkt_len;
2163 compat_rx_pkt.driver_ts = rx_pkt->info.driver_ts;
2164 compat_rx_pkt.firmware_ts = rx_pkt->info.firmware_ts;
2165 compat_rx_pkt.pkt_hash = rx_pkt->info.pkt_hash;
2166 __COPY_TO_USER(&comp_ptr->frame_inf.payload_type,
2167 &compat_rx_pkt.payload_type,
2168 OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash));
2169 __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii,
2170 PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len);
2171
2172 cptr++;
2173 rx_pkt++;
2174 count++;
2175 }
2176 } else
2177 #endif /* CONFIG_COMPAT */
2178 {
2179 ptr = (wifi_rx_report_t *)user_buf;
2180 while ((count < pkt_count) && rx_pkt && ptr) {
2181 __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count);
2182
2183 __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate));
2184 __COPY_TO_USER(&ptr->frame_inf.payload_type,
2185 &rx_pkt->info.payload_type,
2186 OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
2187 __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
2188 PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len);
2189
2190 ptr++;
2191 rx_pkt++;
2192 count++;
2193 }
2194 }
2195
2196 *resp_count = pkt_count;
2197 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2198
2199 return BCME_OK;
2200 }
2201
2202 int
dhd_dbg_detach_pkt_monitor(dhd_pub_t * dhdp)2203 dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp)
2204 {
2205 dhd_dbg_tx_report_t *tx_report;
2206 dhd_dbg_rx_report_t *rx_report;
2207 dhd_dbg_pkt_mon_state_t tx_pkt_state;
2208 dhd_dbg_pkt_mon_state_t tx_status_state;
2209 dhd_dbg_pkt_mon_state_t rx_pkt_state;
2210 unsigned long flags;
2211
2212 if (!dhdp || !dhdp->dbg) {
2213 DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
2214 dhdp, (dhdp ? dhdp->dbg : NULL)));
2215 return -EINVAL;
2216 }
2217
2218 DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
2219 tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
2220 tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
2221 rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
2222
2223 if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
2224 PKT_MON_DETACHED(rx_pkt_state)) {
2225 DHD_PKT_MON(("%s(): packet monitor is already detached, "
2226 "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
2227 __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
2228 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2229 return -EINVAL;
2230 }
2231
2232 tx_report = dhdp->dbg->pkt_mon.tx_report;
2233 rx_report = dhdp->dbg->pkt_mon.rx_report;
2234
2235 /* free and de-initalize tx packet monitoring */
2236 dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
2237 dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
2238 if (tx_report) {
2239 if (tx_report->tx_pkts) {
2240 __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts,
2241 tx_report->pkt_pos);
2242 MFREE(dhdp->osh, tx_report->tx_pkts,
2243 (sizeof(*tx_report->tx_pkts) * MAX_FATE_LOG_LEN));
2244 dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
2245 }
2246 MFREE(dhdp->osh, tx_report, sizeof(*tx_report));
2247 dhdp->dbg->pkt_mon.tx_report = NULL;
2248 }
2249 dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
2250 dhdp->dbg->pkt_mon.tx_status_mon = NULL;
2251
2252 /* free and de-initalize rx packet monitoring */
2253 dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
2254 if (rx_report) {
2255 if (rx_report->rx_pkts) {
2256 __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts,
2257 rx_report->pkt_pos);
2258 MFREE(dhdp->osh, rx_report->rx_pkts,
2259 (sizeof(*rx_report->rx_pkts) * MAX_FATE_LOG_LEN));
2260 dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
2261 }
2262 MFREE(dhdp->osh, rx_report, sizeof(*rx_report));
2263 dhdp->dbg->pkt_mon.rx_report = NULL;
2264 }
2265 dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
2266
2267 DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
2268 DHD_PKT_MON(("%s(): packet monitor detach succeeded\n", __FUNCTION__));
2269 return BCME_OK;
2270 }
2271 #endif /* DBG_PKT_MON */
2272
2273 #if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING)
2274 /*
2275 * XXX: WAR: Because of the overloading by DMA marker field,
2276 * tx_status in TX completion message cannot be used. As a WAR,
2277 * send d11 tx_status through unused status field of PCIe
2278 * completion header.
2279 */
2280 bool
dhd_dbg_process_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)2281 dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
2282 uint16 status)
2283 {
2284 bool pkt_fate = TRUE;
2285 if (dhdp->d11_tx_status) {
2286 pkt_fate = (status == WLFC_CTL_PKTFLAG_DISCARD) ? TRUE : FALSE;
2287 DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status);
2288 }
2289 return pkt_fate;
2290 }
2291 #else /* DBG_PKT_MON || DHD_PKT_LOGGING */
2292 bool
dhd_dbg_process_tx_status(dhd_pub_t * dhdp,void * pkt,uint32 pktid,uint16 status)2293 dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt,
2294 uint32 pktid, uint16 status)
2295 {
2296 return TRUE;
2297 }
2298 #endif /* DBG_PKT_MON || DHD_PKT_LOGGING */
2299
2300 #define EL_LOG_STR_LEN 512
2301
2302 #define PRINT_CHN_PER_LINE 8
2303 #define PRINT_CHAN_LINE(cnt) \
2304 {\
2305 cnt ++; \
2306 if (cnt >= PRINT_CHN_PER_LINE) { \
2307 DHD_ERROR(("%s\n", b.origbuf)); \
2308 bcm_binit(&b, pr_buf, EL_LOG_STR_LEN); \
2309 bcm_bprintf(&b, "%s: ", prefix); \
2310 cnt = 0; \
2311 } \
2312 }
2313
print_roam_chan_list(char * prefix,uint chan_num,uint16 band_2g,uint16 uni2a,uint8 uni3,uint8 * uni2c)2314 void print_roam_chan_list(char *prefix, uint chan_num, uint16 band_2g,
2315 uint16 uni2a, uint8 uni3, uint8 *uni2c)
2316 {
2317 struct bcmstrbuf b;
2318 char pr_buf[EL_LOG_STR_LEN] = { 0 };
2319 int cnt = 0;
2320 int idx, idx2;
2321
2322 bcm_binit(&b, pr_buf, EL_LOG_STR_LEN);
2323 bcm_bprintf(&b, "%s: count(%d)", prefix, chan_num);
2324 /* 2G channnels */
2325 for (idx = 0; idx < NBITS(uint16); idx++) {
2326 if (BCM_BIT(idx) & band_2g) {
2327 bcm_bprintf(&b, " %d", idx);
2328 PRINT_CHAN_LINE(cnt);
2329
2330 }
2331 }
2332
2333 /* 5G UNII BAND 1, UNII BAND 2A */
2334 for (idx = 0; idx < NBITS(uint16); idx++) {
2335 if (BCM_BIT(idx) & uni2a) {
2336 bcm_bprintf(&b, " %u", ROAM_CHN_UNI_2A + idx * ROAM_CHN_SPACE);
2337 PRINT_CHAN_LINE(cnt);
2338 }
2339 }
2340
2341 /* 5G UNII BAND 2C */
2342 for (idx2 = 0; idx2 < 3; idx2++) {
2343 for (idx = 0; idx < NBITS(uint8); idx++) {
2344 if (BCM_BIT(idx) & uni2c[idx2]) {
2345 bcm_bprintf(&b, " %u", ROAM_CHN_UNI_2C +
2346 idx2 * ROAM_CHN_SPACE * NBITS(uint8) +
2347 idx * ROAM_CHN_SPACE);
2348 PRINT_CHAN_LINE(cnt);
2349 }
2350 }
2351 }
2352
2353 /* 5G UNII BAND 3 */
2354 for (idx = 0; idx < NBITS(uint8); idx++) {
2355 if (BCM_BIT(idx) & uni3) {
2356 bcm_bprintf(&b, " %u", ROAM_CHN_UNI_3 + idx * ROAM_CHN_SPACE);
2357 PRINT_CHAN_LINE(cnt);
2358 }
2359 }
2360
2361 if (cnt != 0) {
2362 DHD_ERROR(("%s\n", b.origbuf));
2363 }
2364 }
2365
2366 void pr_roam_scan_start_v1(prcd_event_log_hdr_t *plog_hdr);
2367 void pr_roam_scan_cmpl_v1(prcd_event_log_hdr_t *plog_hdr);
2368 void pr_roam_cmpl_v1(prcd_event_log_hdr_t *plog_hdr);
2369 void pr_roam_nbr_req_v1(prcd_event_log_hdr_t *plog_hdr);
2370 void pr_roam_nbr_rep_v1(prcd_event_log_hdr_t *plog_hdr);
2371 void pr_roam_bcn_req_v1(prcd_event_log_hdr_t *plog_hdr);
2372 void pr_roam_bcn_rep_v1(prcd_event_log_hdr_t *plog_hdr);
2373
2374 void pr_roam_scan_start_v2(prcd_event_log_hdr_t *plog_hdr);
2375 void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr);
2376 void pr_roam_nbr_rep_v2(prcd_event_log_hdr_t *plog_hdr);
2377 void pr_roam_bcn_rep_v2(prcd_event_log_hdr_t *plog_hdr);
2378 void pr_roam_btm_rep_v2(prcd_event_log_hdr_t *plog_hdr);
2379
2380 void pr_roam_bcn_req_v3(prcd_event_log_hdr_t *plog_hdr);
2381 void pr_roam_bcn_rep_v3(prcd_event_log_hdr_t *plog_hdr);
2382 void pr_roam_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr);
2383
2384 static const pr_roam_tbl_t roam_log_print_tbl[] =
2385 {
2386 {ROAM_LOG_VER_1, ROAM_LOG_SCANSTART, pr_roam_scan_start_v1},
2387 {ROAM_LOG_VER_1, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v1},
2388 {ROAM_LOG_VER_1, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1},
2389 {ROAM_LOG_VER_1, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1},
2390 {ROAM_LOG_VER_1, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v1},
2391 {ROAM_LOG_VER_1, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v1},
2392 {ROAM_LOG_VER_1, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v1},
2393
2394 {ROAM_LOG_VER_2, ROAM_LOG_SCANSTART, pr_roam_scan_start_v2},
2395 {ROAM_LOG_VER_2, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v2},
2396 {ROAM_LOG_VER_2, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1},
2397 {ROAM_LOG_VER_2, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1},
2398 {ROAM_LOG_VER_2, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v2},
2399 {ROAM_LOG_VER_2, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v1},
2400 {ROAM_LOG_VER_2, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v2},
2401 {ROAM_LOG_VER_2, ROAM_LOG_BTM_REP, pr_roam_btm_rep_v2},
2402
2403 {ROAM_LOG_VER_3, ROAM_LOG_SCANSTART, pr_roam_scan_start_v2},
2404 {ROAM_LOG_VER_3, ROAM_LOG_SCAN_CMPLT, pr_roam_scan_cmpl_v2},
2405 {ROAM_LOG_VER_3, ROAM_LOG_ROAM_CMPLT, pr_roam_cmpl_v1},
2406 {ROAM_LOG_VER_3, ROAM_LOG_NBR_REQ, pr_roam_nbr_req_v1},
2407 {ROAM_LOG_VER_3, ROAM_LOG_NBR_REP, pr_roam_nbr_rep_v2},
2408 {ROAM_LOG_VER_3, ROAM_LOG_BCN_REQ, pr_roam_bcn_req_v3},
2409 {ROAM_LOG_VER_3, ROAM_LOG_BCN_REP, pr_roam_bcn_rep_v3},
2410 {ROAM_LOG_VER_3, ROAM_LOG_BTM_REP, pr_roam_btm_rep_v3},
2411
2412 {0, PRSV_PERIODIC_ID_MAX, NULL}
2413
2414 };
2415
pr_roam_scan_start_v1(prcd_event_log_hdr_t * plog_hdr)2416 void pr_roam_scan_start_v1(prcd_event_log_hdr_t *plog_hdr)
2417 {
2418 roam_log_trig_v1_t *log = (roam_log_trig_v1_t *)plog_hdr->log_ptr;
2419
2420 DHD_ERROR_ROAM(("ROAM_LOG_SCANSTART time: %d,"
2421 " version:%d reason: %d rssi:%d cu:%d result:%d\n",
2422 plog_hdr->armcycle, log->hdr.version, log->reason,
2423 log->rssi, log->current_cu, log->result));
2424 if (log->reason == WLC_E_REASON_DEAUTH ||
2425 log->reason == WLC_E_REASON_DISASSOC) {
2426 DHD_ERROR_ROAM((" ROAM_LOG_PRT_ROAM: RCVD reason:%d\n",
2427 log->prt_roam.rcvd_reason));
2428 } else if (log->reason == WLC_E_REASON_BSSTRANS_REQ) {
2429 DHD_ERROR_ROAM((" ROAM_LOG_BSS_REQ: mode:%d candidate:%d token:%d "
2430 "duration disassoc:%d valid:%d term:%d\n",
2431 log->bss_trans.req_mode, log->bss_trans.nbrlist_size,
2432 log->bss_trans.token, log->bss_trans.disassoc_dur,
2433 log->bss_trans.validity_dur, log->bss_trans.bss_term_dur));
2434 }
2435 }
2436
pr_roam_scan_cmpl_v1(prcd_event_log_hdr_t * plog_hdr)2437 void pr_roam_scan_cmpl_v1(prcd_event_log_hdr_t *plog_hdr)
2438 {
2439 roam_log_scan_cmplt_v1_t *log = (roam_log_scan_cmplt_v1_t *)plog_hdr->log_ptr;
2440 char chanspec_buf[CHANSPEC_STR_LEN];
2441 int i;
2442
2443 DHD_ERROR_ROAM(("ROAM_LOG_SCAN_CMPL: time:%d version:%d"
2444 "is_full:%d scan_count:%d score_delta:%d",
2445 plog_hdr->armcycle, log->hdr.version, log->full_scan,
2446 log->scan_count, log->score_delta));
2447 DHD_ERROR_ROAM((" ROAM_LOG_CUR_AP: " MACDBG "rssi:%d score:%d channel:%s\n",
2448 MAC2STRDBG((uint8 *)&log->cur_info.addr),
2449 log->cur_info.rssi,
2450 log->cur_info.score,
2451 wf_chspec_ntoa_ex(log->cur_info.chanspec, chanspec_buf)));
2452 for (i = 0; i < log->scan_list_size; i++) {
2453 DHD_ERROR_ROAM((" ROAM_LOG_CANDIDATE %d: " MACDBG
2454 "rssi:%d score:%d channel:%s TPUT:%dkbps\n",
2455 i, MAC2STRDBG((uint8 *)&log->scan_list[i].addr),
2456 log->scan_list[i].rssi, log->scan_list[i].score,
2457 wf_chspec_ntoa_ex(log->scan_list[i].chanspec,
2458 chanspec_buf),
2459 log->scan_list[i].estm_tput != ROAM_LOG_INVALID_TPUT?
2460 log->scan_list[i].estm_tput:0));
2461 }
2462 }
2463
pr_roam_cmpl_v1(prcd_event_log_hdr_t * plog_hdr)2464 void pr_roam_cmpl_v1(prcd_event_log_hdr_t *plog_hdr)
2465 {
2466 roam_log_cmplt_v1_t *log = (roam_log_cmplt_v1_t *)plog_hdr->log_ptr;
2467 char chanspec_buf[CHANSPEC_STR_LEN];
2468
2469 DHD_ERROR_ROAM(("ROAM_LOG_ROAM_CMPL: time: %d, version:%d"
2470 "status: %d reason: %d channel:%s retry:%d " MACDBG "\n",
2471 plog_hdr->armcycle, log->hdr.version, log->status, log->reason,
2472 wf_chspec_ntoa_ex(log->chanspec, chanspec_buf),
2473 log->retry, MAC2STRDBG((uint8 *)&log->addr)));
2474 }
2475
pr_roam_nbr_req_v1(prcd_event_log_hdr_t * plog_hdr)2476 void pr_roam_nbr_req_v1(prcd_event_log_hdr_t *plog_hdr)
2477 {
2478 roam_log_nbrreq_v1_t *log = (roam_log_nbrreq_v1_t *)plog_hdr->log_ptr;
2479
2480 DHD_ERROR_ROAM(("ROAM_LOG_NBR_REQ: time: %d, version:%d token:%d\n",
2481 plog_hdr->armcycle, log->hdr.version, log->token));
2482 }
2483
pr_roam_nbr_rep_v1(prcd_event_log_hdr_t * plog_hdr)2484 void pr_roam_nbr_rep_v1(prcd_event_log_hdr_t *plog_hdr)
2485 {
2486 roam_log_nbrrep_v1_t *log = (roam_log_nbrrep_v1_t *)plog_hdr->log_ptr;
2487
2488 DHD_ERROR_ROAM(("ROAM_LOG_NBR_REP: time:%d, veresion:%d chan_num:%d\n",
2489 plog_hdr->armcycle, log->hdr.version, log->channel_num));
2490 }
2491
pr_roam_bcn_req_v1(prcd_event_log_hdr_t * plog_hdr)2492 void pr_roam_bcn_req_v1(prcd_event_log_hdr_t *plog_hdr)
2493 {
2494 roam_log_bcnrpt_req_v1_t *log = (roam_log_bcnrpt_req_v1_t *)plog_hdr->log_ptr;
2495
2496 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REQ: time:%d, version:%d ret:%d"
2497 "class:%d num_chan:%d ",
2498 plog_hdr->armcycle, log->hdr.version,
2499 log->result, log->reg, log->channel));
2500 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REQ: mode:%d is_wild:%d duration:%d"
2501 "ssid_len:%d\n", log->mode, log->bssid_wild,
2502 log->duration, log->ssid_len));
2503 }
2504
pr_roam_bcn_rep_v1(prcd_event_log_hdr_t * plog_hdr)2505 void pr_roam_bcn_rep_v1(prcd_event_log_hdr_t *plog_hdr)
2506 {
2507 roam_log_bcnrpt_rep_v1_t *log = (roam_log_bcnrpt_rep_v1_t *)plog_hdr->log_ptr;
2508 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REP: time:%d, verseion:%d count:%d\n",
2509 plog_hdr->armcycle, log->hdr.version,
2510 log->count));
2511 }
2512
pr_roam_scan_start_v2(prcd_event_log_hdr_t * plog_hdr)2513 void pr_roam_scan_start_v2(prcd_event_log_hdr_t *plog_hdr)
2514 {
2515 roam_log_trig_v2_t *log = (roam_log_trig_v2_t *)plog_hdr->log_ptr;
2516 DHD_ERROR_ROAM(("ROAM_LOG_SCANSTART time: %d,"
2517 " version:%d reason: %d rssi:%d cu:%d result:%d full_scan:%d\n",
2518 plog_hdr->armcycle, log->hdr.version, log->reason,
2519 log->rssi, log->current_cu, log->result,
2520 log->result?(-1):log->full_scan));
2521 if (log->reason == WLC_E_REASON_DEAUTH ||
2522 log->reason == WLC_E_REASON_DISASSOC) {
2523 DHD_ERROR_ROAM((" ROAM_LOG_PRT_ROAM: RCVD reason:%d\n",
2524 log->prt_roam.rcvd_reason));
2525 } else if (log->reason == WLC_E_REASON_BSSTRANS_REQ) {
2526 DHD_ERROR_ROAM((" ROAM_LOG_BSS_REQ: mode:%d candidate:%d token:%d "
2527 "duration disassoc:%d valid:%d term:%d\n",
2528 log->bss_trans.req_mode, log->bss_trans.nbrlist_size,
2529 log->bss_trans.token, log->bss_trans.disassoc_dur,
2530 log->bss_trans.validity_dur, log->bss_trans.bss_term_dur));
2531 } else if (log->reason == WLC_E_REASON_LOW_RSSI) {
2532 DHD_ERROR_ROAM((" ROAM_LOG_LOW_RSSI: threshold:%d\n",
2533 log->low_rssi.rssi_threshold));
2534 }
2535 }
2536
pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t * plog_hdr)2537 void pr_roam_scan_cmpl_v2(prcd_event_log_hdr_t *plog_hdr)
2538 {
2539 int i;
2540 roam_log_scan_cmplt_v2_t *log = (roam_log_scan_cmplt_v2_t *)plog_hdr->log_ptr;
2541 char chanspec_buf[CHANSPEC_STR_LEN];
2542
2543 DHD_ERROR_ROAM(("ROAM_LOG_SCAN_CMPL: time:%d version:%d"
2544 "scan_count:%d score_delta:%d",
2545 plog_hdr->armcycle, log->hdr.version,
2546 log->scan_count, log->score_delta));
2547 DHD_ERROR_ROAM((" ROAM_LOG_CUR_AP: " MACDBG "rssi:%d score:%d channel:%s\n",
2548 MAC2STRDBG((uint8 *)&log->cur_info.addr),
2549 log->cur_info.rssi,
2550 log->cur_info.score,
2551 wf_chspec_ntoa_ex(log->cur_info.chanspec, chanspec_buf)));
2552 for (i = 0; i < log->scan_list_size; i++) {
2553 DHD_ERROR_ROAM((" ROAM_LOG_CANDIDATE %d: " MACDBG
2554 "rssi:%d score:%d cu :%d channel:%s TPUT:%dkbps\n",
2555 i, MAC2STRDBG((uint8 *)&log->scan_list[i].addr),
2556 log->scan_list[i].rssi, log->scan_list[i].score,
2557 log->scan_list[i].cu * 100 / WL_MAX_CHANNEL_USAGE,
2558 wf_chspec_ntoa_ex(log->scan_list[i].chanspec,
2559 chanspec_buf),
2560 log->scan_list[i].estm_tput != ROAM_LOG_INVALID_TPUT?
2561 log->scan_list[i].estm_tput:0));
2562 }
2563 if (log->chan_num != 0) {
2564 print_roam_chan_list("ROAM_LOG_SCAN_CHANLIST", log->chan_num,
2565 log->band2g_chan_list, log->uni2a_chan_list,
2566 log->uni3_chan_list, log->uni2c_chan_list);
2567 }
2568
2569 }
2570
pr_roam_nbr_rep_v2(prcd_event_log_hdr_t * plog_hdr)2571 void pr_roam_nbr_rep_v2(prcd_event_log_hdr_t *plog_hdr)
2572 {
2573 roam_log_nbrrep_v2_t *log = (roam_log_nbrrep_v2_t *)plog_hdr->log_ptr;
2574 DHD_ERROR_ROAM(("ROAM_LOG_NBR_REP: time:%d, veresion:%d chan_num:%d\n",
2575 plog_hdr->armcycle, log->hdr.version, log->channel_num));
2576 if (log->channel_num != 0) {
2577 print_roam_chan_list("ROAM_LOG_NBR_REP_CHANLIST", log->channel_num,
2578 log->band2g_chan_list, log->uni2a_chan_list,
2579 log->uni3_chan_list, log->uni2c_chan_list);
2580 }
2581 }
2582
pr_roam_bcn_rep_v2(prcd_event_log_hdr_t * plog_hdr)2583 void pr_roam_bcn_rep_v2(prcd_event_log_hdr_t *plog_hdr)
2584 {
2585 roam_log_bcnrpt_rep_v2_t *log = (roam_log_bcnrpt_rep_v2_t *)plog_hdr->log_ptr;
2586
2587 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REP: time:%d, verseion:%d count:%d mode:%d\n",
2588 plog_hdr->armcycle, log->hdr.version,
2589 log->count, log->reason));
2590 }
2591
pr_roam_btm_rep_v2(prcd_event_log_hdr_t * plog_hdr)2592 void pr_roam_btm_rep_v2(prcd_event_log_hdr_t *plog_hdr)
2593 {
2594 roam_log_btm_rep_v2_t *log = (roam_log_btm_rep_v2_t *)plog_hdr->log_ptr;
2595 DHD_ERROR_ROAM(("ROAM_LOG_BTM_REP: time:%d version:%d req_mode:%d "
2596 "status:%d ret:%d\n",
2597 plog_hdr->armcycle, log->hdr.version,
2598 log->req_mode, log->status, log->result));
2599 }
2600
pr_roam_bcn_req_v3(prcd_event_log_hdr_t * plog_hdr)2601 void pr_roam_bcn_req_v3(prcd_event_log_hdr_t *plog_hdr)
2602 {
2603 roam_log_bcnrpt_req_v3_t *log = (roam_log_bcnrpt_req_v3_t *)plog_hdr->log_ptr;
2604
2605 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REQ: time:%d, version:%d ret:%d"
2606 "class:%d %s ",
2607 plog_hdr->armcycle, log->hdr.version,
2608 log->result, log->reg, log->channel?"":"all_chan"));
2609 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REQ: mode:%d is_wild:%d duration:%d"
2610 "ssid_len:%d\n", log->mode, log->bssid_wild,
2611 log->duration, log->ssid_len));
2612 if (log->channel_num != 0) {
2613 print_roam_chan_list("ROAM_LOG_BCNREQ_SCAN_CHANLIST", log->channel_num,
2614 log->band2g_chan_list, log->uni2a_chan_list,
2615 log->uni3_chan_list, log->uni2c_chan_list);
2616 }
2617 }
2618
2619 static const char*
pr_roam_bcn_rep_reason(uint16 reason_detail)2620 pr_roam_bcn_rep_reason(uint16 reason_detail)
2621 {
2622 static const char* reason_tbl[] = {
2623 "BCNRPT_RSN_SUCCESS",
2624 "BCNRPT_RSN_BADARG",
2625 "BCNRPT_RSN_SCAN_ING",
2626 "BCNRPT_RSN_SCAN_FAIL",
2627 "UNKNOWN"
2628 };
2629
2630 if (reason_detail >= ARRAYSIZE(reason_tbl)) {
2631 DHD_ERROR_ROAM(("UNKNOWN Reason:%u\n", reason_detail));
2632 ASSERT(0);
2633 reason_detail = ARRAYSIZE(reason_tbl) - 1;
2634
2635 }
2636 return reason_tbl[reason_detail];
2637 }
2638
pr_roam_bcn_rep_v3(prcd_event_log_hdr_t * plog_hdr)2639 void pr_roam_bcn_rep_v3(prcd_event_log_hdr_t *plog_hdr)
2640 {
2641 roam_log_bcnrpt_rep_v3_t *log = (roam_log_bcnrpt_rep_v3_t *)plog_hdr->log_ptr;
2642
2643 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REP: time:%d, verseion:%d count:%d mode:%d\n",
2644 plog_hdr->armcycle, log->hdr.version,
2645 log->count, log->reason));
2646 DHD_ERROR_ROAM(("ROAM_LOG_BCN_REP: mode reason(%d):%s scan_stus:%u duration:%u\n",
2647 log->reason_detail, pr_roam_bcn_rep_reason(log->reason_detail),
2648 (log->reason_detail == BCNRPT_RSN_SCAN_FAIL)? log->scan_status:0,
2649 log->duration));
2650 }
2651
pr_roam_btm_rep_v3(prcd_event_log_hdr_t * plog_hdr)2652 void pr_roam_btm_rep_v3(prcd_event_log_hdr_t *plog_hdr)
2653 {
2654 roam_log_btm_rep_v3_t *log = (roam_log_btm_rep_v3_t *)plog_hdr->log_ptr;
2655 DHD_ERROR_ROAM(("ROAM_LOG_BTM_REP: time:%d version:%d req_mode:%d "
2656 "status:%d ret:%d target:" MACDBG "\n",
2657 plog_hdr->armcycle, log->hdr.version,
2658 log->req_mode, log->status, log->result,
2659 MAC2STRDBG((uint8 *)&log->target_addr)));
2660 }
2661
2662 void
print_roam_enhanced_log(prcd_event_log_hdr_t * plog_hdr)2663 print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr)
2664 {
2665 prsv_periodic_log_hdr_t *hdr = (prsv_periodic_log_hdr_t *)plog_hdr->log_ptr;
2666 uint32 *ptr = (uint32 *)plog_hdr->log_ptr;
2667 int i;
2668 int loop_cnt = hdr->length / sizeof(uint32);
2669 struct bcmstrbuf b;
2670 char pr_buf[EL_LOG_STR_LEN] = { 0 };
2671 const pr_roam_tbl_t *cur_elem = &roam_log_print_tbl[0];
2672
2673 while (cur_elem && cur_elem->pr_func) {
2674 if (hdr->version == cur_elem->version &&
2675 hdr->id == cur_elem->id) {
2676 cur_elem->pr_func(plog_hdr);
2677 return;
2678 }
2679 cur_elem++;
2680 }
2681
2682 bcm_binit(&b, pr_buf, EL_LOG_STR_LEN);
2683 bcm_bprintf(&b, "ROAM_LOG_UNKNOWN ID:%d ver:%d armcycle:%d",
2684 hdr->id, hdr->version, plog_hdr->armcycle);
2685 for (i = 0; i < loop_cnt && b.size > 0; i++) {
2686 bcm_bprintf(&b, " %x", *ptr);
2687 ptr++;
2688 }
2689 DHD_ERROR_ROAM(("%s\n", b.origbuf));
2690 }
2691
2692 /*
2693 * dhd_dbg_attach: initialziation of dhd dbugability module
2694 *
2695 * Return: An error code or 0 on success.
2696 */
2697 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2698 struct dhd_dbg_ring_buf g_ring_buf;
2699 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2700 int
dhd_dbg_attach(dhd_pub_t * dhdp,dbg_pullreq_t os_pullreq,dbg_urgent_noti_t os_urgent_notifier,void * os_priv)2701 dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
2702 dbg_urgent_noti_t os_urgent_notifier, void *os_priv)
2703 {
2704 dhd_dbg_t *dbg = NULL;
2705 dhd_dbg_ring_t *ring = NULL;
2706 int ret = BCME_ERROR, ring_id = 0;
2707 void *buf = NULL;
2708 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2709 struct dhd_dbg_ring_buf *ring_buf;
2710 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2711
2712 dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t));
2713 if (!dbg)
2714 return BCME_NOMEM;
2715
2716 #ifdef CONFIG_DHD_USE_STATIC_BUF
2717 buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE);
2718 #else
2719 buf = MALLOCZ(dhdp->osh, FW_VERBOSE_RING_SIZE);
2720 #endif
2721 if (!buf)
2722 goto error;
2723 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID,
2724 (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, buf, FALSE);
2725 if (ret)
2726 goto error;
2727
2728 #ifdef CONFIG_DHD_USE_STATIC_BUF
2729 buf = DHD_OS_PREALLOC(dhdp, DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE);
2730 #else
2731 buf = MALLOCZ(dhdp->osh, DHD_EVENT_RING_SIZE);
2732 #endif
2733 if (!buf)
2734 goto error;
2735 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID,
2736 (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, buf, FALSE);
2737 if (ret)
2738 goto error;
2739
2740 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2741 buf = MALLOCZ(dhdp->osh, DRIVER_LOG_RING_SIZE);
2742 if (!buf)
2743 goto error;
2744 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DRIVER_LOG_RING_ID], DRIVER_LOG_RING_ID,
2745 (uint8 *)DRIVER_LOG_RING_NAME, DRIVER_LOG_RING_SIZE, buf, FALSE);
2746 if (ret)
2747 goto error;
2748
2749 buf = MALLOCZ(dhdp->osh, ROAM_STATS_RING_SIZE);
2750 if (!buf)
2751 goto error;
2752 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[ROAM_STATS_RING_ID], ROAM_STATS_RING_ID,
2753 (uint8 *)ROAM_STATS_RING_NAME, ROAM_STATS_RING_SIZE, buf, FALSE);
2754 if (ret)
2755 goto error;
2756 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2757 #ifdef BTLOG
2758 buf = MALLOCZ(dhdp->osh, BT_LOG_RING_SIZE);
2759 if (!buf)
2760 goto error;
2761 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[BT_LOG_RING_ID], BT_LOG_RING_ID,
2762 BT_LOG_RING_NAME, BT_LOG_RING_SIZE, buf, FALSE);
2763 if (ret)
2764 goto error;
2765 #endif /* BTLOG */
2766
2767 dbg->private = os_priv;
2768 dbg->pullreq = os_pullreq;
2769 dbg->urgent_notifier = os_urgent_notifier;
2770 dhdp->dbg = dbg;
2771 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2772 ring_buf = &g_ring_buf;
2773 ring_buf->dhd_pub = dhdp;
2774 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2775 return BCME_OK;
2776
2777 error:
2778 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
2779 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
2780 ring = &dbg->dbg_rings[ring_id];
2781 dhd_dbg_ring_deinit(dhdp, ring);
2782 if (ring->ring_buf) {
2783 #ifndef CONFIG_DHD_USE_STATIC_BUF
2784 MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
2785 #endif
2786 ring->ring_buf = NULL;
2787 }
2788 ring->ring_size = 0;
2789 }
2790 }
2791 MFREE(dhdp->osh, dbg, sizeof(dhd_dbg_t));
2792 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2793 ring_buf = &g_ring_buf;
2794 ring_buf->dhd_pub = NULL;
2795 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2796
2797 return ret;
2798 }
2799
2800 /*
2801 * dhd_dbg_detach: clean up dhd dbugability module
2802 */
2803 void
dhd_dbg_detach(dhd_pub_t * dhdp)2804 dhd_dbg_detach(dhd_pub_t *dhdp)
2805 {
2806 int ring_id;
2807 dhd_dbg_t *dbg;
2808 dhd_dbg_ring_t *ring = NULL;
2809 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2810 struct dhd_dbg_ring_buf *ring_buf;
2811 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2812
2813 if (!dhdp->dbg)
2814 return;
2815
2816 dbg = dhdp->dbg;
2817 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
2818 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
2819 ring = &dbg->dbg_rings[ring_id];
2820 dhd_dbg_ring_deinit(dhdp, ring);
2821 if (ring->ring_buf) {
2822 #ifndef CONFIG_DHD_USE_STATIC_BUF
2823 MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
2824 #endif
2825 ring->ring_buf = NULL;
2826 }
2827 ring->ring_size = 0;
2828 }
2829 }
2830 MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
2831 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
2832 ring_buf = &g_ring_buf;
2833 ring_buf->dhd_pub = NULL;
2834 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
2835 }
2836
2837 uint32
dhd_dbg_get_fwverbose(dhd_pub_t * dhdp)2838 dhd_dbg_get_fwverbose(dhd_pub_t *dhdp)
2839 {
2840 if (dhdp && dhdp->dbg) {
2841 return dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level;
2842 }
2843 return 0;
2844 }
2845
2846 void
dhd_dbg_set_fwverbose(dhd_pub_t * dhdp,uint32 new_val)2847 dhd_dbg_set_fwverbose(dhd_pub_t *dhdp, uint32 new_val)
2848 {
2849
2850 if (dhdp && dhdp->dbg) {
2851 dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level = new_val;
2852 }
2853 }
2854