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