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