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