xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  *  DOC:  qdf_trace
22  *  QCA driver framework (QDF) trace APIs
23  *  Trace, logging, and debugging definitions and APIs
24  */
25 
26 /* Include Files */
27 #include "qdf_str.h"
28 #include <qdf_trace.h>
29 #include <qdf_parse.h>
30 #include <qdf_module.h>
31 #include <qdf_util.h>
32 #include <qdf_mem.h>
33 
34 /* macro to map qdf trace levels into the bitmask */
35 #define QDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level)))
36 
37 #include <wlan_logging_sock_svc.h>
38 #include <qdf_module.h>
39 static int qdf_pidx = -1;
40 static bool qdf_log_dump_at_kernel_enable = true;
41 qdf_declare_param(qdf_log_dump_at_kernel_enable, bool);
42 
43 /* This value of 0 will disable the timer by default. */
44 static uint32_t qdf_log_flush_timer_period;
45 qdf_declare_param(qdf_log_flush_timer_period, uint);
46 
47 #include "qdf_time.h"
48 #include "qdf_mc_timer.h"
49 #include <host_diag_core_log.h>
50 
51 #if defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) || \
52 	defined(CONNECTIVITY_DIAG_EVENT)
53 #include <wlan_connectivity_logging.h>
54 #include "i_host_diag_core_event.h"
55 #endif
56 
57 /* Global qdf print id */
58 
59 /* Preprocessor definitions and constants */
60 
61 enum qdf_timestamp_unit qdf_log_timestamp_type = QDF_LOG_TIMESTAMP_UNIT;
62 
63 #define DP_TRACE_META_DATA_STRLEN 50
64 
65 #ifdef TRACE_RECORD
66 /* Static and Global variables */
67 static spinlock_t ltrace_lock;
68 /* global qdf trace data */
69 static t_qdf_trace_data g_qdf_trace_data;
70 /*
71  * all the call back functions for dumping MTRACE messages from ring buffer
72  * are stored in qdf_trace_cb_table,these callbacks are initialized during init
73  * only so, we will make a copy of these call back functions and maintain in to
74  * qdf_trace_restore_cb_table. Incase if we make modifications to
75  * qdf_trace_cb_table, we can certainly retrieve all the call back functions
76  * back from Restore Table
77  */
78 static tp_qdf_trace_cb qdf_trace_cb_table[QDF_MODULE_ID_MAX];
79 static tp_qdf_trace_cb qdf_trace_restore_cb_table[QDF_MODULE_ID_MAX];
80 
81 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
82 static qdf_trace_record_t *g_qdf_trace_tbl;
83 #else
84 static qdf_trace_record_t g_qdf_trace_tbl[MAX_QDF_TRACE_RECORDS];
85 #endif
86 
87 #endif
88 
89 #ifdef WLAN_FEATURE_MEMDUMP_ENABLE
90 static tp_qdf_state_info_cb qdf_state_info_table[QDF_MODULE_ID_MAX];
91 #endif
92 
93 #ifdef CONFIG_DP_TRACE
94 /* Static and Global variables */
95 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
96 static struct qdf_dp_trace_record_s *g_qdf_dp_trace_tbl;
97 #else
98 static struct qdf_dp_trace_record_s
99 			g_qdf_dp_trace_tbl[MAX_QDF_DP_TRACE_RECORDS];
100 #endif
101 static spinlock_t l_dp_trace_lock;
102 
103 /*
104  * all the options to configure/control DP trace are
105  * defined in this structure
106  */
107 static struct s_qdf_dp_trace_data g_qdf_dp_trace_data;
108 /*
109  * all the call back functions for dumping DPTRACE messages from ring buffer
110  * are stored in qdf_dp_trace_cb_table, callbacks are initialized during init
111  */
112 static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX + 1];
113 #endif
114 
115 #ifdef QCA_WIFI_MODULE_PARAMS_FROM_INI
116 #define QDF_PARAM_STR_LENGTH 40
117 
118 enum qdf_num_module_param {
119 	MEM_DEBUG_DISABLED,
120 	QDF_DBG_MASK,
121 	PREALLOC_DISABLED,
122 	QDF_LOG_DUMP_AT_KERNEL_ENABLE,
123 	QDF_DBG_ARR,
124 	QDF_LOG_FLUSH_TIMER_PERIOD,
125 	QDF_PARAM_MAX,
126 };
127 
128 static char qdf_module_param[QDF_PARAM_MAX][QDF_PARAM_STR_LENGTH] = {
129 	"mem_debug_disabled",
130 	"qdf_dbg_mask",
131 	"prealloc_disabled",
132 	"qdf_log_dump_at_kernel_enable",
133 	"qdf_dbg_arr",
134 	"qdf_log_flush_timer_period",
135 };
136 #endif
137 /**
138  * qdf_snprintf() - wrapper function to snprintf
139  * @str_buffer: string Buffer
140  * @size: defines the size of the data record
141  * @str_format: Format string in which the message to be logged. This format
142  * string contains printf-like replacement parameters, which follow
143  * this parameter in the variable argument list.
144  *
145  * Return: num of bytes written to buffer
146  */
147 int qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...)
148 {
149 	va_list args;
150 	int i;
151 
152 	va_start(args, str_format);
153 	i = vsnprintf(str_buffer, size, str_format, args);
154 	va_end(args);
155 
156 	return i;
157 }
158 qdf_export_symbol(qdf_snprintf);
159 
160 #ifdef QDF_ENABLE_TRACING
161 
162 /**
163  * qdf_trace_msg() - externally called trace function
164  * @module: Module identifier a member of the QDF_MODULE_ID
165  * enumeration that identifies the module issuing the trace message.
166  * @level: Trace level a member of the QDF_TRACE_LEVEL enumeration
167  * indicating the severity of the condition causing the trace message
168  * to be issued. More severe conditions are more likely to be logged.
169  * @str_format: Format string in which the message to be logged. This format
170  * string contains printf-like replacement parameters, which follow
171  * this parameter in the variable argument list.
172  *
173  * Checks the level of severity and accordingly prints the trace messages
174  *
175  * Return: None
176  */
177 void qdf_trace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
178 		   const char *str_format, ...)
179 {
180 	va_list val;
181 
182 	va_start(val, str_format);
183 	qdf_trace_msg_cmn(qdf_pidx, module, level, str_format, val);
184 	va_end(val);
185 }
186 qdf_export_symbol(qdf_trace_msg);
187 
188 void qdf_vtrace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
189 		    const char *str_format, va_list val)
190 {
191 	qdf_trace_msg_cmn(qdf_pidx, module, level, str_format, val);
192 }
193 qdf_export_symbol(qdf_vtrace_msg);
194 
195 #define ROW_SIZE 16
196 /* Buffer size = data bytes(2 hex chars plus space) + NULL */
197 #define BUFFER_SIZE ((QDF_DP_TRACE_RECORD_SIZE * 3) + 1)
198 
199 static void __qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
200 				 void *data, int buf_len, bool print_ascii)
201 {
202 	const u8 *ptr = data;
203 	int i = 0;
204 
205 	if (!qdf_print_is_verbose_enabled(qdf_pidx, module, level))
206 		return;
207 
208 	while (buf_len > 0) {
209 		unsigned char linebuf[BUFFER_SIZE] = {0};
210 		int linelen = min(buf_len, ROW_SIZE);
211 
212 		buf_len -= ROW_SIZE;
213 
214 		hex_dump_to_buffer(ptr, linelen, ROW_SIZE, 1,
215 				   linebuf, sizeof(linebuf), print_ascii);
216 
217 		qdf_trace_msg(module, level, "%.8x: %s", i, linebuf);
218 		ptr += ROW_SIZE;
219 		i += ROW_SIZE;
220 	}
221 }
222 
223 void qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
224 			void *data, int buf_len)
225 {
226 	__qdf_trace_hex_dump(module, level, data, buf_len, false);
227 }
228 
229 qdf_export_symbol(qdf_trace_hex_dump);
230 
231 void qdf_trace_hex_ascii_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
232 			      void *data, int buf_len)
233 {
234 	__qdf_trace_hex_dump(module, level, data, buf_len, true);
235 }
236 
237 qdf_export_symbol(qdf_trace_hex_ascii_dump);
238 
239 #endif
240 
241 #ifdef TRACE_RECORD
242 
243 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
244 static inline QDF_STATUS allocate_g_qdf_trace_tbl_buffer(void)
245 {
246 	g_qdf_trace_tbl = qdf_mem_valloc(MAX_QDF_TRACE_RECORDS *
247 					 sizeof(*g_qdf_trace_tbl));
248 	QDF_BUG(g_qdf_trace_tbl);
249 	return g_qdf_trace_tbl ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
250 }
251 
252 static inline void free_g_qdf_trace_tbl_buffer(void)
253 {
254 	qdf_mem_vfree(g_qdf_trace_tbl);
255 	g_qdf_trace_tbl = NULL;
256 }
257 #else
258 static inline QDF_STATUS allocate_g_qdf_trace_tbl_buffer(void)
259 {
260 	return QDF_STATUS_SUCCESS;
261 }
262 
263 static inline void free_g_qdf_trace_tbl_buffer(void)
264 { }
265 #endif
266 /**
267  * qdf_trace_enable() - Enable MTRACE for specific modules
268  * @bitmask_of_module_id: Bitmask according to enum of the modules.
269  *  32[dec] = 0010 0000 [bin] <enum of HDD is 5>
270  *  64[dec] = 0100 0000 [bin] <enum of SME is 6>
271  *  128[dec] = 1000 0000 [bin] <enum of PE is 7>
272  * @enable: can be true or false true implies enabling MTRACE false implies
273  *		disabling MTRACE.
274  *
275  * Enable MTRACE for specific modules whose bits are set in bitmask and enable
276  * is true. if enable is false it disables MTRACE for that module. set the
277  * bitmask according to enum value of the modules.
278  * This functions will be called when you issue ioctl as mentioned following
279  * [iwpriv wlan0 setdumplog <value> <enable>].
280  * <value> - Decimal number, i.e. 64 decimal value shows only SME module,
281  * 128 decimal value shows only PE module, 192 decimal value shows PE and SME.
282  *
283  * Return: None
284  */
285 void qdf_trace_enable(uint32_t bitmask_of_module_id, uint8_t enable)
286 {
287 	int i;
288 
289 	if (bitmask_of_module_id) {
290 		for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
291 			if (((bitmask_of_module_id >> i) & 1)) {
292 				if (enable) {
293 					if (NULL !=
294 					    qdf_trace_restore_cb_table[i]) {
295 						qdf_trace_cb_table[i] =
296 						qdf_trace_restore_cb_table[i];
297 					}
298 				} else {
299 					qdf_trace_restore_cb_table[i] =
300 						qdf_trace_cb_table[i];
301 					qdf_trace_cb_table[i] = NULL;
302 				}
303 			}
304 		}
305 	} else {
306 		if (enable) {
307 			for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
308 				if (qdf_trace_restore_cb_table[i]) {
309 					qdf_trace_cb_table[i] =
310 						qdf_trace_restore_cb_table[i];
311 				}
312 			}
313 		} else {
314 			for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
315 				qdf_trace_restore_cb_table[i] =
316 					qdf_trace_cb_table[i];
317 				qdf_trace_cb_table[i] = NULL;
318 			}
319 		}
320 	}
321 }
322 qdf_export_symbol(qdf_trace_enable);
323 
324 /**
325  * qdf_trace_init() - initializes qdf trace structures and variables
326  *
327  * Called immediately after cds_preopen, so that we can start recording HDD
328  * events ASAP.
329  *
330  * Return: None
331  */
332 void qdf_trace_init(void)
333 {
334 	uint8_t i;
335 
336 	if (allocate_g_qdf_trace_tbl_buffer() != QDF_STATUS_SUCCESS)
337 		return;
338 	g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR;
339 	g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR;
340 	g_qdf_trace_data.num = 0;
341 	g_qdf_trace_data.enable = true;
342 	g_qdf_trace_data.dump_count = DEFAULT_QDF_TRACE_DUMP_COUNT;
343 	g_qdf_trace_data.num_since_last_dump = 0;
344 
345 	for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
346 		qdf_trace_cb_table[i] = NULL;
347 		qdf_trace_restore_cb_table[i] = NULL;
348 	}
349 }
350 qdf_export_symbol(qdf_trace_init);
351 
352 /**
353  * qdf_trace_deinit() - frees memory allocated dynamically
354  *
355  * Called from cds_deinit, so that we can free the memory and resets
356  * the variables
357  *
358  * Return: None
359  */
360 void qdf_trace_deinit(void)
361 {
362 	g_qdf_trace_data.enable = false;
363 	g_qdf_trace_data.num = 0;
364 	g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR;
365 	g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR;
366 
367 	free_g_qdf_trace_tbl_buffer();
368 }
369 
370 qdf_export_symbol(qdf_trace_deinit);
371 
372 /**
373  * qdf_trace() - puts the messages in to ring-buffer
374  * @module: Enum of module, basically module id.
375  * @code: Code to be recorded
376  * @session: Session ID of the log
377  * @data: Actual message contents
378  *
379  * This function will be called from each module who wants record the messages
380  * in circular queue. Before calling this functions make sure you have
381  * registered your module with qdf through qdf_trace_register function.
382  *
383  * Return: None
384  */
385 void qdf_trace(uint8_t module, uint16_t code, uint16_t session, uint32_t data)
386 {
387 	tp_qdf_trace_record rec = NULL;
388 	unsigned long flags;
389 	char time[18];
390 
391 	if (!g_qdf_trace_data.enable)
392 		return;
393 
394 	/* if module is not registered, don't record for that module */
395 	if (!qdf_trace_cb_table[module])
396 		return;
397 
398 	qdf_get_time_of_the_day_in_hr_min_sec_usec(time, sizeof(time));
399 	/* Acquire the lock so that only one thread at a time can fill the ring
400 	 * buffer
401 	 */
402 	spin_lock_irqsave(&ltrace_lock, flags);
403 
404 	g_qdf_trace_data.num++;
405 
406 	if (g_qdf_trace_data.num > MAX_QDF_TRACE_RECORDS)
407 		g_qdf_trace_data.num = MAX_QDF_TRACE_RECORDS;
408 
409 	if (INVALID_QDF_TRACE_ADDR == g_qdf_trace_data.head) {
410 		/* first record */
411 		g_qdf_trace_data.head = 0;
412 		g_qdf_trace_data.tail = 0;
413 	} else {
414 		/* queue is not empty */
415 		uint32_t tail = g_qdf_trace_data.tail + 1;
416 
417 		if (MAX_QDF_TRACE_RECORDS == tail)
418 			tail = 0;
419 
420 		if (g_qdf_trace_data.head == tail) {
421 			/* full */
422 			if (MAX_QDF_TRACE_RECORDS == ++g_qdf_trace_data.head)
423 				g_qdf_trace_data.head = 0;
424 		}
425 		g_qdf_trace_data.tail = tail;
426 	}
427 
428 	rec = &g_qdf_trace_tbl[g_qdf_trace_data.tail];
429 	rec->code = code;
430 	rec->session = session;
431 	rec->data = data;
432 	rec->qtime = qdf_get_log_timestamp();
433 	scnprintf(rec->time, sizeof(rec->time), "%s", time);
434 	rec->module = module;
435 	rec->pid = (in_interrupt() ? 0 : current->pid);
436 	g_qdf_trace_data.num_since_last_dump++;
437 	spin_unlock_irqrestore(&ltrace_lock, flags);
438 }
439 qdf_export_symbol(qdf_trace);
440 
441 #ifdef ENABLE_MTRACE_LOG
442 void qdf_mtrace_log(QDF_MODULE_ID src_module, QDF_MODULE_ID dst_module,
443 		    uint16_t message_id, uint8_t vdev_id)
444 {
445 	uint32_t trace_log, payload;
446 	static uint16_t counter;
447 
448 	trace_log = (src_module << 23) | (dst_module << 15) | message_id;
449 	payload = (vdev_id << 16) | counter++;
450 
451 	QDF_TRACE(src_module, QDF_TRACE_LEVEL_TRACE, "%x %x",
452 		  trace_log, payload);
453 }
454 
455 qdf_export_symbol(qdf_mtrace_log);
456 #endif
457 
458 void qdf_mtrace(QDF_MODULE_ID src_module, QDF_MODULE_ID dst_module,
459 		uint16_t message_id, uint8_t vdev_id, uint32_t data)
460 {
461 	qdf_trace(src_module, message_id, vdev_id, data);
462 	qdf_mtrace_log(src_module, dst_module, message_id, vdev_id);
463 }
464 
465 qdf_export_symbol(qdf_mtrace);
466 
467 /**
468  * qdf_trace_spin_lock_init() - initializes the lock variable before use
469  *
470  * This function will be called from cds_alloc_global_context, we will have lock
471  * available to use ASAP
472  *
473  * Return: None
474  */
475 QDF_STATUS qdf_trace_spin_lock_init(void)
476 {
477 	spin_lock_init(&ltrace_lock);
478 
479 	return QDF_STATUS_SUCCESS;
480 }
481 qdf_export_symbol(qdf_trace_spin_lock_init);
482 
483 /**
484  * qdf_trace_register() - registers the call back functions
485  * @module_iD: enum value of module
486  * @qdf_trace_callback: call back functions to display the messages in
487  * particular format.
488  *
489  * Registers the call back functions to display the messages in particular
490  * format mentioned in these call back functions. This functions should be
491  * called by interested module in their init part as we will be ready to
492  * register as soon as modules are up.
493  *
494  * Return: None
495  */
496 void qdf_trace_register(QDF_MODULE_ID module_id,
497 			tp_qdf_trace_cb qdf_trace_callback)
498 {
499 	qdf_trace_cb_table[module_id] = qdf_trace_callback;
500 }
501 qdf_export_symbol(qdf_trace_register);
502 
503 /**
504  * qdf_trace_dump_all() - Dump data from ring buffer via call back functions
505  * registered with QDF
506  * @p_mac: Context of particular module
507  * @code: Reason code
508  * @session: Session id of log
509  * @count: Number of lines to dump starting from tail to head
510  *
511  * This function will be called up on issuing ioctl call as mentioned following
512  * [iwpriv wlan0 dumplog 0 0 <n> <bitmask_of_module>]
513  *
514  * <n> - number lines to dump starting from tail to head.
515  *
516  * <bitmask_of_module> - if anybody wants to know how many messages were
517  * recorded for particular module/s mentioned by setbit in bitmask from last
518  * <n> messages. It is optional, if you don't provide then it will dump
519  * everything from buffer.
520  *
521  * Return: None
522  */
523 void qdf_trace_dump_all(void *p_mac, uint8_t code, uint8_t session,
524 	uint32_t count, uint32_t bitmask_of_module)
525 {
526 	qdf_trace_record_t p_record;
527 	int32_t i, tail;
528 
529 	if (!g_qdf_trace_data.enable) {
530 		QDF_TRACE(QDF_MODULE_ID_SYS,
531 			  QDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
532 		return;
533 	}
534 
535 	QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO,
536 		  "DPT: Total Records: %d, Head: %d, Tail: %d",
537 		  g_qdf_trace_data.num, g_qdf_trace_data.head,
538 		  g_qdf_trace_data.tail);
539 
540 	/* acquire the lock so that only one thread at a time can read
541 	 * the ring buffer
542 	 */
543 	spin_lock(&ltrace_lock);
544 
545 	if (g_qdf_trace_data.head != INVALID_QDF_TRACE_ADDR) {
546 		i = g_qdf_trace_data.head;
547 		tail = g_qdf_trace_data.tail;
548 
549 		if (count) {
550 			if (count > g_qdf_trace_data.num)
551 				count = g_qdf_trace_data.num;
552 			if (tail >= (count - 1))
553 				i = tail - count + 1;
554 			else if (count != MAX_QDF_TRACE_RECORDS)
555 				i = MAX_QDF_TRACE_RECORDS - ((count - 1) -
556 							     tail);
557 		}
558 
559 		p_record = g_qdf_trace_tbl[i];
560 		/* right now we are not using num_since_last_dump member but
561 		 * in future we might re-visit and use this member to track
562 		 * how many latest messages got added while we were dumping
563 		 * from ring buffer
564 		 */
565 		g_qdf_trace_data.num_since_last_dump = 0;
566 		spin_unlock(&ltrace_lock);
567 		for (;; ) {
568 			if ((code == 0 || (code == p_record.code)) &&
569 			    (qdf_trace_cb_table[p_record.module])) {
570 				if (0 == bitmask_of_module) {
571 					qdf_trace_cb_table[p_record.
572 							   module] (p_mac,
573 								    &p_record,
574 								    (uint16_t)
575 								    i);
576 				} else {
577 					if (bitmask_of_module &
578 					    (1 << p_record.module)) {
579 						qdf_trace_cb_table[p_record.
580 								   module]
581 							(p_mac, &p_record,
582 							(uint16_t) i);
583 					}
584 				}
585 			}
586 
587 			if (i == tail)
588 				break;
589 			i += 1;
590 
591 			spin_lock(&ltrace_lock);
592 			if (MAX_QDF_TRACE_RECORDS == i) {
593 				i = 0;
594 				p_record = g_qdf_trace_tbl[0];
595 			} else {
596 				p_record = g_qdf_trace_tbl[i];
597 			}
598 			spin_unlock(&ltrace_lock);
599 		}
600 	} else {
601 		spin_unlock(&ltrace_lock);
602 	}
603 }
604 qdf_export_symbol(qdf_trace_dump_all);
605 #endif
606 
607 #ifdef WLAN_FEATURE_MEMDUMP_ENABLE
608 /**
609  * qdf_register_debugcb_init() - initializes debug callbacks
610  * to NULL
611  *
612  * Return: None
613  */
614 void qdf_register_debugcb_init(void)
615 {
616 	uint8_t i;
617 
618 	for (i = 0; i < QDF_MODULE_ID_MAX; i++)
619 		qdf_state_info_table[i] = NULL;
620 }
621 qdf_export_symbol(qdf_register_debugcb_init);
622 
623 /**
624  * qdf_register_debug_callback() - stores callback handlers to print
625  * state information
626  * @module_id: module id of layer
627  * @qdf_state_infocb: callback to be registered
628  *
629  * This function is used to store callback handlers to print
630  * state information
631  *
632  * Return: None
633  */
634 void qdf_register_debug_callback(QDF_MODULE_ID module_id,
635 					tp_qdf_state_info_cb qdf_state_infocb)
636 {
637 	qdf_state_info_table[module_id] = qdf_state_infocb;
638 }
639 qdf_export_symbol(qdf_register_debug_callback);
640 
641 /**
642  * qdf_state_info_dump_all() - it invokes callback of layer which registered
643  * its callback to print its state information.
644  * @buf:  buffer pointer to be passed
645  * @size:  size of buffer to be filled
646  * @driver_dump_size: actual size of buffer used
647  *
648  * Return: QDF_STATUS_SUCCESS on success
649  */
650 QDF_STATUS qdf_state_info_dump_all(char *buf, uint16_t size,
651 			uint16_t *driver_dump_size)
652 {
653 	uint8_t module, ret = QDF_STATUS_SUCCESS;
654 	uint16_t buf_len = size;
655 	char *buf_ptr = buf;
656 
657 	for (module = 0; module < QDF_MODULE_ID_MAX; module++) {
658 		if (qdf_state_info_table[module]) {
659 			qdf_state_info_table[module](&buf_ptr, &buf_len);
660 			if (!buf_len) {
661 				ret = QDF_STATUS_E_NOMEM;
662 				break;
663 			}
664 		}
665 	}
666 
667 	*driver_dump_size = size - buf_len;
668 	return ret;
669 }
670 qdf_export_symbol(qdf_state_info_dump_all);
671 #endif
672 
673 #ifdef CONFIG_DP_TRACE
674 
675 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
676 static inline QDF_STATUS allocate_g_qdf_dp_trace_tbl_buffer(void)
677 {
678 	g_qdf_dp_trace_tbl = qdf_mem_valloc(MAX_QDF_DP_TRACE_RECORDS *
679 					    sizeof(*g_qdf_dp_trace_tbl));
680 	QDF_BUG(g_qdf_dp_trace_tbl);
681 	return g_qdf_dp_trace_tbl ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
682 }
683 
684 static inline void free_g_qdf_dp_trace_tbl_buffer(void)
685 {
686 	qdf_mem_vfree(g_qdf_dp_trace_tbl);
687 	g_qdf_dp_trace_tbl = NULL;
688 }
689 #else
690 static inline QDF_STATUS allocate_g_qdf_dp_trace_tbl_buffer(void)
691 {
692 	return QDF_STATUS_SUCCESS;
693 }
694 
695 static inline void free_g_qdf_dp_trace_tbl_buffer(void)
696 { }
697 #endif
698 
699 #define QDF_DP_TRACE_PREPEND_STR_SIZE 100
700 /*
701  * one dp trace record can't be greater than 300 bytes.
702  * Max Size will be QDF_DP_TRACE_PREPEND_STR_SIZE(100) + BUFFER_SIZE(121).
703  * Always make sure to change this QDF_DP_TRACE_MAX_RECORD_SIZE
704  * value accordingly whenever above two mentioned MACRO value changes.
705  */
706 #define QDF_DP_TRACE_MAX_RECORD_SIZE 300
707 
708 static void qdf_dp_unused(struct qdf_dp_trace_record_s *record,
709 			  uint16_t index, uint8_t pdev_id, uint8_t info)
710 {
711 	qdf_print("%s: QDF_DP_TRACE_MAX event should not be generated",
712 		  __func__);
713 }
714 
715 /**
716  * qdf_dp_trace_init() - enables the DP trace
717  * @live_mode_config: live mode configuration
718  * @thresh: high throughput threshold for disabling live mode
719  * @thresh_time_limit: max time to wait before deciding if thresh is crossed
720  * @verbosity: dptrace verbosity level
721  * @proto_bitmap: bitmap to enable/disable specific protocols
722  *
723  * Called during driver load to init dptrace
724  *
725  * A brief note on the 'thresh' param -
726  * Total # of packets received in a bandwidth timer interval beyond which
727  * DP Trace logging for data packets (including ICMP) will be disabled.
728  * In memory logging will still continue for these packets. Other packets for
729  * which proto.bitmap is set will continue to be recorded in logs and in memory.
730 
731  * Return: None
732  */
733 void qdf_dp_trace_init(bool live_mode_config, uint8_t thresh,
734 				uint16_t time_limit, uint8_t verbosity,
735 				uint32_t proto_bitmap)
736 {
737 	uint8_t i;
738 
739 	if (allocate_g_qdf_dp_trace_tbl_buffer() != QDF_STATUS_SUCCESS) {
740 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
741 				"Failed!!! DP Trace buffer allocation");
742 		return;
743 	}
744 	qdf_dp_trace_spin_lock_init();
745 	qdf_dp_trace_clear_buffer();
746 	g_qdf_dp_trace_data.enable = true;
747 	g_qdf_dp_trace_data.no_of_record = 1;
748 
749 	g_qdf_dp_trace_data.live_mode_config = live_mode_config;
750 	g_qdf_dp_trace_data.live_mode = live_mode_config;
751 	g_qdf_dp_trace_data.high_tput_thresh = thresh;
752 	g_qdf_dp_trace_data.thresh_time_limit = time_limit;
753 	g_qdf_dp_trace_data.proto_bitmap = proto_bitmap;
754 	g_qdf_dp_trace_data.verbosity = verbosity;
755 	g_qdf_dp_trace_data.ini_conf_verbosity = verbosity;
756 
757 	for (i = 0; i < ARRAY_SIZE(qdf_dp_trace_cb_table); i++)
758 		qdf_dp_trace_cb_table[i] = qdf_dp_display_record;
759 
760 	qdf_dp_trace_cb_table[QDF_DP_TRACE_HDD_TX_PACKET_RECORD] =
761 		qdf_dp_trace_cb_table[QDF_DP_TRACE_HDD_RX_PACKET_RECORD] =
762 		qdf_dp_trace_cb_table[QDF_DP_TRACE_TX_PACKET_RECORD] =
763 		qdf_dp_trace_cb_table[QDF_DP_TRACE_RX_PACKET_RECORD] =
764 		qdf_dp_trace_cb_table[QDF_DP_TRACE_DROP_PACKET_RECORD] =
765 		qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD] =
766 		qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD] =
767 		qdf_dp_display_data_pkt_record;
768 
769 	qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD] =
770 	qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD] =
771 	qdf_dp_trace_cb_table[QDF_DP_TRACE_FREE_PACKET_PTR_RECORD] =
772 	qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD] =
773 						qdf_dp_display_ptr_record;
774 	qdf_dp_trace_cb_table[QDF_DP_TRACE_EAPOL_PACKET_RECORD] =
775 	qdf_dp_trace_cb_table[QDF_DP_TRACE_DHCP_PACKET_RECORD] =
776 	qdf_dp_trace_cb_table[QDF_DP_TRACE_ARP_PACKET_RECORD] =
777 	qdf_dp_trace_cb_table[QDF_DP_TRACE_ICMP_PACKET_RECORD] =
778 	qdf_dp_trace_cb_table[QDF_DP_TRACE_ICMPv6_PACKET_RECORD] =
779 						qdf_dp_display_proto_pkt;
780 	qdf_dp_trace_cb_table[QDF_DP_TRACE_MGMT_PACKET_RECORD] =
781 					qdf_dp_display_mgmt_pkt;
782 	qdf_dp_trace_cb_table[QDF_DP_TRACE_TX_CREDIT_RECORD] =
783 					qdf_dp_display_credit_record;
784 	qdf_dp_trace_cb_table[QDF_DP_TRACE_EVENT_RECORD] =
785 					qdf_dp_display_event_record;
786 
787 	qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX] = qdf_dp_unused;
788 }
789 qdf_export_symbol(qdf_dp_trace_init);
790 
791 void qdf_dp_trace_deinit(void)
792 {
793 	if (!g_qdf_dp_trace_data.enable)
794 		return;
795 	spin_lock_bh(&l_dp_trace_lock);
796 	g_qdf_dp_trace_data.enable = false;
797 	g_qdf_dp_trace_data.no_of_record = 0;
798 	spin_unlock_bh(&l_dp_trace_lock);
799 
800 	free_g_qdf_dp_trace_tbl_buffer();
801 }
802 /**
803  * qdf_dp_trace_set_value() - Configure the value to control DP trace
804  * @proto_bitmap: defines the protocol to be tracked
805  * @no_of_records: defines the nth packet which is traced
806  * @verbosity: defines the verbosity level
807  *
808  * Return: None
809  */
810 void qdf_dp_trace_set_value(uint32_t proto_bitmap, uint8_t no_of_record,
811 			    uint8_t verbosity)
812 {
813 	g_qdf_dp_trace_data.proto_bitmap = proto_bitmap;
814 	g_qdf_dp_trace_data.no_of_record = no_of_record;
815 	g_qdf_dp_trace_data.verbosity    = verbosity;
816 	g_qdf_dp_trace_data.dynamic_verbosity_modify = true;
817 }
818 qdf_export_symbol(qdf_dp_trace_set_value);
819 
820 /**
821  * qdf_dp_trace_set_verbosity() - set verbosity value
822  *
823  * @val: Value to set
824  *
825  * Return: Null
826  */
827 void qdf_dp_trace_set_verbosity(uint32_t val)
828 {
829 	g_qdf_dp_trace_data.verbosity = val;
830 }
831 qdf_export_symbol(qdf_dp_trace_set_verbosity);
832 
833 /**
834  * qdf_dp_get_verbosity) - get verbosity value
835  *
836  * Return: int
837  */
838 uint8_t qdf_dp_get_verbosity(void)
839 {
840 	return g_qdf_dp_trace_data.verbosity;
841 }
842 qdf_export_symbol(qdf_dp_get_verbosity);
843 
844 /**
845  * qdf_dp_set_proto_bitmap() - set dp trace proto bitmap
846  *
847  * @val         : unsigned bitmap to set
848  *
849  * Return: proto bitmap
850  */
851 void qdf_dp_set_proto_bitmap(uint32_t val)
852 {
853 	g_qdf_dp_trace_data.proto_bitmap = val;
854 }
855 qdf_export_symbol(qdf_dp_set_proto_bitmap);
856 
857 void qdf_dp_set_proto_event_bitmap(uint32_t value)
858 {
859 	g_qdf_dp_trace_data.proto_event_bitmap = value;
860 }
861 
862 qdf_export_symbol(qdf_dp_set_proto_event_bitmap);
863 
864 static uint32_t qdf_dp_get_proto_event_bitmap(void)
865 {
866 	return g_qdf_dp_trace_data.proto_event_bitmap;
867 }
868 
869 /**
870  * qdf_dp_set_no_of_record() - set dp trace no_of_record
871  *
872  * @val         : unsigned no_of_record to set
873  *
874  * Return: null
875  */
876 void qdf_dp_set_no_of_record(uint32_t val)
877 {
878 	g_qdf_dp_trace_data.no_of_record = val;
879 }
880 qdf_export_symbol(qdf_dp_set_no_of_record);
881 
882 /**
883  * qdf_dp_get_no_of_record() - get dp trace no_of_record
884  *
885  * Return: number of records
886  */
887 uint8_t qdf_dp_get_no_of_record(void)
888 {
889 	return g_qdf_dp_trace_data.no_of_record;
890 }
891 qdf_export_symbol(qdf_dp_get_no_of_record);
892 
893 
894 /**
895  * qdf_dp_trace_verbosity_check() - check whether verbosity level is enabled
896  * @code: defines the event
897  *
898  * In High verbosity all codes are logged.
899  * For Med/Low and Default case code which has
900  * less value than corresponding verbosity codes
901  * are logged.
902  *
903  * Return: true or false depends on whether tracing enabled
904  */
905 static bool qdf_dp_trace_verbosity_check(enum QDF_DP_TRACE_ID code)
906 {
907 	switch (g_qdf_dp_trace_data.verbosity) {
908 	case QDF_DP_TRACE_VERBOSITY_HIGH:
909 		return true;
910 	case QDF_DP_TRACE_VERBOSITY_MEDIUM:
911 		if (code <= QDF_DP_TRACE_MED_VERBOSITY)
912 			return true;
913 		return false;
914 	case QDF_DP_TRACE_VERBOSITY_LOW:
915 		if (code <= QDF_DP_TRACE_LOW_VERBOSITY)
916 			return true;
917 		return false;
918 	case QDF_DP_TRACE_VERBOSITY_ULTRA_LOW:
919 		if (code <= QDF_DP_TRACE_ULTRA_LOW_VERBOSITY)
920 			return true;
921 		return false;
922 	case QDF_DP_TRACE_VERBOSITY_BASE:
923 		if (code <= QDF_DP_TRACE_BASE_VERBOSITY)
924 			return true;
925 		return false;
926 	default:
927 		return false;
928 	}
929 }
930 
931 /**
932  * qdf_dp_get_proto_bitmap() - get dp trace proto bitmap
933  *
934  * Return: proto bitmap
935  */
936 uint32_t qdf_dp_get_proto_bitmap(void)
937 {
938 	if (g_qdf_dp_trace_data.enable)
939 		return g_qdf_dp_trace_data.proto_bitmap;
940 	else
941 		return 0;
942 }
943 
944 /**
945  * qdf_dp_trace_set_track() - Marks whether the packet needs to be traced
946  * @nbuf: defines the netbuf
947  * @dir: direction
948  *
949  * Return: None
950  */
951 void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir)
952 {
953 	uint32_t count = 0;
954 
955 	if (!g_qdf_dp_trace_data.enable)
956 		return;
957 
958 	spin_lock_bh(&l_dp_trace_lock);
959 	if (QDF_TX == dir)
960 		count = ++g_qdf_dp_trace_data.tx_count;
961 	else if (QDF_RX == dir)
962 		count = ++g_qdf_dp_trace_data.rx_count;
963 
964 	if ((g_qdf_dp_trace_data.no_of_record != 0) &&
965 		(count % g_qdf_dp_trace_data.no_of_record == 0)) {
966 		if (QDF_TX == dir)
967 			QDF_NBUF_CB_TX_DP_TRACE(nbuf) = 1;
968 		else if (QDF_RX == dir)
969 			QDF_NBUF_CB_RX_DP_TRACE(nbuf) = 1;
970 	}
971 	spin_unlock_bh(&l_dp_trace_lock);
972 }
973 qdf_export_symbol(qdf_dp_trace_set_track);
974 
975 /* Number of bytes to be grouped together while printing DP-Trace data */
976 #define QDF_DUMP_DP_GROUP_SIZE 6
977 
978 /**
979  * dump_dp_hex_trace() - Display the data in buffer
980  * @prepend_str:     string to prepend the hexdump with.
981  * @inbuf:     buffer which contains data to be displayed
982  * @inbuf_len: defines the size of the data to be displayed
983  *
984  * Return: None
985  */
986 static void
987 dump_dp_hex_trace(char *prepend_str, uint8_t *inbuf, uint8_t inbuf_len)
988 {
989 	unsigned char outbuf[BUFFER_SIZE];
990 	const uint8_t *inbuf_ptr = inbuf;
991 	char *outbuf_ptr = outbuf;
992 	int outbytes_written = 0;
993 
994 	qdf_mem_zero(outbuf, sizeof(outbuf));
995 	do {
996 		outbytes_written += scnprintf(outbuf_ptr,
997 					BUFFER_SIZE - outbytes_written,
998 					"%02x", *inbuf_ptr);
999 		outbuf_ptr = outbuf + outbytes_written;
1000 
1001 		if ((inbuf_ptr - inbuf) &&
1002 		    (inbuf_ptr - inbuf + 1) % QDF_DUMP_DP_GROUP_SIZE == 0) {
1003 			outbytes_written += scnprintf(outbuf_ptr,
1004 						BUFFER_SIZE - outbytes_written,
1005 						" ");
1006 			outbuf_ptr = outbuf + outbytes_written;
1007 		}
1008 		inbuf_ptr++;
1009 	} while (inbuf_ptr < (inbuf + inbuf_len));
1010 	DPTRACE_PRINT("%s %s", prepend_str, outbuf);
1011 }
1012 
1013 /**
1014  * qdf_dp_code_to_string() - convert dptrace code to string
1015  * @code: dptrace code
1016  *
1017  * Return: string version of code
1018  */
1019 static
1020 const char *qdf_dp_code_to_string(enum QDF_DP_TRACE_ID code)
1021 {
1022 	switch (code) {
1023 	case QDF_DP_TRACE_DROP_PACKET_RECORD:
1024 		return "DROP:";
1025 	case QDF_DP_TRACE_EAPOL_PACKET_RECORD:
1026 		return "EAPOL:";
1027 	case QDF_DP_TRACE_DHCP_PACKET_RECORD:
1028 		return "DHCP:";
1029 	case QDF_DP_TRACE_ARP_PACKET_RECORD:
1030 		return "ARP:";
1031 	case QDF_DP_TRACE_ICMP_PACKET_RECORD:
1032 		return "ICMP:";
1033 	case QDF_DP_TRACE_ICMPv6_PACKET_RECORD:
1034 		return "ICMPv6:";
1035 	case QDF_DP_TRACE_MGMT_PACKET_RECORD:
1036 		return "MGMT:";
1037 	case QDF_DP_TRACE_TX_CREDIT_RECORD:
1038 		return "CREDIT:";
1039 	case QDF_DP_TRACE_EVENT_RECORD:
1040 		return "EVENT:";
1041 	case QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD:
1042 		return "HDD: TX: PTR:";
1043 	case QDF_DP_TRACE_LI_DP_TX_PACKET_PTR_RECORD:
1044 		return "LI_DP: TX: PTR:";
1045 	case QDF_DP_TRACE_HDD_TX_PACKET_RECORD:
1046 		return "HDD: TX: DATA:";
1047 	case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD:
1048 	case QDF_DP_TRACE_TX_PACKET_RECORD:
1049 		return "TX:";
1050 	case QDF_DP_TRACE_CE_PACKET_PTR_RECORD:
1051 		return "CE: TX: PTR:";
1052 	case QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD:
1053 		return "CE: TX: FAST: PTR:";
1054 	case QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD:
1055 		return "CE: TX: FAST: ERR:";
1056 	case QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD:
1057 	case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD:
1058 		return "FREE: TX: PTR:";
1059 	case QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD:
1060 		return "HTT: RX: PTR:";
1061 	case QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD:
1062 		return "HTT: RX: OF: PTR:";
1063 	case QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD:
1064 		return "HDD: RX: PTR:";
1065 	case QDF_DP_TRACE_RX_LI_DP_PACKET_PTR_RECORD:
1066 		return "LI_DP: RX: PTR:";
1067 	case QDF_DP_TRACE_HDD_RX_PACKET_RECORD:
1068 		return "HDD: RX: DATA:";
1069 	case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD:
1070 		return "LI_DP_NULL: RX: DATA:";
1071 	case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD:
1072 	case QDF_DP_TRACE_RX_PACKET_RECORD:
1073 		return "RX:";
1074 	case QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD:
1075 		return "TXRX: TX: Q: PTR:";
1076 	case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD:
1077 		return "TXRX: TX: PTR:";
1078 	case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD:
1079 		return "TXRX: TX: FAST: PTR:";
1080 	case QDF_DP_TRACE_HTT_PACKET_PTR_RECORD:
1081 		return "HTT: TX: PTR:";
1082 	case QDF_DP_TRACE_HTC_PACKET_PTR_RECORD:
1083 		return "HTC: TX: PTR:";
1084 	case QDF_DP_TRACE_HIF_PACKET_PTR_RECORD:
1085 		return "HIF: TX: PTR:";
1086 	case QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD:
1087 		return "TXRX: RX: PTR:";
1088 	case QDF_DP_TRACE_HDD_TX_TIMEOUT:
1089 		return "HDD: STA: TO:";
1090 	case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
1091 		return "HDD: SAP: TO:";
1092 	default:
1093 		return "Invalid";
1094 	}
1095 }
1096 
1097 /**
1098  * qdf_dp_dir_to_str() - convert direction to string
1099  * @dir: direction
1100  *
1101  * Return: string version of direction
1102  */
1103 static const char *qdf_dp_dir_to_str(enum qdf_proto_dir dir)
1104 {
1105 	switch (dir) {
1106 	case QDF_TX:
1107 		return " --> ";
1108 	case QDF_RX:
1109 		return " <-- ";
1110 	default:
1111 		return "invalid";
1112 	}
1113 }
1114 
1115 static const char *qdf_dp_credit_source_to_str(
1116 		enum QDF_CREDIT_UPDATE_SOURCE source)
1117 {
1118 	switch (source) {
1119 	case QDF_TX_SCHED:
1120 		return "TX SCHED";
1121 	case QDF_TX_COMP:
1122 		return "TX COMP";
1123 	case QDF_TX_CREDIT_UPDATE:
1124 		return "CREDIT UP";
1125 	case QDF_TX_HTT_MSG:
1126 		return "HTT TX MSG";
1127 	case QDF_HTT_ATTACH:
1128 		return "HTT ATTACH";
1129 	default:
1130 		return "invalid";
1131 	}
1132 }
1133 
1134 static const char *qdf_dp_operation_to_str(enum QDF_CREDIT_OPERATION op)
1135 {
1136 	switch (op) {
1137 	case QDF_CREDIT_INC:
1138 		return "+";
1139 	case QDF_CREDIT_DEC:
1140 		return "-";
1141 	case QDF_CREDIT_ABS:
1142 		return "ABS";
1143 	default:
1144 		return "invalid";
1145 	}
1146 }
1147 
1148 /**
1149  * qdf_dp_type_to_str() - convert packet type to string
1150  * @type: type
1151  *
1152  * Return: string version of packet type
1153  */
1154 static const char *qdf_dp_type_to_str(enum qdf_proto_type type)
1155 {
1156 	switch (type) {
1157 	case QDF_PROTO_TYPE_DHCP:
1158 		return "DHCP";
1159 	case QDF_PROTO_TYPE_EAPOL:
1160 		return "EAPOL";
1161 	case QDF_PROTO_TYPE_ARP:
1162 		return "ARP";
1163 	case QDF_PROTO_TYPE_ICMP:
1164 		return "ICMP";
1165 	case QDF_PROTO_TYPE_ICMPv6:
1166 		return "ICMPv6";
1167 	case QDF_PROTO_TYPE_MGMT:
1168 		return "MGMT";
1169 	case QDF_PROTO_TYPE_EVENT:
1170 		return "EVENT";
1171 	default:
1172 		return "invalid";
1173 	}
1174 }
1175 
1176 /**
1177  * qdf_dp_subtype_to_str() - convert packet subtype to string
1178  * @type: type
1179  *
1180  * Return: string version of packet subtype
1181  */
1182 static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype)
1183 {
1184 	switch (subtype) {
1185 	case QDF_PROTO_EAPOL_M1:
1186 		return "M1";
1187 	case QDF_PROTO_EAPOL_M2:
1188 		return "M2";
1189 	case QDF_PROTO_EAPOL_M3:
1190 		return "M3";
1191 	case QDF_PROTO_EAPOL_M4:
1192 		return "M4";
1193 	case QDF_PROTO_DHCP_DISCOVER:
1194 		return "DISC";
1195 	case QDF_PROTO_DHCP_REQUEST:
1196 		return "REQ";
1197 	case QDF_PROTO_DHCP_OFFER:
1198 		return "OFF";
1199 	case QDF_PROTO_DHCP_ACK:
1200 		return "ACK";
1201 	case QDF_PROTO_DHCP_NACK:
1202 		return "NACK";
1203 	case QDF_PROTO_DHCP_RELEASE:
1204 		return "REL";
1205 	case QDF_PROTO_DHCP_INFORM:
1206 		return "INFORM";
1207 	case QDF_PROTO_DHCP_DECLINE:
1208 		return "DECL";
1209 	case QDF_PROTO_ARP_REQ:
1210 	case QDF_PROTO_ICMP_REQ:
1211 	case QDF_PROTO_ICMPV6_REQ:
1212 		return "REQ";
1213 	case QDF_PROTO_ARP_RES:
1214 	case QDF_PROTO_ICMP_RES:
1215 	case QDF_PROTO_ICMPV6_RES:
1216 		return "RSP";
1217 	case QDF_PROTO_ICMPV6_RS:
1218 		return "RS";
1219 	case QDF_PROTO_ICMPV6_RA:
1220 		return "RA";
1221 	case QDF_PROTO_ICMPV6_NS:
1222 		return "NS";
1223 	case QDF_PROTO_ICMPV6_NA:
1224 		return "NA";
1225 	case QDF_PROTO_MGMT_ASSOC:
1226 		return "ASSOC";
1227 	case QDF_PROTO_MGMT_DISASSOC:
1228 		return "DISASSOC";
1229 	case QDF_PROTO_MGMT_AUTH:
1230 		return "AUTH";
1231 	case QDF_PROTO_MGMT_DEAUTH:
1232 		return "DEAUTH";
1233 	case QDF_ROAM_SYNCH:
1234 		return "ROAM SYNCH";
1235 	case QDF_ROAM_COMPLETE:
1236 		return "ROAM COMP";
1237 	case QDF_ROAM_EVENTID:
1238 		return "ROAM EVENTID";
1239 	default:
1240 		return "invalid";
1241 	}
1242 }
1243 
1244 /**
1245  * qdf_dp_enable_check() - check if dptrace, TX/RX tracing is enabled
1246  * @nbuf: nbuf
1247  * @code: dptrace code
1248  * @dir: TX or RX direction
1249  *
1250  * Return: true/false
1251  */
1252 static bool qdf_dp_enable_check(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
1253 				enum qdf_proto_dir dir)
1254 {
1255 	/* Return when Dp trace is not enabled */
1256 	if (!g_qdf_dp_trace_data.enable)
1257 		return false;
1258 
1259 	if (qdf_dp_trace_verbosity_check(code) == false)
1260 		return false;
1261 
1262 	if (nbuf && (dir == QDF_TX && ((QDF_NBUF_CB_TX_DP_TRACE(nbuf) == 0) ||
1263 				       (QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) !=
1264 					QDF_NBUF_TX_PKT_DATA_TRACK))))
1265 		return false;
1266 
1267 	if (nbuf && (dir == QDF_RX && (QDF_NBUF_CB_RX_DP_TRACE(nbuf) == 0)))
1268 		return false;
1269 
1270 	/*
1271 	 * Special packets called with NULL nbuf and this API is expected to
1272 	 * return true
1273 	 */
1274 	return true;
1275 }
1276 
1277 /**
1278  * qdf_dp_trace_fill_meta_str() - fill up a common meta string
1279  * @prepend_str: pointer to string
1280  * @size: size of prepend_str
1281  * @rec_index: index of record
1282  * @info: info related to the record
1283  * @record: pointer to the record
1284  *
1285  * Return: ret value from scnprintf
1286  */
1287 static inline
1288 int qdf_dp_trace_fill_meta_str(char *prepend_str, int size,
1289 			       int rec_index, uint8_t info,
1290 			       struct qdf_dp_trace_record_s *record)
1291 {
1292 	char buffer[20];
1293 	int ret = 0;
1294 	bool live = info & QDF_DP_TRACE_RECORD_INFO_LIVE ? true : false;
1295 	bool throttled = info & QDF_DP_TRACE_RECORD_INFO_THROTTLED ?
1296 								true : false;
1297 
1298 	scnprintf(buffer, sizeof(buffer), "%llu", record->time);
1299 	ret = scnprintf(prepend_str, size,
1300 			"%s DPT: %04d:%02d%s %s",
1301 			throttled ? "*" : "",
1302 			rec_index,
1303 			record->pdev_id,
1304 			live ? "" : buffer,
1305 			qdf_dp_code_to_string(record->code));
1306 
1307 	return ret;
1308 }
1309 
1310 /**
1311  * qdf_dp_fill_record_data() - fill meta data and data into the record
1312  * @rec: pointer to record data
1313  * @data: pointer to data
1314  * @data_size: size of the data
1315  * @meta_data: pointer to metadata
1316  * @metadata_size: size of metadata
1317  *
1318  * Should be called from within a spin_lock for the qdf record.
1319  * Fills up rec->data with |metadata|data|
1320  *
1321  * Return: none
1322  */
1323 static void qdf_dp_fill_record_data
1324 	(struct qdf_dp_trace_record_s *rec,
1325 	uint8_t *data, uint8_t data_size,
1326 	uint8_t *meta_data, uint8_t metadata_size)
1327 {
1328 	int32_t available = QDF_DP_TRACE_RECORD_SIZE;
1329 	uint8_t *rec_data = rec->data;
1330 	uint8_t data_to_copy = 0;
1331 
1332 	qdf_mem_zero(rec_data, QDF_DP_TRACE_RECORD_SIZE);
1333 
1334 	/* copy meta data */
1335 	if (meta_data) {
1336 		if (metadata_size > available) {
1337 			QDF_TRACE_WARN(QDF_MODULE_ID_QDF,
1338 				       "%s: meta data does not fit into the record",
1339 				       __func__);
1340 			goto end;
1341 		}
1342 		qdf_mem_copy(rec_data, meta_data, metadata_size);
1343 		available = available - metadata_size;
1344 	} else {
1345 		metadata_size = 0;
1346 	}
1347 
1348 	/* copy data */
1349 	if (data && (data_size > 0) && (available > 0)) {
1350 		data_to_copy = data_size;
1351 		if (data_size > available)
1352 			data_to_copy = available;
1353 		qdf_mem_copy(&rec_data[metadata_size], data, data_to_copy);
1354 	}
1355 end:
1356 	rec->size = data_to_copy;
1357 }
1358 
1359 /**
1360  * qdf_dp_add_record() - add dp trace record
1361  * @code: dptrace code
1362  * @pdev_id: pdev_id
1363  * @print: true to print it in kmsg
1364  * @data: data pointer
1365  * @data_size: size of data to be copied
1366  * @meta_data: meta data to be prepended to data
1367  * @metadata_size: sizeof meta data
1368  * @print: whether to print record
1369  *
1370  * Return: none
1371  */
1372 static void qdf_dp_add_record(enum QDF_DP_TRACE_ID code, uint8_t pdev_id,
1373 			      uint8_t *data, uint8_t data_size,
1374 			      uint8_t *meta_data, uint8_t metadata_size,
1375 			      bool print)
1376 
1377 {
1378 	struct qdf_dp_trace_record_s *rec = NULL;
1379 	int index;
1380 	bool print_this_record = false;
1381 	u8 info = 0;
1382 
1383 	if (code >= QDF_DP_TRACE_MAX) {
1384 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
1385 				"invalid record code %u, max code %u",
1386 				code, QDF_DP_TRACE_MAX);
1387 		return;
1388 	}
1389 
1390 	spin_lock_bh(&l_dp_trace_lock);
1391 
1392 	if (print || g_qdf_dp_trace_data.force_live_mode) {
1393 		print_this_record = true;
1394 	} else if (g_qdf_dp_trace_data.live_mode == 1) {
1395 		print_this_record = true;
1396 		g_qdf_dp_trace_data.print_pkt_cnt++;
1397 		if (g_qdf_dp_trace_data.print_pkt_cnt >
1398 				g_qdf_dp_trace_data.high_tput_thresh) {
1399 			g_qdf_dp_trace_data.live_mode = 0;
1400 			g_qdf_dp_trace_data.verbosity =
1401 					QDF_DP_TRACE_VERBOSITY_ULTRA_LOW;
1402 			info |= QDF_DP_TRACE_RECORD_INFO_THROTTLED;
1403 		}
1404 	}
1405 
1406 	g_qdf_dp_trace_data.num++;
1407 
1408 	if (g_qdf_dp_trace_data.num > MAX_QDF_DP_TRACE_RECORDS)
1409 		g_qdf_dp_trace_data.num = MAX_QDF_DP_TRACE_RECORDS;
1410 
1411 	if (INVALID_QDF_DP_TRACE_ADDR == g_qdf_dp_trace_data.head) {
1412 		/* first record */
1413 		g_qdf_dp_trace_data.head = 0;
1414 		g_qdf_dp_trace_data.tail = 0;
1415 	} else {
1416 		/* queue is not empty */
1417 		g_qdf_dp_trace_data.tail++;
1418 
1419 		if (MAX_QDF_DP_TRACE_RECORDS == g_qdf_dp_trace_data.tail)
1420 			g_qdf_dp_trace_data.tail = 0;
1421 
1422 		if (g_qdf_dp_trace_data.head == g_qdf_dp_trace_data.tail) {
1423 			/* full */
1424 			if (MAX_QDF_DP_TRACE_RECORDS ==
1425 				++g_qdf_dp_trace_data.head)
1426 				g_qdf_dp_trace_data.head = 0;
1427 		}
1428 	}
1429 
1430 	rec = &g_qdf_dp_trace_tbl[g_qdf_dp_trace_data.tail];
1431 	index = g_qdf_dp_trace_data.tail;
1432 	rec->code = code;
1433 	rec->pdev_id = pdev_id;
1434 	rec->size = 0;
1435 	qdf_dp_fill_record_data(rec, data, data_size,
1436 				meta_data, metadata_size);
1437 	rec->time = qdf_get_log_timestamp();
1438 	rec->pid = (in_interrupt() ? 0 : current->pid);
1439 
1440 	if (rec->code >= QDF_DP_TRACE_MAX) {
1441 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
1442 				"invalid record code %u, max code %u",
1443 				rec->code, QDF_DP_TRACE_MAX);
1444 		return;
1445 	}
1446 
1447 	spin_unlock_bh(&l_dp_trace_lock);
1448 
1449 	info |= QDF_DP_TRACE_RECORD_INFO_LIVE;
1450 	if (print_this_record)
1451 		qdf_dp_trace_cb_table[rec->code] (rec, index,
1452 					QDF_TRACE_DEFAULT_PDEV_ID, info);
1453 }
1454 
1455 /**
1456  * qdf_get_rate_limit_by_type() - Get the rate limit by pkt type
1457  * @type: packet type
1458  *
1459  * Return: Rate limit value for a particular packet type
1460  */
1461 static inline
1462 uint8_t qdf_get_rate_limit_by_type(uint8_t type)
1463 {
1464 	switch (type) {
1465 	case QDF_PROTO_TYPE_DHCP:
1466 		return QDF_MAX_DHCP_PKTS_PER_SEC;
1467 	case QDF_PROTO_TYPE_EAPOL:
1468 		return QDF_MAX_EAPOL_PKTS_PER_SEC;
1469 	case QDF_PROTO_TYPE_ARP:
1470 		return QDF_MAX_ARP_PKTS_PER_SEC;
1471 	case QDF_PROTO_TYPE_DNS:
1472 		return QDF_MAX_DNS_PKTS_PER_SEC;
1473 	default:
1474 		return QDF_MAX_OTHER_PKTS_PER_SEC;
1475 	}
1476 }
1477 
1478 /**
1479  * qdf_get_pkt_type_string() - Get the string based on pkt type
1480  * @type: packet type
1481  * @subtype: packet subtype
1482  *
1483  * Return: String based on pkt type
1484  */
1485 static
1486 uint8_t *qdf_get_pkt_type_string(uint8_t type, uint8_t subtype)
1487 {
1488 	switch (subtype) {
1489 	case QDF_PROTO_EAPOL_M1:
1490 		return "EAPOL-1";
1491 	case QDF_PROTO_EAPOL_M2:
1492 		return "EAPOL-2";
1493 	case QDF_PROTO_EAPOL_M3:
1494 		return "EAPOL-3";
1495 	case QDF_PROTO_EAPOL_M4:
1496 		return "EAPOL-4";
1497 	case QDF_PROTO_DHCP_DISCOVER:
1498 		return "DHCP-D";
1499 	case QDF_PROTO_DHCP_REQUEST:
1500 		return "DHCP-R";
1501 	case QDF_PROTO_DHCP_OFFER:
1502 		return "DHCP-O";
1503 	case QDF_PROTO_DHCP_ACK:
1504 		return "DHCP-A";
1505 	case QDF_PROTO_DHCP_NACK:
1506 		return "DHCP-NA";
1507 	case QDF_PROTO_DHCP_RELEASE:
1508 		return "DHCP-REL";
1509 	case QDF_PROTO_DHCP_INFORM:
1510 		return "DHCP-IN";
1511 	case QDF_PROTO_DHCP_DECLINE:
1512 		return "DHCP-DEC";
1513 	case QDF_PROTO_ARP_REQ:
1514 		return "ARP-RQ";
1515 	case QDF_PROTO_ARP_RES:
1516 		return "ARP-RS";
1517 	case QDF_PROTO_DNS_QUERY:
1518 		return "DNS_Q";
1519 	case QDF_PROTO_DNS_RES:
1520 		return "DNS_RS";
1521 	default:
1522 		switch (type) {
1523 		case QDF_PROTO_TYPE_EAPOL:
1524 			return "EAP";
1525 		case QDF_PROTO_TYPE_DHCP:
1526 			return "DHCP";
1527 		case QDF_PROTO_TYPE_ARP:
1528 			return "ARP";
1529 		case QDF_PROTO_TYPE_DNS:
1530 			return "DNS";
1531 		default:
1532 			return "UNKNOWN";
1533 		}
1534 	}
1535 }
1536 
1537 /**
1538  * qdf_get_pkt_status_string() - Get the string based on pkt status
1539  * @status: packet status
1540  *
1541  * Return: String based on pkt status
1542  */
1543 static
1544 uint8_t *qdf_get_pkt_status_string(uint8_t status)
1545 {
1546 	switch (status) {
1547 	case QDF_TX_RX_STATUS_INVALID:
1548 		return "inv";
1549 	case QDF_TX_RX_STATUS_OK:
1550 		return "succ";
1551 	case QDF_TX_RX_STATUS_FW_DISCARD:
1552 		return "disc";
1553 	case QDF_TX_RX_STATUS_NO_ACK:
1554 		return "nack";
1555 	case QDF_TX_RX_STATUS_DROP:
1556 		return "drop";
1557 	default:
1558 		return "unknown";
1559 	}
1560 }
1561 
1562 /**
1563  * qdf_dp_log_proto_pkt_info() - Send diag log with pkt info
1564  * @sa: Source MAC address
1565  * @da: Destination MAC address
1566  * @type: packet type
1567  * @subtype: packet subtype
1568  * @dir: tx or rx
1569  * @msdu_id: MSDU id
1570  * @status: status code
1571  *
1572  * Return: none
1573  */
1574 void qdf_dp_log_proto_pkt_info(uint8_t *sa, uint8_t *da, uint8_t type,
1575 			       uint8_t subtype, uint8_t dir, uint16_t msdu_id,
1576 			       uint8_t status)
1577 {
1578 	uint8_t pkt_rate_limit;
1579 	static ulong last_ticks_tx[QDF_PROTO_SUBTYPE_MAX] = {0};
1580 	static ulong last_ticks_rx[QDF_PROTO_SUBTYPE_MAX] = {0};
1581 	ulong curr_ticks = jiffies;
1582 
1583 	pkt_rate_limit = qdf_get_rate_limit_by_type(type);
1584 
1585 	if ((dir == QDF_TX &&
1586 	     !time_after(curr_ticks,
1587 			 last_ticks_tx[subtype] + HZ / pkt_rate_limit)) ||
1588 	    (dir == QDF_RX &&
1589 	     !time_after(curr_ticks,
1590 			 last_ticks_rx[subtype] + HZ / pkt_rate_limit)))
1591 		return;
1592 
1593 	if (dir == QDF_TX)
1594 		last_ticks_tx[subtype] = curr_ticks;
1595 	else
1596 		last_ticks_rx[subtype] = curr_ticks;
1597 
1598 	if (status == QDF_TX_RX_STATUS_INVALID)
1599 		qdf_nofl_info("%s %s: SA:" QDF_MAC_ADDR_FMT " DA:" QDF_MAC_ADDR_FMT,
1600 			      qdf_get_pkt_type_string(type, subtype),
1601 			      dir ? "RX" : "TX", QDF_MAC_ADDR_REF(sa),
1602 			      QDF_MAC_ADDR_REF(da));
1603 	else
1604 		qdf_nofl_info("%s %s: SA:" QDF_MAC_ADDR_FMT " DA:" QDF_MAC_ADDR_FMT " msdu_id:%d status: %s",
1605 			      qdf_get_pkt_type_string(type, subtype),
1606 			      dir ? "RX" : "TX", QDF_MAC_ADDR_REF(sa),
1607 			      QDF_MAC_ADDR_REF(da), msdu_id,
1608 			      qdf_get_pkt_status_string(status));
1609 }
1610 
1611 qdf_export_symbol(qdf_dp_log_proto_pkt_info);
1612 
1613 /**
1614  * qdf_log_icmpv6_pkt() - log ICMPv6 packet
1615  * @vdev_id: ID of the vdev
1616  * @skb: skb pointer
1617  * @dir: direction
1618  * @pdev_id: ID of the pdev
1619  *
1620  * Return: true/false
1621  */
1622 static bool qdf_log_icmpv6_pkt(uint8_t vdev_id, struct sk_buff *skb,
1623 			       enum qdf_proto_dir dir, uint8_t pdev_id)
1624 {
1625 	enum qdf_proto_subtype subtype;
1626 
1627 	if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMPv6) &&
1628 		((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ICMPv6 ==
1629 			QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
1630 		 (dir == QDF_RX && qdf_nbuf_is_icmpv6_pkt(skb) == true))) {
1631 
1632 		subtype = qdf_nbuf_get_icmpv6_subtype(skb);
1633 
1634 		QDF_NBUF_CB_DP_TRACE_PRINT(skb) = false;
1635 		if (dir == QDF_TX)
1636 			QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
1637 		else if (dir == QDF_RX)
1638 			QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
1639 
1640 		DPTRACE(qdf_dp_trace_proto_pkt(
1641 			QDF_DP_TRACE_ICMPv6_PACKET_RECORD,
1642 			vdev_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
1643 			(skb->data + QDF_NBUF_DEST_MAC_OFFSET),
1644 			QDF_PROTO_TYPE_ICMPv6, subtype, dir, pdev_id, false, 0));
1645 
1646 		switch (subtype) {
1647 		case QDF_PROTO_ICMPV6_REQ:
1648 			g_qdf_dp_trace_data.icmpv6_req++;
1649 			break;
1650 		case QDF_PROTO_ICMPV6_RES:
1651 			g_qdf_dp_trace_data.icmpv6_resp++;
1652 			break;
1653 		case QDF_PROTO_ICMPV6_RS:
1654 			g_qdf_dp_trace_data.icmpv6_rs++;
1655 			break;
1656 		case QDF_PROTO_ICMPV6_RA:
1657 			g_qdf_dp_trace_data.icmpv6_ra++;
1658 			break;
1659 		case QDF_PROTO_ICMPV6_NS:
1660 			g_qdf_dp_trace_data.icmpv6_ns++;
1661 			break;
1662 		case QDF_PROTO_ICMPV6_NA:
1663 			g_qdf_dp_trace_data.icmpv6_na++;
1664 			break;
1665 		default:
1666 			break;
1667 		}
1668 		return true;
1669 	}
1670 
1671 	return false;
1672 }
1673 
1674 /**
1675  * qdf_log_icmp_pkt() - log ICMP packet
1676  * @vdev_id: ID of the vdev
1677  * @skb: skb pointer
1678  * @dir: direction
1679  * @pdev_id: ID of the pdev
1680  *
1681  * Return: true/false
1682  */
1683 static bool qdf_log_icmp_pkt(uint8_t vdev_id, struct sk_buff *skb,
1684 			     enum qdf_proto_dir dir, uint8_t pdev_id)
1685 {
1686 	enum qdf_proto_subtype proto_subtype;
1687 	uint8_t *data = NULL;
1688 	uint16_t seq_num = 0;
1689 	uint16_t icmp_id = 0;
1690 	uint32_t proto_priv_data = 0;
1691 
1692 	if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMP) &&
1693 	    (qdf_nbuf_is_icmp_pkt(skb) == true)) {
1694 
1695 		QDF_NBUF_CB_DP_TRACE_PRINT(skb) = false;
1696 		proto_subtype = qdf_nbuf_get_icmp_subtype(skb);
1697 
1698 		data = qdf_nbuf_data(skb);
1699 		icmp_id = qdf_cpu_to_be16(*(uint16_t *)(data + ICMP_ID_OFFSET));
1700 		seq_num = qdf_cpu_to_be16(*(uint16_t *)(data + ICMP_SEQ_NUM_OFFSET));
1701 
1702 		proto_priv_data |= ((proto_priv_data | ((uint32_t)icmp_id)) << 16);
1703 		proto_priv_data |= (uint32_t)seq_num;
1704 
1705 		if (QDF_TX == dir)
1706 			QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
1707 		else if (QDF_RX == dir)
1708 			QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
1709 
1710 		DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ICMP_PACKET_RECORD,
1711 					       vdev_id,
1712 					       skb->data +
1713 					       QDF_NBUF_SRC_MAC_OFFSET,
1714 					       skb->data +
1715 					       QDF_NBUF_DEST_MAC_OFFSET,
1716 					       QDF_PROTO_TYPE_ICMP,
1717 					       proto_subtype, dir, pdev_id,
1718 					       false, proto_priv_data));
1719 
1720 		if (proto_subtype == QDF_PROTO_ICMP_REQ)
1721 			g_qdf_dp_trace_data.icmp_req++;
1722 		else
1723 			g_qdf_dp_trace_data.icmp_resp++;
1724 
1725 		return true;
1726 	}
1727 	return false;
1728 }
1729 
1730 #ifdef CONNECTIVITY_DIAG_EVENT
1731 enum diag_tx_status wlan_get_diag_tx_status(enum qdf_dp_tx_rx_status tx_status)
1732 {
1733 	switch (tx_status) {
1734 	case DIAG_TX_RX_STATUS_FW_DISCARD:
1735 	case DIAG_TX_RX_STATUS_INVALID:
1736 	case DIAG_TX_RX_STATUS_DROP:
1737 	case DIAG_TX_RX_STATUS_DOWNLOAD_SUCC:
1738 	case DIAG_TX_RX_STATUS_DEFAULT:
1739 	default:
1740 		return DIAG_TX_STATUS_FAIL;
1741 	case DIAG_TX_RX_STATUS_NO_ACK:
1742 		return DIAG_TX_STATUS_NO_ACK;
1743 	case DIAG_TX_RX_STATUS_OK:
1744 		return DIAG_TX_STATUS_ACK;
1745 	}
1746 
1747 	return DIAG_TX_STATUS_FAIL;
1748 }
1749 
1750 /**
1751  * qdf_subtype_to_wlan_main_tag() - Convert qdf subtype to wlan main tag
1752  * @subtype: EAPoL key subtype
1753  *
1754  * Return: Wlan main tag subtype
1755  */
1756 static int qdf_subtype_to_wlan_main_tag(enum qdf_proto_subtype subtype)
1757 {
1758 	switch (subtype) {
1759 	case QDF_PROTO_DHCP_DISCOVER:
1760 		return WLAN_CONN_DIAG_DHCP_DISC_EVENT;
1761 	case QDF_PROTO_DHCP_REQUEST:
1762 		return WLAN_CONN_DIAG_DHCP_REQUEST_EVENT;
1763 	case QDF_PROTO_DHCP_OFFER:
1764 		return WLAN_CONN_DIAG_DHCP_OFFER_EVENT;
1765 	case QDF_PROTO_DHCP_ACK:
1766 		return WLAN_CONN_DIAG_DHCP_ACK_EVENT;
1767 	case QDF_PROTO_DHCP_NACK:
1768 		return WLAN_CONN_DIAG_DHCP_NACK_EVENT;
1769 	case QDF_PROTO_EAPOL_M1:
1770 		return WLAN_CONN_DIAG_EAPOL_M1_EVENT;
1771 	case QDF_PROTO_EAPOL_M2:
1772 		return WLAN_CONN_DIAG_EAPOL_M2_EVENT;
1773 	case QDF_PROTO_EAPOL_M3:
1774 		return WLAN_CONN_DIAG_EAPOL_M3_EVENT;
1775 	case QDF_PROTO_EAPOL_M4:
1776 		return WLAN_CONN_DIAG_EAPOL_M4_EVENT;
1777 	default:
1778 		return WLAN_CONN_DIAG_MAX;
1779 	}
1780 }
1781 
1782 /**
1783  * qdf_get_wlan_eap_code() - Get EAP code
1784  * @data: skb data pointer
1785  *
1786  * Return: EAP code value
1787  */
1788 static int qdf_get_wlan_eap_code(uint8_t *data)
1789 {
1790 	uint8_t code = *(data + EAP_CODE_OFFSET);
1791 
1792 	switch (code) {
1793 	case QDF_EAP_REQUEST:
1794 		return WLAN_CONN_DIAG_EAP_REQ_EVENT;
1795 	case QDF_EAP_RESPONSE:
1796 		return WLAN_CONN_DIAG_EAP_RESP_EVENT;
1797 	case QDF_EAP_SUCCESS:
1798 		return WLAN_CONN_DIAG_EAP_SUCC_EVENT;
1799 	case QDF_EAP_FAILURE:
1800 		return WLAN_CONN_DIAG_EAP_FAIL_EVENT;
1801 	default:
1802 		return WLAN_CONN_DIAG_MAX;
1803 	}
1804 }
1805 
1806 /**
1807  * qdf_eapol_get_key_type() - Get EAPOL key type
1808  * @data: skb data pointer
1809  * @subtype: EAPoL key subtype
1810  *
1811  * Return: EAPOL key type
1812  */
1813 static
1814 uint8_t qdf_eapol_get_key_type(uint8_t *data, enum qdf_proto_subtype subtype)
1815 {
1816 	uint16_t key_info = *(uint16_t *)(data + EAPOL_KEY_INFO_OFFSET);
1817 
1818 	/* If key type is PTK, key type will be set in EAPOL Key info */
1819 	if (key_info & EAPOL_KEY_TYPE_MASK)
1820 		return qdf_subtype_to_wlan_main_tag(subtype);
1821 	else if (key_info & EAPOL_KEY_ENCRYPTED_MASK)
1822 		return WLAN_CONN_DIAG_GTK_M1_EVENT;
1823 	else
1824 		return WLAN_CONN_DIAG_GTK_M2_EVENT;
1825 }
1826 
1827 /**
1828  * qdf_skip_wlan_connectivity_log() - Check if connectivity log need to skip
1829  * @type: Protocol type
1830  * @subtype: Protocol subtype
1831  * @dir: Rx or Tx
1832  *
1833  * Return: true or false
1834  */
1835 static inline
1836 bool qdf_skip_wlan_connectivity_log(enum qdf_proto_type type,
1837 				    enum qdf_proto_subtype subtype,
1838 				    enum qdf_proto_dir dir)
1839 {
1840 	if (dir == QDF_RX && type == QDF_PROTO_TYPE_DHCP &&
1841 	    (subtype == QDF_PROTO_DHCP_DISCOVER ||
1842 	     subtype == QDF_PROTO_DHCP_REQUEST))
1843 		return true;
1844 	return false;
1845 }
1846 
1847 /**
1848  * qdf_fill_wlan_connectivity_log() - Fill and queue protocol packet to logging
1849  * the logging queue
1850  * @type: Protocol type
1851  * @subtype: Protocol subtype
1852  * @dir: Rx or Tx
1853  * @qdf_tx_status: Tx completion status
1854  * @vdev_id: DP vdev ID
1855  * @data: skb data pointer
1856  *
1857  * Return: None
1858  */
1859 static
1860 void qdf_fill_wlan_connectivity_log(enum qdf_proto_type type,
1861 				    enum qdf_proto_subtype subtype,
1862 				    enum qdf_proto_dir dir,
1863 				    enum qdf_dp_tx_rx_status qdf_tx_status,
1864 				    uint8_t vdev_id, uint8_t *data)
1865 {
1866 	uint8_t pkt_type;
1867 
1868 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info);
1869 
1870 	if (qdf_skip_wlan_connectivity_log(type, subtype, dir))
1871 		return;
1872 
1873 	qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event));
1874 
1875 	wlan_diag_event.diag_cmn.timestamp_us =
1876 					qdf_get_time_of_the_day_ms() * 1000;
1877 	wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
1878 	wlan_diag_event.diag_cmn.vdev_id = vdev_id;
1879 
1880 	wlan_diag_event.version = DIAG_MGMT_VERSION;
1881 
1882 	if (type == QDF_PROTO_TYPE_DHCP) {
1883 		wlan_diag_event.subtype =
1884 					qdf_subtype_to_wlan_main_tag(subtype);
1885 	} else if (type == QDF_PROTO_TYPE_EAPOL) {
1886 		pkt_type = *(data + EAPOL_PACKET_TYPE_OFFSET);
1887 		if (pkt_type == EAPOL_PACKET_TYPE_EAP) {
1888 			wlan_diag_event.subtype =
1889 						qdf_get_wlan_eap_code(data);
1890 			wlan_diag_event.eap_type =
1891 						*(data + EAP_TYPE_OFFSET);
1892 			wlan_diag_event.eap_len =
1893 			   qdf_ntohs(*(uint16_t *)(data + EAP_LENGTH_OFFSET));
1894 		} else if (pkt_type == EAPOL_PACKET_TYPE_KEY) {
1895 			wlan_diag_event.subtype =
1896 					qdf_eapol_get_key_type(data, subtype);
1897 		} else if (pkt_type == EAPOL_PACKET_TYPE_START) {
1898 			wlan_diag_event.subtype =
1899 					WLAN_CONN_DIAG_EAP_START_EVENT;
1900 			wlan_diag_event.eap_len =
1901 			    qdf_ntohs(*(uint16_t *)(data + EAPOL_PKT_LEN_OFFSET));
1902 		} else {
1903 			return;
1904 		}
1905 	} else {
1906 		return;
1907 	}
1908 
1909 	/*Tx completion status needs to be logged*/
1910 	if (dir == QDF_TX)
1911 		wlan_diag_event.tx_status =
1912 					wlan_get_diag_tx_status(qdf_tx_status);
1913 
1914 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_CONN_DP);
1915 }
1916 
1917 #elif defined(WLAN_FEATURE_CONNECTIVITY_LOGGING)
1918 /**
1919  * qdf_subtype_to_wlan_main_tag() - Convert qdf subtype to wlan main tag
1920  * @subtype: EAPoL key subtype
1921  *
1922  * Return: Wlan main tag subtype
1923  */
1924 static int qdf_subtype_to_wlan_main_tag(enum qdf_proto_subtype subtype)
1925 {
1926 	switch (subtype) {
1927 	case QDF_PROTO_DHCP_DISCOVER:
1928 		return WLAN_DHCP_DISCOVER;
1929 	case QDF_PROTO_DHCP_REQUEST:
1930 		return WLAN_DHCP_REQUEST;
1931 	case QDF_PROTO_DHCP_OFFER:
1932 		return WLAN_DHCP_OFFER;
1933 	case QDF_PROTO_DHCP_ACK:
1934 		return WLAN_DHCP_ACK;
1935 	case QDF_PROTO_DHCP_NACK:
1936 		return WLAN_DHCP_NACK;
1937 	case QDF_PROTO_EAPOL_M1:
1938 		return WLAN_EAPOL_M1;
1939 	case QDF_PROTO_EAPOL_M2:
1940 		return WLAN_EAPOL_M2;
1941 	case QDF_PROTO_EAPOL_M3:
1942 		return WLAN_EAPOL_M3;
1943 	case QDF_PROTO_EAPOL_M4:
1944 		return WLAN_EAPOL_M4;
1945 	default:
1946 		return WLAN_TAG_MAX;
1947 	}
1948 }
1949 
1950 /**
1951  * qdf_get_wlan_eap_code() - Get EAP code
1952  * @data: skb data pointer
1953  *
1954  * Return: EAP code value
1955  */
1956 static int qdf_get_wlan_eap_code(uint8_t *data)
1957 {
1958 	uint8_t code = *(data + EAP_CODE_OFFSET);
1959 
1960 	switch (code) {
1961 	case QDF_EAP_REQUEST:
1962 		return WLAN_EAP_REQUEST;
1963 	case QDF_EAP_RESPONSE:
1964 		return WLAN_EAP_RESPONSE;
1965 	case QDF_EAP_SUCCESS:
1966 		return WLAN_EAP_SUCCESS;
1967 	case QDF_EAP_FAILURE:
1968 		return WLAN_EAP_FAILURE;
1969 	default:
1970 		return WLAN_TAG_MAX;
1971 	}
1972 }
1973 
1974 /**
1975  * qdf_eapol_get_key_type() - Get EAPOL key type
1976  * @data: skb data pointer
1977  * @subtype: EAPoL key subtype
1978  *
1979  * Return: EAPOL key type
1980  */
1981 static
1982 uint8_t qdf_eapol_get_key_type(uint8_t *data, enum qdf_proto_subtype subtype)
1983 {
1984 	uint16_t key_info = *(uint16_t *)(data + EAPOL_KEY_INFO_OFFSET);
1985 
1986 	/* If key type is PTK, key type will be set in EAPOL Key info */
1987 	if (key_info & EAPOL_KEY_TYPE_MASK)
1988 		return qdf_subtype_to_wlan_main_tag(subtype);
1989 	else if (key_info & EAPOL_KEY_ENCRYPTED_MASK)
1990 		return WLAN_GTK_M1;
1991 	else
1992 		return WLAN_GTK_M2;
1993 }
1994 
1995 /**
1996  * qdf_skip_wlan_connectivity_log() - Check if connectivity log need to skip
1997  * @type: Protocol type
1998  * @subtype: Protocol subtype
1999  * @dir: Rx or Tx
2000  *
2001  * Return: true or false
2002  */
2003 static inline
2004 bool qdf_skip_wlan_connectivity_log(enum qdf_proto_type type,
2005 				    enum qdf_proto_subtype subtype,
2006 				    enum qdf_proto_dir dir)
2007 {
2008 	if ((dir == QDF_RX) && (type == QDF_PROTO_TYPE_DHCP) &&
2009 	    ((subtype == QDF_PROTO_DHCP_DISCOVER) ||
2010 	     (subtype == QDF_PROTO_DHCP_REQUEST)))
2011 		return true;
2012 	return false;
2013 }
2014 
2015 static
2016 void qdf_fill_wlan_connectivity_log(enum qdf_proto_type type,
2017 				    enum qdf_proto_subtype subtype,
2018 				    enum qdf_proto_dir dir,
2019 				    enum qdf_dp_tx_rx_status qdf_tx_status,
2020 				    uint8_t vdev_id, uint8_t *data)
2021 {
2022 	struct wlan_log_record log_buf = {0};
2023 	uint8_t pkt_type;
2024 
2025 	if (qdf_skip_wlan_connectivity_log(type, subtype, dir))
2026 		return;
2027 
2028 	log_buf.timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
2029 	log_buf.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
2030 	log_buf.vdev_id = vdev_id;
2031 	if (type == QDF_PROTO_TYPE_DHCP) {
2032 		log_buf.log_subtype = qdf_subtype_to_wlan_main_tag(subtype);
2033 	} else if (type == QDF_PROTO_TYPE_EAPOL) {
2034 		pkt_type = *(data + EAPOL_PACKET_TYPE_OFFSET);
2035 		if (pkt_type == EAPOL_PACKET_TYPE_EAP) {
2036 			log_buf.log_subtype = qdf_get_wlan_eap_code(data);
2037 			log_buf.pkt_info.eap_type = *(data + EAP_TYPE_OFFSET);
2038 			log_buf.pkt_info.eap_len =
2039 			   qdf_ntohs(*(uint16_t *)(data + EAP_LENGTH_OFFSET));
2040 		} else if (pkt_type == EAPOL_PACKET_TYPE_KEY) {
2041 			log_buf.log_subtype = qdf_eapol_get_key_type(data,
2042 								     subtype);
2043 		} else {
2044 			return;
2045 		}
2046 	} else {
2047 		return;
2048 	}
2049 
2050 	/*Tx completion status needs to be logged*/
2051 	if (dir == QDF_TX)
2052 		log_buf.pkt_info.tx_status = qdf_tx_status;
2053 
2054 	wlan_connectivity_log_enqueue(&log_buf);
2055 }
2056 
2057 #else
2058 static inline
2059 void qdf_fill_wlan_connectivity_log(enum qdf_proto_type type,
2060 				    enum qdf_proto_subtype subtype,
2061 				    enum qdf_proto_dir dir,
2062 				    enum qdf_dp_tx_rx_status qdf_tx_status,
2063 				    uint8_t vdev_id, uint8_t *data)
2064 {
2065 }
2066 #endif
2067 
2068 /**
2069  * qdf_log_eapol_pkt() - log EAPOL packet
2070  * @vdev_id: ID of the vdev
2071  * @skb: skb pointer
2072  * @dir: direction
2073  * @pdev_id: ID of the pdev
2074  *
2075  * Return: true/false
2076  */
2077 static bool qdf_log_eapol_pkt(uint8_t vdev_id, struct sk_buff *skb,
2078 			      enum qdf_proto_dir dir, uint8_t pdev_id)
2079 {
2080 	enum qdf_proto_subtype subtype;
2081 	uint32_t dp_eap_trace;
2082 	uint32_t dp_eap_event;
2083 
2084 	dp_eap_trace = qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
2085 	dp_eap_event = qdf_dp_get_proto_event_bitmap() &
2086 				QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
2087 
2088 	if (!dp_eap_trace && !dp_eap_event)
2089 		return false;
2090 
2091 	if (!((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_EAPOL ==
2092 	       QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
2093 	      (dir == QDF_RX && qdf_nbuf_is_ipv4_eapol_pkt(skb) == true)))
2094 		return false;
2095 
2096 	subtype = qdf_nbuf_get_eapol_subtype(skb);
2097 
2098 	if (dp_eap_event && dir == QDF_RX) {
2099 		qdf_dp_log_proto_pkt_info(skb->data + QDF_NBUF_SRC_MAC_OFFSET,
2100 					  skb->data + QDF_NBUF_DEST_MAC_OFFSET,
2101 					  QDF_PROTO_TYPE_EAPOL, subtype, dir,
2102 					  QDF_TRACE_DEFAULT_MSDU_ID,
2103 					  QDF_TX_RX_STATUS_INVALID);
2104 		qdf_fill_wlan_connectivity_log(QDF_PROTO_TYPE_EAPOL, subtype,
2105 					       QDF_RX, 0, vdev_id, skb->data);
2106 	}
2107 
2108 	if (dp_eap_trace) {
2109 		QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true;
2110 		if (QDF_TX == dir)
2111 			QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
2112 		else if (QDF_RX == dir)
2113 			QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
2114 
2115 		DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_EAPOL_PACKET_RECORD,
2116 					       vdev_id,
2117 					       skb->data +
2118 					       QDF_NBUF_SRC_MAC_OFFSET,
2119 					       skb->data +
2120 					       QDF_NBUF_DEST_MAC_OFFSET,
2121 					       QDF_PROTO_TYPE_EAPOL, subtype,
2122 					       dir, pdev_id, true, 0));
2123 
2124 		switch (subtype) {
2125 		case QDF_PROTO_EAPOL_M1:
2126 			g_qdf_dp_trace_data.eapol_m1++;
2127 			break;
2128 		case QDF_PROTO_EAPOL_M2:
2129 			g_qdf_dp_trace_data.eapol_m2++;
2130 			break;
2131 		case QDF_PROTO_EAPOL_M3:
2132 			g_qdf_dp_trace_data.eapol_m3++;
2133 			break;
2134 		case QDF_PROTO_EAPOL_M4:
2135 			g_qdf_dp_trace_data.eapol_m4++;
2136 			break;
2137 		default:
2138 			g_qdf_dp_trace_data.eapol_others++;
2139 			break;
2140 		}
2141 	}
2142 
2143 	return true;
2144 }
2145 
2146 /**
2147  * qdf_log_dhcp_pkt() - log DHCP packet
2148  * @vdev_id: ID of the vdev
2149  * @skb: skb pointer
2150  * @dir: direction
2151  * @pdev_id: ID of the pdev
2152  *
2153  * Return: true/false
2154  */
2155 static bool qdf_log_dhcp_pkt(uint8_t vdev_id, struct sk_buff *skb,
2156 			     enum qdf_proto_dir dir, uint8_t pdev_id)
2157 {
2158 	enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
2159 	uint32_t dp_dhcp_trace;
2160 	uint32_t dp_dhcp_event;
2161 
2162 	dp_dhcp_trace = qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_DHCP;
2163 	dp_dhcp_event = qdf_dp_get_proto_event_bitmap() &
2164 				QDF_NBUF_PKT_TRAC_TYPE_DHCP;
2165 
2166 	if (!dp_dhcp_trace && !dp_dhcp_event)
2167 		return false;
2168 
2169 	if (!((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
2170 	       QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
2171 	      (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true)))
2172 		return false;
2173 
2174 	subtype = qdf_nbuf_get_dhcp_subtype(skb);
2175 
2176 	if (dp_dhcp_event && dir == QDF_RX) {
2177 		qdf_dp_log_proto_pkt_info(skb->data + QDF_NBUF_SRC_MAC_OFFSET,
2178 					  skb->data + QDF_NBUF_DEST_MAC_OFFSET,
2179 					  QDF_PROTO_TYPE_DHCP, subtype, dir,
2180 					  QDF_TRACE_DEFAULT_MSDU_ID,
2181 					  QDF_TX_RX_STATUS_INVALID);
2182 		qdf_fill_wlan_connectivity_log(QDF_PROTO_TYPE_DHCP, subtype,
2183 					       QDF_RX, 0, vdev_id, 0);
2184 	}
2185 
2186 	if (dp_dhcp_trace) {
2187 		QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true;
2188 		if (QDF_TX == dir)
2189 			QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
2190 		else if (QDF_RX == dir)
2191 			QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
2192 
2193 		DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_DHCP_PACKET_RECORD,
2194 					       vdev_id,
2195 					       skb->data +
2196 					       QDF_NBUF_SRC_MAC_OFFSET,
2197 					       skb->data +
2198 					       QDF_NBUF_DEST_MAC_OFFSET,
2199 					       QDF_PROTO_TYPE_DHCP, subtype,
2200 					       dir, pdev_id, true, 0));
2201 
2202 		switch (subtype) {
2203 		case QDF_PROTO_DHCP_DISCOVER:
2204 			g_qdf_dp_trace_data.dhcp_disc++;
2205 			break;
2206 		case QDF_PROTO_DHCP_OFFER:
2207 			g_qdf_dp_trace_data.dhcp_off++;
2208 			break;
2209 		case QDF_PROTO_DHCP_REQUEST:
2210 			g_qdf_dp_trace_data.dhcp_req++;
2211 			break;
2212 		case QDF_PROTO_DHCP_ACK:
2213 			g_qdf_dp_trace_data.dhcp_ack++;
2214 			break;
2215 		case QDF_PROTO_DHCP_NACK:
2216 			g_qdf_dp_trace_data.dhcp_nack++;
2217 			break;
2218 		default:
2219 			g_qdf_dp_trace_data.eapol_others++;
2220 			break;
2221 		}
2222 	}
2223 
2224 	return true;
2225 }
2226 
2227 /**
2228  * qdf_log_arp_pkt() - log ARP packet
2229  * @vdev_id: ID of the vdev
2230  * @skb: skb pointer
2231  * @dir: direction
2232  * @pdev_id: ID of the pdev
2233  *
2234  * Return: true/false
2235  */
2236 static bool qdf_log_arp_pkt(uint8_t vdev_id, struct sk_buff *skb,
2237 			    enum qdf_proto_dir dir, uint8_t pdev_id)
2238 {
2239 	enum qdf_proto_subtype proto_subtype;
2240 
2241 	if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ARP) &&
2242 		((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ARP ==
2243 			QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
2244 		 (dir == QDF_RX && qdf_nbuf_is_ipv4_arp_pkt(skb) == true))) {
2245 
2246 		proto_subtype = qdf_nbuf_get_arp_subtype(skb);
2247 		QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true;
2248 		if (QDF_TX == dir)
2249 			QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
2250 		else if (QDF_RX == dir)
2251 			QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
2252 
2253 		DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ARP_PACKET_RECORD,
2254 					       vdev_id,
2255 					       skb->data +
2256 					       QDF_NBUF_SRC_MAC_OFFSET,
2257 					       skb->data +
2258 					       QDF_NBUF_DEST_MAC_OFFSET,
2259 					       QDF_PROTO_TYPE_ARP,
2260 					       proto_subtype, dir, pdev_id,
2261 					       true, 0));
2262 
2263 		if (QDF_PROTO_ARP_REQ == proto_subtype)
2264 			g_qdf_dp_trace_data.arp_req++;
2265 		else
2266 			g_qdf_dp_trace_data.arp_resp++;
2267 
2268 		return true;
2269 	}
2270 	return false;
2271 }
2272 
2273 
2274 bool qdf_dp_trace_log_pkt(uint8_t vdev_id, struct sk_buff *skb,
2275 			  enum qdf_proto_dir dir, uint8_t pdev_id)
2276 {
2277 	if (!qdf_dp_get_proto_bitmap() && !qdf_dp_get_proto_event_bitmap())
2278 		return false;
2279 	if (qdf_log_arp_pkt(vdev_id, skb, dir, pdev_id))
2280 		return true;
2281 	if (qdf_log_dhcp_pkt(vdev_id, skb, dir, pdev_id))
2282 		return true;
2283 	if (qdf_log_eapol_pkt(vdev_id, skb, dir, pdev_id))
2284 		return true;
2285 	if (qdf_log_icmp_pkt(vdev_id, skb, dir, pdev_id))
2286 		return true;
2287 	if (qdf_log_icmpv6_pkt(vdev_id, skb, dir, pdev_id))
2288 		return true;
2289 	return false;
2290 }
2291 qdf_export_symbol(qdf_dp_trace_log_pkt);
2292 
2293 void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record,
2294 			      uint16_t index, uint8_t pdev_id, uint8_t info)
2295 {
2296 	int loc;
2297 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2298 	struct qdf_dp_trace_mgmt_buf *buf =
2299 		(struct qdf_dp_trace_mgmt_buf *)record->data;
2300 
2301 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2302 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2303 					 index, info, record);
2304 
2305 	DPTRACE_PRINT("%s [%d] [%s %s]",
2306 		      prepend_str,
2307 		      buf->vdev_id,
2308 		      qdf_dp_type_to_str(buf->type),
2309 		      qdf_dp_subtype_to_str(buf->subtype));
2310 }
2311 qdf_export_symbol(qdf_dp_display_mgmt_pkt);
2312 
2313 
2314 void qdf_dp_trace_mgmt_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id,
2315 		uint8_t pdev_id, enum qdf_proto_type type,
2316 		enum qdf_proto_subtype subtype)
2317 {
2318 	struct qdf_dp_trace_mgmt_buf buf;
2319 	int buf_size = sizeof(struct qdf_dp_trace_mgmt_buf);
2320 
2321 	if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
2322 		return;
2323 
2324 	if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
2325 		QDF_BUG(0);
2326 
2327 	buf.type = type;
2328 	buf.subtype = subtype;
2329 	buf.vdev_id = vdev_id;
2330 	qdf_dp_add_record(code, pdev_id, (uint8_t *)&buf, buf_size,
2331 			  NULL, 0, true);
2332 }
2333 qdf_export_symbol(qdf_dp_trace_mgmt_pkt);
2334 
2335 static void
2336 qdf_dpt_display_credit_record_debugfs(qdf_debugfs_file_t file,
2337 				      struct qdf_dp_trace_record_s *record,
2338 				      uint32_t index)
2339 {
2340 	int loc;
2341 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2342 	struct qdf_dp_trace_credit_record *buf =
2343 		(struct qdf_dp_trace_credit_record *)record->data;
2344 
2345 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2346 					 index, 0, record);
2347 	if (buf->operation == QDF_OP_NA)
2348 		qdf_debugfs_printf(file, "%s [%s] [T: %d G0: %d G1: %d]\n",
2349 				   prepend_str,
2350 				   qdf_dp_credit_source_to_str(buf->source),
2351 				   buf->total_credits, buf->g0_credit,
2352 				   buf->g1_credit);
2353 	else
2354 		qdf_debugfs_printf(file,
2355 				   "%s [%s] [T: %d G0: %d G1: %d] [%s %d]\n",
2356 				   prepend_str,
2357 				   qdf_dp_credit_source_to_str(buf->source),
2358 				   buf->total_credits, buf->g0_credit,
2359 				   buf->g1_credit,
2360 				   qdf_dp_operation_to_str(buf->operation),
2361 				   buf->delta);
2362 }
2363 
2364 void qdf_dp_display_credit_record(struct qdf_dp_trace_record_s *record,
2365 				  uint16_t index, uint8_t pdev_id, uint8_t info)
2366 {
2367 	int loc;
2368 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2369 	struct qdf_dp_trace_credit_record *buf =
2370 		(struct qdf_dp_trace_credit_record *)record->data;
2371 
2372 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2373 					 index, info, record);
2374 	if (buf->operation == QDF_OP_NA)
2375 		DPTRACE_PRINT("%s [%s] [T: %d G0: %d G1: %d]",
2376 			      prepend_str,
2377 			      qdf_dp_credit_source_to_str(buf->source),
2378 			      buf->total_credits, buf->g0_credit,
2379 			      buf->g1_credit);
2380 	else
2381 		DPTRACE_PRINT("%s [%s] [T: %d G0: %d G1: %d] [%s %d]",
2382 			      prepend_str,
2383 			      qdf_dp_credit_source_to_str(buf->source),
2384 			      buf->total_credits, buf->g0_credit,
2385 			      buf->g1_credit,
2386 			      qdf_dp_operation_to_str(buf->operation),
2387 			      buf->delta);
2388 }
2389 
2390 void qdf_dp_trace_credit_record(enum QDF_CREDIT_UPDATE_SOURCE source,
2391 				enum QDF_CREDIT_OPERATION operation,
2392 				int delta, int total_credits,
2393 				int g0_credit, int g1_credit)
2394 {
2395 	struct qdf_dp_trace_credit_record buf;
2396 	int buf_size = sizeof(struct qdf_dp_trace_credit_record);
2397 	enum QDF_DP_TRACE_ID code = QDF_DP_TRACE_TX_CREDIT_RECORD;
2398 
2399 	if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
2400 		return;
2401 
2402 	if (!(qdf_dp_get_proto_bitmap() & QDF_HL_CREDIT_TRACKING))
2403 		return;
2404 
2405 	if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
2406 		QDF_BUG(0);
2407 
2408 	buf.source = source;
2409 	buf.operation = operation;
2410 	buf.delta = delta;
2411 	buf.total_credits = total_credits;
2412 	buf.g0_credit = g0_credit;
2413 	buf.g1_credit = g1_credit;
2414 
2415 	qdf_dp_add_record(code, QDF_TRACE_DEFAULT_PDEV_ID, (uint8_t *)&buf,
2416 			  buf_size, NULL, 0, false);
2417 }
2418 qdf_export_symbol(qdf_dp_trace_credit_record);
2419 
2420 void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record,
2421 			      uint16_t index, uint8_t pdev_id, uint8_t info)
2422 {
2423 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2424 	struct qdf_dp_trace_event_buf *buf =
2425 		(struct qdf_dp_trace_event_buf *)record->data;
2426 
2427 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2428 	qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2429 				   index, info, record);
2430 
2431 	DPTRACE_PRINT("%s [%d] [%s %s]",
2432 		      prepend_str,
2433 		      buf->vdev_id,
2434 		      qdf_dp_type_to_str(buf->type),
2435 		      qdf_dp_subtype_to_str(buf->subtype));
2436 }
2437 qdf_export_symbol(qdf_dp_display_event_record);
2438 
2439 /**
2440  * qdf_dp_trace_record_event() - record events
2441  * @code: dptrace code
2442  * @vdev_id: vdev id
2443  * @pdev_id: pdev_id
2444  * @type: proto type
2445  * @subtype: proto subtype
2446  *
2447  * Return: none
2448  */
2449 void qdf_dp_trace_record_event(enum QDF_DP_TRACE_ID code, uint8_t vdev_id,
2450 		uint8_t pdev_id, enum qdf_proto_type type,
2451 		enum qdf_proto_subtype subtype)
2452 {
2453 	struct qdf_dp_trace_event_buf buf;
2454 	int buf_size = sizeof(struct qdf_dp_trace_event_buf);
2455 
2456 	if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
2457 		return;
2458 
2459 	if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
2460 		QDF_BUG(0);
2461 
2462 	buf.type = type;
2463 	buf.subtype = subtype;
2464 	buf.vdev_id = vdev_id;
2465 	qdf_dp_add_record(code, pdev_id,
2466 			  (uint8_t *)&buf, buf_size, NULL, 0, true);
2467 }
2468 qdf_export_symbol(qdf_dp_trace_record_event);
2469 
2470 
2471 void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record,
2472 			      uint16_t index, uint8_t pdev_id, uint8_t info)
2473 {
2474 	int loc;
2475 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2476 	struct qdf_dp_trace_proto_buf *buf =
2477 		(struct qdf_dp_trace_proto_buf *)record->data;
2478 
2479 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2480 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2481 					 index, info, record);
2482 	DPTRACE_PRINT("%s [%d] [%s] SA: "
2483 		      QDF_MAC_ADDR_FMT " %s DA:"
2484 		      QDF_MAC_ADDR_FMT " proto priv data = %08x",
2485 		      prepend_str,
2486 		      buf->vdev_id,
2487 		      qdf_dp_subtype_to_str(buf->subtype),
2488 		      QDF_MAC_ADDR_REF(buf->sa.bytes),
2489 		      qdf_dp_dir_to_str(buf->dir),
2490 		      QDF_MAC_ADDR_REF(buf->da.bytes),
2491 		      buf->proto_priv_data);
2492 }
2493 qdf_export_symbol(qdf_dp_display_proto_pkt);
2494 
2495 void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id,
2496 		uint8_t *sa, uint8_t *da, enum qdf_proto_type type,
2497 		enum qdf_proto_subtype subtype, enum qdf_proto_dir dir,
2498 		uint8_t pdev_id, bool print, uint32_t proto_priv_data)
2499 {
2500 	struct qdf_dp_trace_proto_buf buf;
2501 	int buf_size = sizeof(struct qdf_dp_trace_proto_buf);
2502 
2503 	if (qdf_dp_enable_check(NULL, code, dir) == false)
2504 		return;
2505 
2506 	if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
2507 		QDF_BUG(0);
2508 
2509 	memcpy(&buf.sa, sa, QDF_NET_ETH_LEN);
2510 	memcpy(&buf.da, da, QDF_NET_ETH_LEN);
2511 	buf.dir = dir;
2512 	buf.type = type;
2513 	buf.subtype = subtype;
2514 	buf.vdev_id = vdev_id;
2515 	buf.proto_priv_data = proto_priv_data;
2516 	qdf_dp_add_record(code, pdev_id,
2517 			  (uint8_t *)&buf, buf_size, NULL, 0, print);
2518 }
2519 qdf_export_symbol(qdf_dp_trace_proto_pkt);
2520 
2521 void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *record,
2522 				uint16_t index, uint8_t pdev_id, uint8_t info)
2523 {
2524 	int loc;
2525 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2526 	struct qdf_dp_trace_ptr_buf *buf =
2527 		(struct qdf_dp_trace_ptr_buf *)record->data;
2528 	bool is_free_pkt_ptr_record = false;
2529 
2530 	if ((record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) ||
2531 	    (record->code == QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD))
2532 		is_free_pkt_ptr_record = true;
2533 
2534 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2535 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2536 					 index, info, record);
2537 
2538 	if (loc < sizeof(prepend_str))
2539 		scnprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
2540 			  "[msdu id %d %s %d]",
2541 			  buf->msdu_id,
2542 			  is_free_pkt_ptr_record ? "status" : "vdev_id",
2543 			  buf->status);
2544 
2545 	if (info & QDF_DP_TRACE_RECORD_INFO_LIVE) {
2546 		/* In live mode donot dump the contents of the cookie */
2547 		DPTRACE_PRINT("%s", prepend_str);
2548 	} else {
2549 		dump_dp_hex_trace(prepend_str, (uint8_t *)&buf->cookie,
2550 			sizeof(buf->cookie));
2551 	}
2552 }
2553 qdf_export_symbol(qdf_dp_display_ptr_record);
2554 
2555 static
2556 enum qdf_proto_type qdf_dp_get_pkt_proto_type(qdf_nbuf_t nbuf)
2557 {
2558 	uint8_t pkt_type;
2559 
2560 	if (!nbuf)
2561 		return QDF_PROTO_TYPE_MAX;
2562 
2563 	if (qdf_nbuf_data_is_dns_query(nbuf) ||
2564 	    qdf_nbuf_data_is_dns_response(nbuf))
2565 		return QDF_PROTO_TYPE_DNS;
2566 
2567 	pkt_type = QDF_NBUF_CB_GET_PACKET_TYPE(nbuf);
2568 
2569 	switch (pkt_type) {
2570 	case QDF_NBUF_CB_PACKET_TYPE_EAPOL:
2571 		return QDF_PROTO_TYPE_EAPOL;
2572 	case QDF_NBUF_CB_PACKET_TYPE_ARP:
2573 		return QDF_PROTO_TYPE_ARP;
2574 	case QDF_NBUF_CB_PACKET_TYPE_DHCP:
2575 		return QDF_PROTO_TYPE_DHCP;
2576 	default:
2577 		return QDF_PROTO_TYPE_MAX;
2578 	}
2579 }
2580 
2581 static
2582 enum qdf_proto_subtype qdf_dp_get_pkt_subtype(qdf_nbuf_t nbuf,
2583 					      enum qdf_proto_type pkt_type)
2584 {
2585 	switch (pkt_type) {
2586 	case QDF_PROTO_TYPE_EAPOL:
2587 		return qdf_nbuf_get_eapol_subtype(nbuf);
2588 	case QDF_PROTO_TYPE_ARP:
2589 		return qdf_nbuf_get_arp_subtype(nbuf);
2590 	case QDF_PROTO_TYPE_DHCP:
2591 		return qdf_nbuf_get_dhcp_subtype(nbuf);
2592 	case QDF_PROTO_TYPE_DNS:
2593 		return (qdf_nbuf_data_is_dns_query(nbuf)) ?
2594 				QDF_PROTO_DNS_QUERY : QDF_PROTO_DNS_RES;
2595 	default:
2596 		return QDF_PROTO_INVALID;
2597 	}
2598 }
2599 
2600 static
2601 bool qdf_dp_proto_log_enable_check(enum qdf_proto_type pkt_type,
2602 				   uint16_t status)
2603 {
2604 	if (pkt_type == QDF_PROTO_TYPE_MAX)
2605 		return false;
2606 
2607 	switch (pkt_type) {
2608 	case QDF_PROTO_TYPE_EAPOL:
2609 		return qdf_dp_get_proto_event_bitmap() &
2610 				QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
2611 	case QDF_PROTO_TYPE_DHCP:
2612 		return qdf_dp_get_proto_event_bitmap() &
2613 				QDF_NBUF_PKT_TRAC_TYPE_DHCP;
2614 	case QDF_PROTO_TYPE_ARP:
2615 		if (status == QDF_TX_RX_STATUS_OK)
2616 			return false;
2617 		else
2618 			return qdf_dp_get_proto_event_bitmap() &
2619 					QDF_NBUF_PKT_TRAC_TYPE_ARP;
2620 	case QDF_PROTO_TYPE_DNS:
2621 		if (status == QDF_TX_RX_STATUS_OK)
2622 			return false;
2623 		else
2624 			return qdf_dp_get_proto_event_bitmap() &
2625 					QDF_NBUF_PKT_TRAC_TYPE_DNS;
2626 	default:
2627 		return false;
2628 	}
2629 }
2630 
2631 void qdf_dp_track_noack_check(qdf_nbuf_t nbuf, enum qdf_proto_subtype *subtype)
2632 {
2633 	enum qdf_proto_type pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
2634 	uint16_t dp_track = 0;
2635 
2636 	switch (pkt_type) {
2637 	case QDF_PROTO_TYPE_EAPOL:
2638 		dp_track = qdf_dp_get_proto_bitmap() &
2639 				QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
2640 		break;
2641 	case QDF_PROTO_TYPE_DHCP:
2642 		dp_track = qdf_dp_get_proto_bitmap() &
2643 				QDF_NBUF_PKT_TRAC_TYPE_DHCP;
2644 		break;
2645 	case QDF_PROTO_TYPE_ARP:
2646 		dp_track = qdf_dp_get_proto_bitmap() &
2647 					QDF_NBUF_PKT_TRAC_TYPE_ARP;
2648 		break;
2649 	case QDF_PROTO_TYPE_DNS:
2650 		dp_track = qdf_dp_get_proto_bitmap() &
2651 					QDF_NBUF_PKT_TRAC_TYPE_DNS;
2652 		break;
2653 	default:
2654 		break;
2655 	}
2656 
2657 	if (!dp_track) {
2658 		*subtype = QDF_PROTO_INVALID;
2659 		return;
2660 	}
2661 
2662 	*subtype = qdf_dp_get_pkt_subtype(nbuf, pkt_type);
2663 }
2664 qdf_export_symbol(qdf_dp_track_noack_check);
2665 
2666 enum qdf_dp_tx_rx_status qdf_dp_get_status_from_a_status(uint8_t status)
2667 {
2668 	if (status == QDF_A_STATUS_ERROR)
2669 		return QDF_TX_RX_STATUS_INVALID;
2670 	else if (status == QDF_A_STATUS_OK)
2671 		return QDF_TX_RX_STATUS_OK;
2672 	else
2673 		return QDF_TX_RX_STATUS_MAX;
2674 }
2675 qdf_export_symbol(qdf_dp_get_status_from_a_status);
2676 
2677 void qdf_dp_trace_ptr(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
2678 		uint8_t pdev_id, uint8_t *data, uint8_t size,
2679 		uint16_t msdu_id, uint16_t buf_arg_status,
2680 		enum qdf_dp_tx_rx_status qdf_tx_status)
2681 {
2682 	struct qdf_dp_trace_ptr_buf buf;
2683 	int buf_size = sizeof(struct qdf_dp_trace_ptr_buf);
2684 	enum qdf_proto_type pkt_type;
2685 	enum qdf_proto_subtype subtype;
2686 
2687 	pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
2688 	if ((code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD ||
2689 	     code == QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD) &&
2690 	    qdf_dp_proto_log_enable_check(pkt_type, qdf_tx_status)) {
2691 		subtype = qdf_dp_get_pkt_subtype(nbuf, pkt_type);
2692 		qdf_dp_log_proto_pkt_info(nbuf->data + QDF_NBUF_SRC_MAC_OFFSET,
2693 					 nbuf->data + QDF_NBUF_DEST_MAC_OFFSET,
2694 					 pkt_type, subtype,
2695 					 QDF_TX, msdu_id, qdf_tx_status);
2696 		qdf_fill_wlan_connectivity_log(pkt_type, subtype,
2697 					       QDF_TX, qdf_tx_status,
2698 					       QDF_NBUF_CB_TX_VDEV_CTX(nbuf),
2699 					       nbuf->data);
2700 	}
2701 
2702 	if (qdf_dp_enable_check(nbuf, code, QDF_TX) == false)
2703 		return;
2704 
2705 	if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
2706 		QDF_BUG(0);
2707 
2708 	qdf_mem_copy(&buf.cookie, data, size);
2709 	buf.msdu_id = msdu_id;
2710 	buf.status = buf_arg_status;
2711 	qdf_dp_add_record(code, pdev_id, (uint8_t *)&buf, buf_size, NULL, 0,
2712 			  QDF_NBUF_CB_DP_TRACE_PRINT(nbuf));
2713 }
2714 qdf_export_symbol(qdf_dp_trace_ptr);
2715 
2716 void qdf_dp_trace_data_pkt(qdf_nbuf_t nbuf, uint8_t pdev_id,
2717 			   enum QDF_DP_TRACE_ID code, uint16_t msdu_id,
2718 			   enum qdf_proto_dir dir)
2719 {
2720 	struct qdf_dp_trace_data_buf buf;
2721 	enum qdf_proto_type pkt_type;
2722 
2723 	pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
2724 	if (code == QDF_DP_TRACE_DROP_PACKET_RECORD &&
2725 	    qdf_dp_proto_log_enable_check(pkt_type, QDF_TX_RX_STATUS_DROP))
2726 		qdf_dp_log_proto_pkt_info(nbuf->data + QDF_NBUF_SRC_MAC_OFFSET,
2727 					 nbuf->data + QDF_NBUF_DEST_MAC_OFFSET,
2728 					 pkt_type,
2729 					 qdf_dp_get_pkt_subtype(nbuf, pkt_type),
2730 					 QDF_TX, msdu_id,
2731 					 QDF_TX_RX_STATUS_DROP);
2732 
2733 	buf.msdu_id = msdu_id;
2734 	if (!qdf_dp_enable_check(nbuf, code, dir))
2735 		return;
2736 
2737 	qdf_dp_add_record(code, pdev_id,
2738 			  nbuf ? qdf_nbuf_data(nbuf) : NULL,
2739 			  nbuf ? nbuf->len - nbuf->data_len : 0,
2740 			  (uint8_t *)&buf, sizeof(struct qdf_dp_trace_data_buf),
2741 			  (nbuf) ? QDF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false);
2742 }
2743 
2744 qdf_export_symbol(qdf_dp_trace_data_pkt);
2745 
2746 void qdf_dp_display_record(struct qdf_dp_trace_record_s *record,
2747 			   uint16_t index, uint8_t pdev_id, uint8_t info)
2748 {
2749 	int loc;
2750 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2751 
2752 	if (!(pdev_id == QDF_TRACE_DEFAULT_PDEV_ID ||
2753 		pdev_id == record->pdev_id))
2754 		return;
2755 
2756 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2757 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2758 					 index, info, record);
2759 
2760 	switch (record->code) {
2761 	case  QDF_DP_TRACE_HDD_TX_TIMEOUT:
2762 		DPTRACE_PRINT(" %s: HDD TX Timeout", prepend_str);
2763 		break;
2764 	case  QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
2765 		DPTRACE_PRINT(" %s: HDD SoftAP TX Timeout", prepend_str);
2766 		break;
2767 	case  QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD:
2768 		DPTRACE_PRINT(" %s: CE Fast Packet Error", prepend_str);
2769 		break;
2770 	case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD:
2771 	default:
2772 		dump_dp_hex_trace(prepend_str, record->data, record->size);
2773 		break;
2774 	};
2775 }
2776 qdf_export_symbol(qdf_dp_display_record);
2777 
2778 void
2779 qdf_dp_display_data_pkt_record(struct qdf_dp_trace_record_s *record,
2780 			       uint16_t rec_index, uint8_t pdev_id,
2781 			       uint8_t info)
2782 {
2783 	int loc;
2784 	char prepend_str[DP_TRACE_META_DATA_STRLEN + 10];
2785 	struct qdf_dp_trace_data_buf *buf =
2786 		(struct qdf_dp_trace_data_buf *)record->data;
2787 
2788 	qdf_mem_zero(prepend_str, sizeof(prepend_str));
2789 
2790 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2791 					 rec_index, info, record);
2792 	if (loc < sizeof(prepend_str))
2793 		loc += snprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
2794 				"[%d]", buf->msdu_id);
2795 	dump_dp_hex_trace(prepend_str,
2796 			  &record->data[sizeof(struct qdf_dp_trace_data_buf)],
2797 			  record->size);
2798 }
2799 
2800 /**
2801  * qdf_dp_trace() - Stores the data in buffer
2802  * @nbuf  : defines the netbuf
2803  * @code : defines the event
2804  * @pdev_id: pdev_id
2805  * @data : defines the data to be stored
2806  * @size : defines the size of the data record
2807  *
2808  * Return: None
2809  */
2810 void qdf_dp_trace(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, uint8_t pdev_id,
2811 	uint8_t *data, uint8_t size, enum qdf_proto_dir dir)
2812 {
2813 
2814 	if (qdf_dp_enable_check(nbuf, code, dir) == false)
2815 		return;
2816 
2817 	qdf_dp_add_record(code, pdev_id, nbuf ? qdf_nbuf_data(nbuf) : NULL,
2818 			  size, NULL, 0,
2819 			  (nbuf) ? QDF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false);
2820 }
2821 qdf_export_symbol(qdf_dp_trace);
2822 
2823 /**
2824  * qdf_dp_trace_spin_lock_init() - initializes the lock variable before use
2825  * This function will be called from cds_alloc_global_context, we will have lock
2826  * available to use ASAP
2827  *
2828  * Return: None
2829  */
2830 void qdf_dp_trace_spin_lock_init(void)
2831 {
2832 	spin_lock_init(&l_dp_trace_lock);
2833 }
2834 qdf_export_symbol(qdf_dp_trace_spin_lock_init);
2835 
2836 /**
2837  * qdf_dp_trace_disable_live_mode - disable live mode for dptrace
2838  *
2839  * Return: none
2840  */
2841 void qdf_dp_trace_disable_live_mode(void)
2842 {
2843 	g_qdf_dp_trace_data.force_live_mode = 0;
2844 }
2845 qdf_export_symbol(qdf_dp_trace_disable_live_mode);
2846 
2847 /**
2848  * qdf_dp_trace_enable_live_mode() - enable live mode for dptrace
2849  *
2850  * Return: none
2851  */
2852 void qdf_dp_trace_enable_live_mode(void)
2853 {
2854 	g_qdf_dp_trace_data.force_live_mode = 1;
2855 }
2856 qdf_export_symbol(qdf_dp_trace_enable_live_mode);
2857 
2858 /**
2859  * qdf_dp_trace_clear_buffer() - clear dp trace buffer
2860  *
2861  * Return: none
2862  */
2863 void qdf_dp_trace_clear_buffer(void)
2864 {
2865 	g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR;
2866 	g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR;
2867 	g_qdf_dp_trace_data.num = 0;
2868 	g_qdf_dp_trace_data.dump_counter = 0;
2869 	g_qdf_dp_trace_data.num_records_to_dump = MAX_QDF_DP_TRACE_RECORDS;
2870 	if (g_qdf_dp_trace_data.enable)
2871 		memset(g_qdf_dp_trace_tbl, 0,
2872 		       MAX_QDF_DP_TRACE_RECORDS *
2873 		       sizeof(struct qdf_dp_trace_record_s));
2874 }
2875 qdf_export_symbol(qdf_dp_trace_clear_buffer);
2876 
2877 void qdf_dp_trace_dump_stats(void)
2878 {
2879 		DPTRACE_PRINT("STATS |DPT: tx %u rx %u icmp(%u %u) arp(%u %u) icmpv6(%u %u %u %u %u %u) dhcp(%u %u %u %u %u %u) eapol(%u %u %u %u %u)",
2880 			      g_qdf_dp_trace_data.tx_count,
2881 			      g_qdf_dp_trace_data.rx_count,
2882 			      g_qdf_dp_trace_data.icmp_req,
2883 			      g_qdf_dp_trace_data.icmp_resp,
2884 			      g_qdf_dp_trace_data.arp_req,
2885 			      g_qdf_dp_trace_data.arp_resp,
2886 			      g_qdf_dp_trace_data.icmpv6_req,
2887 			      g_qdf_dp_trace_data.icmpv6_resp,
2888 			      g_qdf_dp_trace_data.icmpv6_ns,
2889 			      g_qdf_dp_trace_data.icmpv6_na,
2890 			      g_qdf_dp_trace_data.icmpv6_rs,
2891 			      g_qdf_dp_trace_data.icmpv6_ra,
2892 			      g_qdf_dp_trace_data.dhcp_disc,
2893 			      g_qdf_dp_trace_data.dhcp_off,
2894 			      g_qdf_dp_trace_data.dhcp_req,
2895 			      g_qdf_dp_trace_data.dhcp_ack,
2896 			      g_qdf_dp_trace_data.dhcp_nack,
2897 			      g_qdf_dp_trace_data.dhcp_others,
2898 			      g_qdf_dp_trace_data.eapol_m1,
2899 			      g_qdf_dp_trace_data.eapol_m2,
2900 			      g_qdf_dp_trace_data.eapol_m3,
2901 			      g_qdf_dp_trace_data.eapol_m4,
2902 			      g_qdf_dp_trace_data.eapol_others);
2903 }
2904 qdf_export_symbol(qdf_dp_trace_dump_stats);
2905 
2906 /**
2907  * qdf_dpt_dump_hex_trace_debugfs() - read data in file
2908  * @file: file to read
2909  * @str: string to prepend the hexdump with.
2910  * @buf: buffer which contains data to be written
2911  * @buf_len: defines the size of the data to be written
2912  *
2913  * Return: None
2914  */
2915 static void qdf_dpt_dump_hex_trace_debugfs(qdf_debugfs_file_t file,
2916 				char *str, uint8_t *buf, uint8_t buf_len)
2917 {
2918 	unsigned char linebuf[BUFFER_SIZE];
2919 	const u8 *ptr = buf;
2920 	int i, linelen, remaining = buf_len;
2921 
2922 	/* Dump the bytes in the last line */
2923 	for (i = 0; i < buf_len; i += ROW_SIZE) {
2924 		linelen = min(remaining, ROW_SIZE);
2925 		remaining -= ROW_SIZE;
2926 
2927 		hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1,
2928 				linebuf, sizeof(linebuf), false);
2929 
2930 		qdf_debugfs_printf(file, "%s %s\n", str, linebuf);
2931 	}
2932 }
2933 
2934 /**
2935  * qdf_dpt_display_proto_pkt_debugfs() - display proto packet
2936  * @file: file to read
2937  * @record: dptrace record
2938  * @index: index
2939  *
2940  * Return: none
2941  */
2942 static void qdf_dpt_display_proto_pkt_debugfs(qdf_debugfs_file_t file,
2943 				struct qdf_dp_trace_record_s *record,
2944 				uint32_t index)
2945 {
2946 	int loc;
2947 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2948 	struct qdf_dp_trace_proto_buf *buf =
2949 		(struct qdf_dp_trace_proto_buf *)record->data;
2950 
2951 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2952 					 index, 0, record);
2953 	qdf_debugfs_printf(file, "%s [%d] [%s] SA: "
2954 			   QDF_MAC_ADDR_FMT " %s DA: "
2955 			   QDF_MAC_ADDR_FMT,
2956 			   prepend_str,
2957 			   buf->vdev_id,
2958 			   qdf_dp_subtype_to_str(buf->subtype),
2959 			   QDF_MAC_ADDR_REF(buf->sa.bytes),
2960 			   qdf_dp_dir_to_str(buf->dir),
2961 			   QDF_MAC_ADDR_REF(buf->da.bytes));
2962 	qdf_debugfs_printf(file, "\n");
2963 }
2964 
2965 /**
2966  * qdf_dpt_display_mgmt_pkt_debugfs() - display mgmt packet
2967  * @file: file to read
2968  * @record: dptrace record
2969  * @index: index
2970  *
2971  * Return: none
2972  */
2973 static void qdf_dpt_display_mgmt_pkt_debugfs(qdf_debugfs_file_t file,
2974 				struct qdf_dp_trace_record_s *record,
2975 				uint32_t index)
2976 {
2977 
2978 	int loc;
2979 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
2980 	struct qdf_dp_trace_mgmt_buf *buf =
2981 		(struct qdf_dp_trace_mgmt_buf *)record->data;
2982 
2983 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
2984 					 index, 0, record);
2985 
2986 	qdf_debugfs_printf(file, "%s [%d] [%s %s]\n",
2987 			   prepend_str,
2988 			   buf->vdev_id,
2989 			   qdf_dp_type_to_str(buf->type),
2990 			   qdf_dp_subtype_to_str(buf->subtype));
2991 }
2992 
2993 /**
2994  * qdf_dpt_display_event_record_debugfs() - display event records
2995  * @file: file to read
2996  * @record: dptrace record
2997  * @index: index
2998  *
2999  * Return: none
3000  */
3001 static void qdf_dpt_display_event_record_debugfs(qdf_debugfs_file_t file,
3002 				struct qdf_dp_trace_record_s *record,
3003 				uint32_t index)
3004 {
3005 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
3006 	struct qdf_dp_trace_event_buf *buf =
3007 		(struct qdf_dp_trace_event_buf *)record->data;
3008 
3009 	qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
3010 				   index, 0, record);
3011 	qdf_debugfs_printf(file, "%s [%d] [%s %s]\n",
3012 			   prepend_str,
3013 			   buf->vdev_id,
3014 			   qdf_dp_type_to_str(buf->type),
3015 			   qdf_dp_subtype_to_str(buf->subtype));
3016 }
3017 
3018 /**
3019  * qdf_dpt_display_ptr_record_debugfs() - display record ptr
3020  * @file: file to read
3021  * @record: dptrace record
3022  * @index: index
3023  *
3024  * Return: none
3025  */
3026 static void qdf_dpt_display_ptr_record_debugfs(qdf_debugfs_file_t file,
3027 				struct qdf_dp_trace_record_s *record,
3028 				uint32_t index)
3029 {
3030 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
3031 	int loc;
3032 	struct qdf_dp_trace_ptr_buf *buf =
3033 		(struct qdf_dp_trace_ptr_buf *)record->data;
3034 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
3035 					 index, 0, record);
3036 
3037 	if (loc < sizeof(prepend_str))
3038 		scnprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
3039 			  "[msdu id %d %s %d]",
3040 			  buf->msdu_id,
3041 			  (record->code ==
3042 				QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) ?
3043 			  "status" : "vdev_id",
3044 			  buf->status);
3045 
3046 	qdf_dpt_dump_hex_trace_debugfs(file, prepend_str,
3047 				       (uint8_t *)&buf->cookie,
3048 				       sizeof(buf->cookie));
3049 }
3050 
3051 /**
3052  * qdf_dpt_display_ptr_record_debugfs() - display record
3053  * @file: file to read
3054  * @record: dptrace record
3055  * @index: index
3056  *
3057  * Return: none
3058  */
3059 static void qdf_dpt_display_record_debugfs(qdf_debugfs_file_t file,
3060 				struct qdf_dp_trace_record_s *record,
3061 				uint32_t index)
3062 {
3063 	int loc;
3064 	char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
3065 	struct qdf_dp_trace_data_buf *buf =
3066 		(struct qdf_dp_trace_data_buf *)record->data;
3067 
3068 	loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
3069 					 index, 0, record);
3070 	if (loc < sizeof(prepend_str))
3071 		loc += snprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
3072 				"[%d]", buf->msdu_id);
3073 	qdf_dpt_dump_hex_trace_debugfs(file, prepend_str,
3074 				       record->data, record->size);
3075 }
3076 
3077 uint32_t qdf_dpt_get_curr_pos_debugfs(qdf_debugfs_file_t file,
3078 				      enum qdf_dpt_debugfs_state state)
3079 {
3080 	uint32_t i = 0;
3081 	uint32_t tail;
3082 	uint32_t count = g_qdf_dp_trace_data.num;
3083 
3084 	if (!g_qdf_dp_trace_data.enable) {
3085 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
3086 		  "%s: Tracing Disabled", __func__);
3087 		return QDF_STATUS_E_EMPTY;
3088 	}
3089 
3090 	if (!count) {
3091 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
3092 		  "%s: no packets", __func__);
3093 		return QDF_STATUS_E_EMPTY;
3094 	}
3095 
3096 	if (state == QDF_DPT_DEBUGFS_STATE_SHOW_IN_PROGRESS)
3097 		return g_qdf_dp_trace_data.curr_pos;
3098 
3099 	qdf_debugfs_printf(file,
3100 		"DPT: config - bitmap 0x%x verb %u #rec %u rec_requested %u live_config %u thresh %u time_limit %u\n",
3101 		g_qdf_dp_trace_data.proto_bitmap,
3102 		g_qdf_dp_trace_data.verbosity,
3103 		g_qdf_dp_trace_data.no_of_record,
3104 		g_qdf_dp_trace_data.num_records_to_dump,
3105 		g_qdf_dp_trace_data.live_mode_config,
3106 		g_qdf_dp_trace_data.high_tput_thresh,
3107 		g_qdf_dp_trace_data.thresh_time_limit);
3108 
3109 	qdf_debugfs_printf(file,
3110 		"STATS |DPT: icmp(%u %u) arp(%u %u) icmpv6(%u %u %u %u %u %u) dhcp(%u %u %u %u %u %u) eapol(%u %u %u %u %u)\n",
3111 		g_qdf_dp_trace_data.icmp_req,
3112 		g_qdf_dp_trace_data.icmp_resp,
3113 		g_qdf_dp_trace_data.arp_req,
3114 		g_qdf_dp_trace_data.arp_resp,
3115 		g_qdf_dp_trace_data.icmpv6_req,
3116 		g_qdf_dp_trace_data.icmpv6_resp,
3117 		g_qdf_dp_trace_data.icmpv6_ns,
3118 		g_qdf_dp_trace_data.icmpv6_na,
3119 		g_qdf_dp_trace_data.icmpv6_rs,
3120 		g_qdf_dp_trace_data.icmpv6_ra,
3121 		g_qdf_dp_trace_data.dhcp_disc,
3122 		g_qdf_dp_trace_data.dhcp_off,
3123 		g_qdf_dp_trace_data.dhcp_req,
3124 		g_qdf_dp_trace_data.dhcp_ack,
3125 		g_qdf_dp_trace_data.dhcp_nack,
3126 		g_qdf_dp_trace_data.dhcp_others,
3127 		g_qdf_dp_trace_data.eapol_m1,
3128 		g_qdf_dp_trace_data.eapol_m2,
3129 		g_qdf_dp_trace_data.eapol_m3,
3130 		g_qdf_dp_trace_data.eapol_m4,
3131 		g_qdf_dp_trace_data.eapol_others);
3132 
3133 	qdf_debugfs_printf(file,
3134 		"DPT: Total Records: %d, Head: %d, Tail: %d\n",
3135 		g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head,
3136 		g_qdf_dp_trace_data.tail);
3137 
3138 	spin_lock_bh(&l_dp_trace_lock);
3139 	if (g_qdf_dp_trace_data.head != INVALID_QDF_DP_TRACE_ADDR) {
3140 		i = g_qdf_dp_trace_data.head;
3141 		tail = g_qdf_dp_trace_data.tail;
3142 
3143 		if (count > g_qdf_dp_trace_data.num)
3144 			count = g_qdf_dp_trace_data.num;
3145 
3146 		if (tail >= (count - 1))
3147 			i = tail - count + 1;
3148 		else if (count != MAX_QDF_DP_TRACE_RECORDS)
3149 			i = MAX_QDF_DP_TRACE_RECORDS - ((count - 1) -
3150 						     tail);
3151 		g_qdf_dp_trace_data.curr_pos = 0;
3152 		g_qdf_dp_trace_data.saved_tail = tail;
3153 	}
3154 	spin_unlock_bh(&l_dp_trace_lock);
3155 
3156 	return g_qdf_dp_trace_data.saved_tail;
3157 }
3158 qdf_export_symbol(qdf_dpt_get_curr_pos_debugfs);
3159 
3160 QDF_STATUS qdf_dpt_dump_stats_debugfs(qdf_debugfs_file_t file,
3161 				      uint32_t curr_pos)
3162 {
3163 	struct qdf_dp_trace_record_s p_record;
3164 	uint32_t i = curr_pos;
3165 	uint16_t num_records_to_dump = g_qdf_dp_trace_data.num_records_to_dump;
3166 
3167 	if (!g_qdf_dp_trace_data.enable) {
3168 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
3169 			  "%s: Tracing Disabled", __func__);
3170 		return QDF_STATUS_E_FAILURE;
3171 	}
3172 
3173 	if (num_records_to_dump > g_qdf_dp_trace_data.num)
3174 		num_records_to_dump = g_qdf_dp_trace_data.num;
3175 
3176 	/*
3177 	 * Max dp trace record size should always be less than
3178 	 * QDF_DP_TRACE_PREPEND_STR_SIZE(100) + BUFFER_SIZE(121).
3179 	 */
3180 	if (WARN_ON(QDF_DP_TRACE_MAX_RECORD_SIZE <
3181 				QDF_DP_TRACE_PREPEND_STR_SIZE + BUFFER_SIZE))
3182 		return QDF_STATUS_E_FAILURE;
3183 
3184 	spin_lock_bh(&l_dp_trace_lock);
3185 	p_record = g_qdf_dp_trace_tbl[i];
3186 	spin_unlock_bh(&l_dp_trace_lock);
3187 
3188 	for (;; ) {
3189 		/*
3190 		 * Initially we get file as 1 page size, and
3191 		 * if remaining size in file is less than one record max size,
3192 		 * then return so that it gets an extra page.
3193 		 */
3194 		if ((file->size - file->count) < QDF_DP_TRACE_MAX_RECORD_SIZE) {
3195 			spin_lock_bh(&l_dp_trace_lock);
3196 			g_qdf_dp_trace_data.curr_pos = i;
3197 			spin_unlock_bh(&l_dp_trace_lock);
3198 			return QDF_STATUS_E_FAILURE;
3199 		}
3200 
3201 		switch (p_record.code) {
3202 		case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD:
3203 		case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD:
3204 		case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD:
3205 			qdf_dpt_display_ptr_record_debugfs(file, &p_record, i);
3206 			break;
3207 
3208 		case QDF_DP_TRACE_EAPOL_PACKET_RECORD:
3209 		case QDF_DP_TRACE_DHCP_PACKET_RECORD:
3210 		case QDF_DP_TRACE_ARP_PACKET_RECORD:
3211 		case QDF_DP_TRACE_ICMP_PACKET_RECORD:
3212 		case QDF_DP_TRACE_ICMPv6_PACKET_RECORD:
3213 			qdf_dpt_display_proto_pkt_debugfs(file, &p_record, i);
3214 			break;
3215 
3216 		case QDF_DP_TRACE_TX_CREDIT_RECORD:
3217 			qdf_dpt_display_credit_record_debugfs(file, &p_record,
3218 							      i);
3219 			break;
3220 
3221 		case QDF_DP_TRACE_MGMT_PACKET_RECORD:
3222 			qdf_dpt_display_mgmt_pkt_debugfs(file, &p_record, i);
3223 			break;
3224 
3225 		case QDF_DP_TRACE_EVENT_RECORD:
3226 			qdf_dpt_display_event_record_debugfs(file, &p_record,
3227 							     i);
3228 			break;
3229 
3230 		case QDF_DP_TRACE_HDD_TX_TIMEOUT:
3231 			qdf_debugfs_printf(
3232 					file, "DPT: %04d: %llu %s\n",
3233 					i, p_record.time,
3234 					qdf_dp_code_to_string(p_record.code));
3235 			qdf_debugfs_printf(file, "HDD TX Timeout\n");
3236 			break;
3237 
3238 		case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
3239 			qdf_debugfs_printf(
3240 					file, "DPT: %04d: %llu %s\n",
3241 					i, p_record.time,
3242 					qdf_dp_code_to_string(p_record.code));
3243 			qdf_debugfs_printf(file, "HDD SoftAP TX Timeout\n");
3244 			break;
3245 
3246 		case QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD:
3247 			qdf_debugfs_printf(
3248 					file, "DPT: %04d: %llu %s\n",
3249 					i, p_record.time,
3250 					qdf_dp_code_to_string(p_record.code));
3251 			qdf_debugfs_printf(file, "CE Fast Packet Error\n");
3252 			break;
3253 
3254 		case QDF_DP_TRACE_MAX:
3255 			qdf_debugfs_printf(file,
3256 				"%s: QDF_DP_TRACE_MAX event should not be generated\n",
3257 				__func__);
3258 			break;
3259 
3260 		case QDF_DP_TRACE_HDD_TX_PACKET_RECORD:
3261 		case QDF_DP_TRACE_HDD_RX_PACKET_RECORD:
3262 		case QDF_DP_TRACE_TX_PACKET_RECORD:
3263 		case QDF_DP_TRACE_RX_PACKET_RECORD:
3264 		case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD:
3265 		case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD:
3266 
3267 		default:
3268 			qdf_dpt_display_record_debugfs(file, &p_record, i);
3269 			break;
3270 		}
3271 
3272 		if (++g_qdf_dp_trace_data.dump_counter == num_records_to_dump)
3273 			break;
3274 
3275 		spin_lock_bh(&l_dp_trace_lock);
3276 		if (i == 0)
3277 			i = MAX_QDF_DP_TRACE_RECORDS;
3278 
3279 		i -= 1;
3280 		p_record = g_qdf_dp_trace_tbl[i];
3281 		spin_unlock_bh(&l_dp_trace_lock);
3282 	}
3283 
3284 	g_qdf_dp_trace_data.dump_counter = 0;
3285 
3286 	return QDF_STATUS_SUCCESS;
3287 }
3288 qdf_export_symbol(qdf_dpt_dump_stats_debugfs);
3289 
3290 /**
3291  * qdf_dpt_set_value_debugfs() - Configure the value to control DP trace
3292  * @proto_bitmap: defines the protocol to be tracked
3293  * @no_of_records: defines the nth packet which is traced
3294  * @verbosity: defines the verbosity level
3295  *
3296  * Return: None
3297  */
3298 void qdf_dpt_set_value_debugfs(uint8_t proto_bitmap, uint8_t no_of_record,
3299 			    uint8_t verbosity, uint16_t num_records_to_dump)
3300 {
3301 	if (g_qdf_dp_trace_data.enable) {
3302 		g_qdf_dp_trace_data.proto_bitmap = proto_bitmap;
3303 		g_qdf_dp_trace_data.no_of_record = no_of_record;
3304 		g_qdf_dp_trace_data.verbosity    = verbosity;
3305 		g_qdf_dp_trace_data.num_records_to_dump = num_records_to_dump;
3306 	}
3307 }
3308 qdf_export_symbol(qdf_dpt_set_value_debugfs);
3309 
3310 
3311 /**
3312  * qdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions
3313  * registered with QDF
3314  * @count: Number of lines to dump starting from tail to head
3315  * @pdev_id: pdev_id
3316  *
3317  * Return: None
3318  */
3319 void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id)
3320 {
3321 	struct qdf_dp_trace_record_s p_record;
3322 	int32_t i, tail;
3323 
3324 	if (!g_qdf_dp_trace_data.enable) {
3325 		DPTRACE_PRINT("Tracing Disabled");
3326 		return;
3327 	}
3328 
3329 	DPTRACE_PRINT(
3330 		"DPT: config - bitmap 0x%x verb %u #rec %u live_config %u thresh %u time_limit %u",
3331 		g_qdf_dp_trace_data.proto_bitmap,
3332 		g_qdf_dp_trace_data.verbosity,
3333 		g_qdf_dp_trace_data.no_of_record,
3334 		g_qdf_dp_trace_data.live_mode_config,
3335 		g_qdf_dp_trace_data.high_tput_thresh,
3336 		g_qdf_dp_trace_data.thresh_time_limit);
3337 
3338 	qdf_dp_trace_dump_stats();
3339 
3340 	DPTRACE_PRINT("DPT: Total Records: %d, Head: %d, Tail: %d",
3341 		      g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head,
3342 		      g_qdf_dp_trace_data.tail);
3343 
3344 	/* acquire the lock so that only one thread at a time can read
3345 	 * the ring buffer
3346 	 */
3347 	spin_lock_bh(&l_dp_trace_lock);
3348 
3349 	if (g_qdf_dp_trace_data.head != INVALID_QDF_DP_TRACE_ADDR) {
3350 		i = g_qdf_dp_trace_data.head;
3351 		tail = g_qdf_dp_trace_data.tail;
3352 
3353 		if (count) {
3354 			if (count > g_qdf_dp_trace_data.num)
3355 				count = g_qdf_dp_trace_data.num;
3356 			if (tail >= (count - 1))
3357 				i = tail - count + 1;
3358 			else if (count != MAX_QDF_DP_TRACE_RECORDS)
3359 				i = MAX_QDF_DP_TRACE_RECORDS - ((count - 1) -
3360 							     tail);
3361 		}
3362 
3363 		p_record = g_qdf_dp_trace_tbl[i];
3364 		spin_unlock_bh(&l_dp_trace_lock);
3365 		for (;; ) {
3366 			qdf_dp_trace_cb_table[p_record.code](&p_record,
3367 							(uint16_t)i, pdev_id, false);
3368 			if (i == tail)
3369 				break;
3370 			i += 1;
3371 
3372 			spin_lock_bh(&l_dp_trace_lock);
3373 			if (MAX_QDF_DP_TRACE_RECORDS == i)
3374 				i = 0;
3375 
3376 			p_record = g_qdf_dp_trace_tbl[i];
3377 			spin_unlock_bh(&l_dp_trace_lock);
3378 		}
3379 	} else {
3380 		spin_unlock_bh(&l_dp_trace_lock);
3381 	}
3382 }
3383 qdf_export_symbol(qdf_dp_trace_dump_all);
3384 
3385 /**
3386  * qdf_dp_trace_throttle_live_mode() - Throttle DP Trace live mode
3387  * @high_bw_request: whether this is a high BW req or not
3388  *
3389  * The function tries to prevent excessive logging into the live buffer by
3390  * having an upper limit on number of packets that can be logged per second.
3391  *
3392  * The intention is to allow occasional pings and data packets and really low
3393  * throughput levels while suppressing bursts and higher throughput levels so
3394  * that we donot hog the live buffer.
3395  *
3396  * If the number of packets printed in a particular second exceeds the thresh,
3397  * disable printing in the next second.
3398  *
3399  * Return: None
3400  */
3401 void qdf_dp_trace_throttle_live_mode(bool high_bw_request)
3402 {
3403 	static int bw_interval_counter;
3404 
3405 	if (g_qdf_dp_trace_data.enable == false ||
3406 		g_qdf_dp_trace_data.live_mode_config == false)
3407 		return;
3408 
3409 	if (high_bw_request) {
3410 		g_qdf_dp_trace_data.live_mode = 0;
3411 		bw_interval_counter = 0;
3412 		return;
3413 	}
3414 
3415 	bw_interval_counter++;
3416 
3417 	if (0 == (bw_interval_counter %
3418 			g_qdf_dp_trace_data.thresh_time_limit)) {
3419 
3420 		spin_lock_bh(&l_dp_trace_lock);
3421 			if (g_qdf_dp_trace_data.print_pkt_cnt <=
3422 				g_qdf_dp_trace_data.high_tput_thresh)
3423 				g_qdf_dp_trace_data.live_mode = 1;
3424 
3425 		g_qdf_dp_trace_data.print_pkt_cnt = 0;
3426 		spin_unlock_bh(&l_dp_trace_lock);
3427 	}
3428 }
3429 qdf_export_symbol(qdf_dp_trace_throttle_live_mode);
3430 
3431 void qdf_dp_trace_apply_tput_policy(bool is_data_traffic)
3432 {
3433 	if (g_qdf_dp_trace_data.dynamic_verbosity_modify) {
3434 		goto check_live_mode;
3435 		return;
3436 	}
3437 
3438 	if (is_data_traffic) {
3439 		g_qdf_dp_trace_data.verbosity =
3440 					QDF_DP_TRACE_VERBOSITY_ULTRA_LOW;
3441 	} else {
3442 		g_qdf_dp_trace_data.verbosity =
3443 					g_qdf_dp_trace_data.ini_conf_verbosity;
3444 	}
3445 check_live_mode:
3446 	qdf_dp_trace_throttle_live_mode(is_data_traffic);
3447 }
3448 #endif
3449 
3450 struct qdf_print_ctrl print_ctrl_obj[MAX_PRINT_CONFIG_SUPPORTED];
3451 
3452 struct category_name_info g_qdf_category_name[MAX_SUPPORTED_CATEGORY] = {
3453 	[QDF_MODULE_ID_TDLS] = {"tdls"},
3454 	[QDF_MODULE_ID_ACS] = {"ACS"},
3455 	[QDF_MODULE_ID_SCAN_SM] = {"scan state machine"},
3456 	[QDF_MODULE_ID_SCANENTRY] = {"scan entry"},
3457 	[QDF_MODULE_ID_WDS] = {"WDS"},
3458 	[QDF_MODULE_ID_ACTION] = {"action"},
3459 	[QDF_MODULE_ID_ROAM] = {"STA roaming"},
3460 	[QDF_MODULE_ID_INACT] = {"inactivity"},
3461 	[QDF_MODULE_ID_DOTH] = {"11h"},
3462 	[QDF_MODULE_ID_IQUE] = {"IQUE"},
3463 	[QDF_MODULE_ID_WME] = {"WME"},
3464 	[QDF_MODULE_ID_ACL] = {"ACL"},
3465 	[QDF_MODULE_ID_WPA] = {"WPA/RSN"},
3466 	[QDF_MODULE_ID_RADKEYS] = {"dump 802.1x keys"},
3467 	[QDF_MODULE_ID_RADDUMP] = {"dump radius packet"},
3468 	[QDF_MODULE_ID_RADIUS] = {"802.1x radius client"},
3469 	[QDF_MODULE_ID_DOT1XSM] = {"802.1x state machine"},
3470 	[QDF_MODULE_ID_DOT1X] = {"802.1x authenticator"},
3471 	[QDF_MODULE_ID_POWER] = {"power save"},
3472 	[QDF_MODULE_ID_STATE] = {"state"},
3473 	[QDF_MODULE_ID_OUTPUT] = {"output"},
3474 	[QDF_MODULE_ID_SCAN] = {"scan"},
3475 	[QDF_MODULE_ID_AUTH] = {"authentication"},
3476 	[QDF_MODULE_ID_ASSOC] = {"association"},
3477 	[QDF_MODULE_ID_NODE] = {"node"},
3478 	[QDF_MODULE_ID_ELEMID] = {"element ID"},
3479 	[QDF_MODULE_ID_XRATE] = {"rate"},
3480 	[QDF_MODULE_ID_INPUT] = {"input"},
3481 	[QDF_MODULE_ID_CRYPTO] = {"crypto"},
3482 	[QDF_MODULE_ID_DUMPPKTS] = {"dump packet"},
3483 	[QDF_MODULE_ID_DEBUG] = {"debug"},
3484 	[QDF_MODULE_ID_MLME] = {"mlme"},
3485 	[QDF_MODULE_ID_RRM] = {"rrm"},
3486 	[QDF_MODULE_ID_WNM] = {"wnm"},
3487 	[QDF_MODULE_ID_P2P_PROT] = {"p2p_prot"},
3488 	[QDF_MODULE_ID_PROXYARP] = {"proxyarp"},
3489 	[QDF_MODULE_ID_L2TIF] = {"l2tif"},
3490 	[QDF_MODULE_ID_WIFIPOS] = {"wifipos"},
3491 	[QDF_MODULE_ID_WRAP] = {"wrap"},
3492 	[QDF_MODULE_ID_DFS] = {"dfs"},
3493 	[QDF_MODULE_ID_ATF] = {"atf"},
3494 	[QDF_MODULE_ID_SPLITMAC] = {"splitmac"},
3495 	[QDF_MODULE_ID_IOCTL] = {"ioctl"},
3496 	[QDF_MODULE_ID_NAC] = {"nac"},
3497 	[QDF_MODULE_ID_MESH] = {"mesh"},
3498 	[QDF_MODULE_ID_MBO] = {"mbo"},
3499 	[QDF_MODULE_ID_EXTIOCTL_CHANSWITCH] = {"extchanswitch"},
3500 	[QDF_MODULE_ID_EXTIOCTL_CHANSSCAN] = {"extchanscan"},
3501 	[QDF_MODULE_ID_TLSHIM] = {"tlshim"},
3502 	[QDF_MODULE_ID_WMI] = {"WMI"},
3503 	[QDF_MODULE_ID_HTT] = {"HTT"},
3504 	[QDF_MODULE_ID_HDD] = {"HDD"},
3505 	[QDF_MODULE_ID_SME] = {"SME"},
3506 	[QDF_MODULE_ID_PE] = {"PE"},
3507 	[QDF_MODULE_ID_WMA] = {"WMA"},
3508 	[QDF_MODULE_ID_SYS] = {"SYS"},
3509 	[QDF_MODULE_ID_QDF] = {"QDF"},
3510 	[QDF_MODULE_ID_SAP] = {"SAP"},
3511 	[QDF_MODULE_ID_HDD_SOFTAP] = {"HDD_SAP"},
3512 	[QDF_MODULE_ID_HDD_DATA] = {"DATA"},
3513 	[QDF_MODULE_ID_HDD_SAP_DATA] = {"SAP_DATA"},
3514 	[QDF_MODULE_ID_HIF] = {"HIF"},
3515 	[QDF_MODULE_ID_HTC] = {"HTC"},
3516 	[QDF_MODULE_ID_TXRX] = {"TXRX"},
3517 	[QDF_MODULE_ID_QDF_DEVICE] = {"QDF_DEV"},
3518 	[QDF_MODULE_ID_CFG] = {"CFG"},
3519 	[QDF_MODULE_ID_BMI] = {"BMI"},
3520 	[QDF_MODULE_ID_EPPING] = {"EPPING"},
3521 	[QDF_MODULE_ID_QVIT] = {"QVIT"},
3522 	[QDF_MODULE_ID_DP] = {"DP"},
3523 	[QDF_MODULE_ID_HAL] = {"HAL"},
3524 	[QDF_MODULE_ID_SOC] = {"SOC"},
3525 	[QDF_MODULE_ID_OS_IF] = {"OSIF"},
3526 	[QDF_MODULE_ID_TARGET_IF] = {"TIF"},
3527 	[QDF_MODULE_ID_SCHEDULER] = {"SCH"},
3528 	[QDF_MODULE_ID_MGMT_TXRX] = {"MGMT_TXRX"},
3529 	[QDF_MODULE_ID_PMO] = {"PMO"},
3530 	[QDF_MODULE_ID_POLICY_MGR] = {"POLICY_MGR"},
3531 	[QDF_MODULE_ID_SA_API] = {"SA_API"},
3532 	[QDF_MODULE_ID_NAN] = {"NAN"},
3533 	[QDF_MODULE_ID_SPECTRAL] = {"SPECTRAL"},
3534 	[QDF_MODULE_ID_P2P] = {"P2P"},
3535 	[QDF_MODULE_ID_OFFCHAN_TXRX] = {"OFFCHAN"},
3536 	[QDF_MODULE_ID_REGULATORY] = {"REGULATORY"},
3537 	[QDF_MODULE_ID_OBJ_MGR] = {"OBJMGR"},
3538 	[QDF_MODULE_ID_SERIALIZATION] = {"SER"},
3539 	[QDF_MODULE_ID_NSS] = {"NSS"},
3540 	[QDF_MODULE_ID_ROAM_DEBUG] = {"roam debug"},
3541 	[QDF_MODULE_ID_DIRECT_BUF_RX] = {"DIRECT_BUF_RX"},
3542 	[QDF_MODULE_ID_DISA] = {"disa"},
3543 	[QDF_MODULE_ID_GREEN_AP] = {"GREEN_AP"},
3544 	[QDF_MODULE_ID_FD] = {"FILS discovery"},
3545 	[QDF_MODULE_ID_FTM] = {"FTM"},
3546 	[QDF_MODULE_ID_OCB] = {"OCB"},
3547 	[QDF_MODULE_ID_CONFIG] = {"CONFIG"},
3548 	[QDF_MODULE_ID_IPA] = {"IPA"},
3549 	[QDF_MODULE_ID_CP_STATS] = {"CP_STATS"},
3550 	[QDF_MODULE_ID_DCS] = {"DCS"},
3551 	[QDF_MODULE_ID_ACTION_OUI] = {"action_oui"},
3552 	[QDF_MODULE_ID_TARGET] = {"TARGET"},
3553 	[QDF_MODULE_ID_MBSSIE] = {"MBSSIE"},
3554 	[QDF_MODULE_ID_FWOL] = {"fwol"},
3555 	[QDF_MODULE_ID_SM_ENGINE] = {"SM_ENG"},
3556 	[QDF_MODULE_ID_CMN_MLME] = {"CMN_MLME"},
3557 	[QDF_MODULE_ID_BSSCOLOR] = {"BSSCOLOR"},
3558 	[QDF_MODULE_ID_CFR] = {"CFR"},
3559 	[QDF_MODULE_ID_DP_TX_CAPTURE] = {"TX_CAPTURE_ENHANCE"},
3560 	[QDF_MODULE_ID_INTEROP_ISSUES_AP] = {"INTEROP_ISSUES_AP"},
3561 	[QDF_MODULE_ID_DENYLIST_MGR] = {"dlm"},
3562 	[QDF_MODULE_ID_QLD] = {"QLD"},
3563 	[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = {"Dynamic Mode Change"},
3564 	[QDF_MODULE_ID_COEX] = {"COEX"},
3565 	[QDF_MODULE_ID_MON_FILTER] = {"Monitor Filter"},
3566 	[QDF_MODULE_ID_PKT_CAPTURE] = {"pkt_capture"},
3567 	[QDF_MODULE_ID_RPTR] = {"RPTR"},
3568 	[QDF_MODULE_ID_6GHZ] = {"6GHZ"},
3569 	[QDF_MODULE_ID_IOT_SIM] = {"IOT_SIM"},
3570 	[QDF_MODULE_ID_MSCS] = {"MSCS"},
3571 	[QDF_MODULE_ID_GPIO] = {"GPIO_CFG"},
3572 	[QDF_MODULE_ID_IFMGR] = {"IF_MGR"},
3573 	[QDF_MODULE_ID_DIAG] = {"DIAG"},
3574 	[QDF_MODULE_ID_DP_INIT] = {"DP_INIT"},
3575 	[QDF_MODULE_ID_DP_TX] = {"DP_TX"},
3576 	[QDF_MODULE_ID_DP_RX] = {"DP_RX"},
3577 	[QDF_MODULE_ID_DP_STATS] = {"DP_STATS"},
3578 	[QDF_MODULE_ID_DP_HTT] = {"DP_HTT"},
3579 	[QDF_MODULE_ID_DP_PEER] = {"DP_PEER"},
3580 	[QDF_MODULE_ID_DP_RX_ERROR] = {"DP_RX_ERROR"},
3581 	[QDF_MODULE_ID_DP_HTT_TX_STATS] = {"DP_HTT_TX_STATS"},
3582 	[QDF_MODULE_ID_DP_RX_MON_STATUS] = {"DP_RX_MON_STATUS"},
3583 	[QDF_MODULE_ID_DP_RX_MON_DEST] = {"DP_RX_MON_DEST"},
3584 	[QDF_MODULE_ID_DP_REO] = {"DP_REO"},
3585 	[QDF_MODULE_ID_DP_TX_COMP] = {"DP_TX_COMP"},
3586 	[QDF_MODULE_ID_DP_VDEV] = {"DP_VDEV"},
3587 	[QDF_MODULE_ID_DP_CDP] = {"DP_CDP"},
3588 	[QDF_MODULE_ID_TSO] = {"TSO"},
3589 	[QDF_MODULE_ID_ME] = {"ME"},
3590 	[QDF_MODULE_ID_QWRAP] = {"QWRAP"},
3591 	[QDF_MODULE_ID_DBDC_REP] = {"DBDC_REP"},
3592 	[QDF_MODULE_ID_EXT_AP] = {"EXT_AP"},
3593 	[QDF_MODULE_ID_MLO] = {"MLO_MGR"},
3594 	[QDF_MODULE_ID_MGMT_RX_REO] = {"MGMT_RX_REO"},
3595 	[QDF_MODULE_ID_MLOIE] = {"MLOIE"},
3596 	[QDF_MODULE_ID_MBSS] = {"MBSS"},
3597 	[QDF_MODULE_ID_MON] = {"MONITOR"},
3598 	[QDF_MODULE_ID_AFC] = {"AFC"},
3599 	[QDF_MODULE_ID_TWT] = {"TWT"},
3600 	[QDF_MODULE_ID_SON] = {"SON"},
3601 	[QDF_MODULE_ID_WLAN_PRE_CAC] = {"PRE_CAC"},
3602 	[QDF_MODULE_ID_T2LM] = {"T2LM"},
3603 	[QDF_MODULE_ID_DP_SAWF] = {"DP_SAWF"},
3604 	[QDF_MODULE_ID_SCS] = {"SCS"},
3605 	[QDF_MODULE_ID_DP_UMAC_RESET] = {"UMAC_HW_RESET"},
3606 	[QDF_MODULE_ID_COAP] = {"COAP"},
3607 	[QDF_MODULE_ID_FTM_TIME_SYNC] = {"Time Sync"},
3608 	[QDF_MODULE_ID_WIFI_RADAR] = {"WIFI RADAR"},
3609 	[QDF_MODULE_ID_CDP] =  {"CDP"},
3610 	[QDF_MODULE_ID_ANY] = {"ANY"},
3611 };
3612 qdf_export_symbol(g_qdf_category_name);
3613 
3614 /**
3615  * qdf_trace_display() - Display trace
3616  *
3617  * Return:  None
3618  */
3619 void qdf_trace_display(void)
3620 {
3621 	QDF_MODULE_ID module_id;
3622 
3623 	pr_err("     1)FATAL  2)ERROR  3)WARN  4)INFO  5)INFO_H  6)INFO_M  7)INFO_L 8)DEBUG\n");
3624 	for (module_id = 0; module_id < QDF_MODULE_ID_MAX; ++module_id) {
3625 		pr_err("%2d)%s    %s        %s       %s       %s        %s         %s         %s        %s\n",
3626 		       (int)module_id,
3627 		       g_qdf_category_name[module_id].category_name_str,
3628 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3629 			       QDF_TRACE_LEVEL_FATAL) ? "X" : " ",
3630 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3631 			       QDF_TRACE_LEVEL_ERROR) ? "X" : " ",
3632 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3633 			       QDF_TRACE_LEVEL_WARN) ? "X" : " ",
3634 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3635 			       QDF_TRACE_LEVEL_INFO) ? "X" : " ",
3636 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3637 			       QDF_TRACE_LEVEL_INFO_HIGH) ? "X" : " ",
3638 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3639 			       QDF_TRACE_LEVEL_INFO_MED) ? "X" : " ",
3640 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3641 			       QDF_TRACE_LEVEL_INFO_LOW) ? "X" : " ",
3642 		       qdf_print_is_verbose_enabled(qdf_pidx, module_id,
3643 			       QDF_TRACE_LEVEL_DEBUG) ? "X" : " ");
3644 	}
3645 }
3646 qdf_export_symbol(qdf_trace_display);
3647 
3648 #ifdef WLAN_MAX_LOGS_PER_SEC
3649 static qdf_time_t __log_window_end;
3650 static qdf_atomic_t __log_window_count;
3651 uint32_t qdf_rl_print_count = WLAN_MAX_LOGS_PER_SEC;
3652 uint32_t qdf_rl_print_time = 1;
3653 uint32_t qdf_rl_print_suppressed;
3654 
3655 /**
3656  * qdf_detected_excessive_logging() - Excessive logging detected
3657  *
3658  * Track logging count using a quasi-tumbling window.
3659  * If the max logging count for a given window is exceeded,
3660  * return true else fails.
3661  *
3662  * Return: true/false
3663  */
3664 bool qdf_detected_excessive_logging(void)
3665 {
3666 	qdf_time_t now = qdf_system_ticks();
3667 	bool excessive_prints = false;
3668 
3669 	/*
3670 	 * If 'now' is more recent than the end of the window, reset.
3671 	 *
3672 	 * Note: This is not thread safe, and can result in more than one reset.
3673 	 * For our purposes, this is fine.
3674 	 */
3675 	if (!qdf_atomic_read(&__log_window_count)) {
3676 		__log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time);
3677 	} else if (qdf_system_time_after(now, __log_window_end)) {
3678 		__log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time);
3679 		qdf_atomic_set(&__log_window_count, 0);
3680 	}
3681 
3682 	if (qdf_atomic_inc_return(&__log_window_count) > qdf_rl_print_count)
3683 		excessive_prints = true;
3684 
3685 	return excessive_prints;
3686 }
3687 
3688 void qdf_rl_print_count_set(uint32_t rl_print_count)
3689 {
3690 	qdf_rl_print_count = rl_print_count;
3691 }
3692 
3693 qdf_export_symbol(qdf_rl_print_count_set);
3694 
3695 void qdf_rl_print_time_set(uint32_t rl_print_time)
3696 {
3697 	qdf_rl_print_time = rl_print_time;
3698 }
3699 
3700 qdf_export_symbol(qdf_rl_print_time_set);
3701 
3702 void qdf_rl_print_suppressed_log(void)
3703 {
3704 	if (qdf_rl_print_suppressed) {
3705 		pr_err("QDF Ratelimiting: %d prints suppressed",
3706 		       qdf_rl_print_suppressed);
3707 		qdf_rl_print_suppressed = 0;
3708 	}
3709 }
3710 
3711 void qdf_rl_print_suppressed_inc(void)
3712 {
3713 	qdf_rl_print_suppressed++;
3714 }
3715 #else
3716 #define qdf_rl_print_suppressed_log()
3717 #define qdf_rl_print_suppressed_inc()
3718 #endif /* WLAN_MAX_LOGS_PER_SEC */
3719 
3720 #ifdef QDF_TRACE_PRINT_ENABLE
3721 static inline void print_to_console(char *str_buffer)
3722 {
3723 	if (qdf_in_interrupt() && qdf_detected_excessive_logging()) {
3724 		qdf_rl_print_suppressed_inc();
3725 		return;
3726 	}
3727 	qdf_rl_print_suppressed_log();
3728 	pr_err("%s\n", str_buffer);
3729 }
3730 #else
3731 
3732 #define print_to_console(str)
3733 #endif
3734 
3735 #ifdef MULTI_IF_NAME
3736 static const char *qdf_trace_wlan_modname(void)
3737 {
3738 	return MULTI_IF_NAME;
3739 }
3740 #else
3741 static const char *qdf_trace_wlan_modname(void)
3742 {
3743 	return "wlan";
3744 }
3745 #endif
3746 
3747 void qdf_trace_msg_cmn(unsigned int idx,
3748 			QDF_MODULE_ID category,
3749 			QDF_TRACE_LEVEL verbose,
3750 			const char *str_format, va_list val)
3751 {
3752 	char str_buffer[QDF_TRACE_BUFFER_SIZE];
3753 	int n;
3754 
3755 	/* Check if index passed is valid */
3756 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
3757 		pr_info("%s: Invalid index - %d\n", __func__, idx);
3758 		return;
3759 	}
3760 
3761 	/* Check if print control object is in use */
3762 	if (!print_ctrl_obj[idx].in_use) {
3763 		pr_info("%s: Invalid print control object\n", __func__);
3764 		return;
3765 	}
3766 
3767 	/* Check if category passed is valid */
3768 	if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
3769 		vscnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE, str_format, val);
3770 		pr_info("%s: Invalid category: %d, log: %s\n",
3771 			__func__, category, str_buffer);
3772 		return;
3773 	}
3774 
3775 	/* Check if verbose mask is valid */
3776 	if (verbose < 0 || verbose >= QDF_TRACE_LEVEL_MAX) {
3777 		vscnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE, str_format, val);
3778 		pr_info("%s: Invalid verbose level %d, log: %s\n",
3779 			__func__, verbose, str_buffer);
3780 		return;
3781 	}
3782 
3783 	/*
3784 	 * Print the trace message when the desired verbose level is set in
3785 	 * the desired category for the print control object
3786 	 */
3787 	if (print_ctrl_obj[idx].cat_info[category].category_verbose_mask &
3788 	    QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) {
3789 		static const char * const VERBOSE_STR[] = {
3790 			[QDF_TRACE_LEVEL_NONE] = "",
3791 			[QDF_TRACE_LEVEL_FATAL] = "F",
3792 			[QDF_TRACE_LEVEL_ERROR] = "E",
3793 			[QDF_TRACE_LEVEL_WARN] = "W",
3794 			[QDF_TRACE_LEVEL_INFO] = "I",
3795 			[QDF_TRACE_LEVEL_INFO_HIGH] = "IH",
3796 			[QDF_TRACE_LEVEL_INFO_MED] = "IM",
3797 			[QDF_TRACE_LEVEL_INFO_LOW] = "IL",
3798 			[QDF_TRACE_LEVEL_DEBUG] = "D",
3799 			[QDF_TRACE_LEVEL_TRACE] = "T",
3800 			[QDF_TRACE_LEVEL_ALL] = "" };
3801 
3802 		/* print the prefix string into the string buffer... */
3803 		n = scnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE,
3804 			     "%s: [%d:%s:%s] ", qdf_trace_wlan_modname(),
3805 			     in_interrupt() ? 0 : current->pid,
3806 			     VERBOSE_STR[verbose],
3807 			     g_qdf_category_name[category].category_name_str);
3808 
3809 		/* print the formatted log message after the prefix string */
3810 		vscnprintf(str_buffer + n, QDF_TRACE_BUFFER_SIZE - n,
3811 			   str_format, val);
3812 #if defined(WLAN_LOGGING_SOCK_SVC_ENABLE)
3813 		wlan_log_to_user(verbose, (char *)str_buffer,
3814 				 strlen(str_buffer));
3815 		if (qdf_unlikely(qdf_log_dump_at_kernel_enable))
3816 			print_to_console(str_buffer);
3817 #else
3818 		pr_err("%s\n", str_buffer);
3819 #endif
3820 	}
3821 }
3822 qdf_export_symbol(qdf_trace_msg_cmn);
3823 
3824 QDF_STATUS qdf_print_setup(void)
3825 {
3826 	int i;
3827 
3828 	/* Loop through all print ctrl objects */
3829 	for (i = 0; i < MAX_PRINT_CONFIG_SUPPORTED; i++) {
3830 		if (qdf_print_ctrl_cleanup(i))
3831 			return QDF_STATUS_E_FAILURE;
3832 	}
3833 	return QDF_STATUS_SUCCESS;
3834 }
3835 qdf_export_symbol(qdf_print_setup);
3836 
3837 QDF_STATUS qdf_print_ctrl_cleanup(unsigned int idx)
3838 {
3839 	int i = 0;
3840 
3841 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
3842 		pr_info("%s: Invalid index - %d\n", __func__, idx);
3843 		return QDF_STATUS_E_FAILURE;
3844 	}
3845 
3846 	/* Clean up the print control object corresponding to that index
3847 	 * If success, callee to change print control index to -1
3848 	 */
3849 
3850 	for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
3851 		print_ctrl_obj[idx].cat_info[i].category_verbose_mask =
3852 							QDF_TRACE_LEVEL_NONE;
3853 	}
3854 	print_ctrl_obj[idx].custom_print = NULL;
3855 	print_ctrl_obj[idx].custom_ctxt = NULL;
3856 	qdf_print_clean_node_flag(idx);
3857 	print_ctrl_obj[idx].in_use = false;
3858 
3859 	return QDF_STATUS_SUCCESS;
3860 }
3861 qdf_export_symbol(qdf_print_ctrl_cleanup);
3862 
3863 int qdf_print_ctrl_register(const struct category_info *cinfo,
3864 			    void *custom_print_handler,
3865 			    void *custom_ctx,
3866 			    const char *pctrl_name)
3867 {
3868 	int idx = -1;
3869 	int i = 0;
3870 
3871 	for (i = 0; i < MAX_PRINT_CONFIG_SUPPORTED; i++) {
3872 		if (!print_ctrl_obj[i].in_use) {
3873 			idx = i;
3874 			break;
3875 		}
3876 	}
3877 
3878 	/* Callee to handle idx -1 appropriately */
3879 	if (idx == -1) {
3880 		pr_info("%s: Allocation failed! No print control object free\n",
3881 			__func__);
3882 		return idx;
3883 	}
3884 
3885 	print_ctrl_obj[idx].in_use = true;
3886 
3887 	/*
3888 	 * In case callee does not pass category info,
3889 	 * custom print handler, custom context and print control name,
3890 	 * we do not set any value here. Clean up for the print control
3891 	 * getting allocated would have taken care of initializing
3892 	 * default values.
3893 	 *
3894 	 * We need to only set in_use to 1 in such a case
3895 	 */
3896 
3897 	if (pctrl_name) {
3898 		qdf_str_lcopy(print_ctrl_obj[idx].name, pctrl_name,
3899 			      sizeof(print_ctrl_obj[idx].name));
3900 	}
3901 
3902 	if (custom_print_handler)
3903 		print_ctrl_obj[idx].custom_print = custom_print_handler;
3904 
3905 	if (custom_ctx)
3906 		print_ctrl_obj[idx].custom_ctxt = custom_ctx;
3907 
3908 	if (cinfo) {
3909 		for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
3910 			if (cinfo[i].category_verbose_mask ==
3911 			    QDF_TRACE_LEVEL_ALL) {
3912 				print_ctrl_obj[idx].cat_info[i]
3913 				.category_verbose_mask = 0xFFFF;
3914 			} else if ((cinfo[i].category_verbose_mask ==
3915 				   QDF_TRACE_LEVEL_NONE) ||
3916 				   (cinfo[i].category_verbose_mask ==
3917 				   QDF_TRACE_LEVEL_TO_MODULE_BITMASK(
3918 				   QDF_TRACE_LEVEL_NONE))) {
3919 				print_ctrl_obj[idx].cat_info[i]
3920 				.category_verbose_mask = 0;
3921 			} else {
3922 				print_ctrl_obj[idx].cat_info[i]
3923 				.category_verbose_mask =
3924 				cinfo[i].category_verbose_mask;
3925 			}
3926 		}
3927 	}
3928 
3929 	return idx;
3930 }
3931 qdf_export_symbol(qdf_print_ctrl_register);
3932 
3933 #ifdef QDF_TRACE_PRINT_ENABLE
3934 void qdf_shared_print_ctrl_cleanup(void)
3935 {
3936 	qdf_print_ctrl_cleanup(qdf_pidx);
3937 }
3938 qdf_export_symbol(qdf_shared_print_ctrl_cleanup);
3939 
3940 /*
3941  * Set this to invalid value to differentiate with user-provided
3942  * value.
3943  */
3944 int qdf_dbg_mask = QDF_TRACE_LEVEL_MAX;
3945 qdf_export_symbol(qdf_dbg_mask);
3946 qdf_declare_param(qdf_dbg_mask, int);
3947 
3948 /*
3949  * QDF can be passed parameters which indicate the
3950  * debug level for each module.
3951  * an array of string values are passed, each string hold the following form
3952  *
3953  * <module name string>=<integer debug level value>
3954  *
3955  * The array qdf_dbg_arr will hold these module-string=value strings
3956  * The variable qdf_dbg_arr_cnt will have the count of how many such
3957  * string values were passed.
3958  */
3959 static char *qdf_dbg_arr[QDF_MODULE_ID_MAX];
3960 static int qdf_dbg_arr_cnt;
3961 qdf_declare_param_array(qdf_dbg_arr, charp, &qdf_dbg_arr_cnt);
3962 
3963 static uint16_t set_cumulative_verbose_mask(QDF_TRACE_LEVEL max_level)
3964 {
3965 	uint16_t category_verbose_mask = 0;
3966 	QDF_TRACE_LEVEL level;
3967 
3968 	for (level = QDF_TRACE_LEVEL_FATAL; level <= max_level; level++) {
3969 		category_verbose_mask |=
3970 			QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
3971 	}
3972 	return category_verbose_mask;
3973 }
3974 
3975 static QDF_MODULE_ID find_qdf_module_from_string(char *str)
3976 {
3977 	QDF_MODULE_ID mod_id;
3978 
3979 	for (mod_id = 0; mod_id < QDF_MODULE_ID_MAX; mod_id++) {
3980 		if (strcasecmp(str,
3981 				g_qdf_category_name[mod_id].category_name_str)
3982 				== 0) {
3983 			break;
3984 		}
3985 	}
3986 	return mod_id;
3987 }
3988 
3989 static void process_qdf_dbg_arr_param(struct category_info *cinfo,
3990 					int array_index)
3991 {
3992 	char *mod_val_str, *mod_str, *val_str;
3993 	unsigned long dbg_level;
3994 	QDF_MODULE_ID mod_id;
3995 
3996 	mod_val_str = qdf_dbg_arr[array_index];
3997 	mod_str = strsep(&mod_val_str, "=");
3998 	val_str = mod_val_str;
3999 	if (!val_str) {
4000 		pr_info("qdf_dbg_arr: %s not in the <mod>=<val> form\n",
4001 				mod_str);
4002 		return;
4003 	}
4004 
4005 	mod_id = find_qdf_module_from_string(mod_str);
4006 	if (mod_id >= QDF_MODULE_ID_MAX) {
4007 		pr_info("ERROR!!Module name %s not in the list of modules\n",
4008 				mod_str);
4009 		return;
4010 	}
4011 
4012 	if (kstrtol(val_str, 10, &dbg_level) < 0) {
4013 		pr_info("ERROR!!Invalid debug level for module: %s\n",
4014 				mod_str);
4015 		return;
4016 	}
4017 
4018 	if (dbg_level >= QDF_TRACE_LEVEL_MAX) {
4019 		pr_info("ERROR!!Debug level for %s too high", mod_str);
4020 		pr_info("max: %d given %lu\n", QDF_TRACE_LEVEL_MAX,
4021 				dbg_level);
4022 		return;
4023 	}
4024 
4025 	pr_info("User passed setting module %s(%d) to level %lu\n",
4026 			mod_str,
4027 			mod_id,
4028 			dbg_level);
4029 	cinfo[mod_id].category_verbose_mask =
4030 		set_cumulative_verbose_mask((QDF_TRACE_LEVEL)dbg_level);
4031 }
4032 
4033 static void set_default_trace_levels(struct category_info *cinfo)
4034 {
4035 	int i;
4036 	static QDF_TRACE_LEVEL module_trace_default_level[QDF_MODULE_ID_MAX] = {
4037 		[QDF_MODULE_ID_TDLS] = QDF_TRACE_LEVEL_NONE,
4038 		[QDF_MODULE_ID_ACS] = QDF_TRACE_LEVEL_NONE,
4039 		[QDF_MODULE_ID_SCAN_SM] = QDF_TRACE_LEVEL_NONE,
4040 		[QDF_MODULE_ID_SCANENTRY] = QDF_TRACE_LEVEL_NONE,
4041 		[QDF_MODULE_ID_WDS] = QDF_TRACE_LEVEL_NONE,
4042 		[QDF_MODULE_ID_ACTION] = QDF_TRACE_LEVEL_NONE,
4043 		[QDF_MODULE_ID_ROAM] = QDF_TRACE_LEVEL_NONE,
4044 		[QDF_MODULE_ID_INACT] = QDF_TRACE_LEVEL_NONE,
4045 		[QDF_MODULE_ID_DOTH] = QDF_TRACE_LEVEL_NONE,
4046 		[QDF_MODULE_ID_IQUE] = QDF_TRACE_LEVEL_NONE,
4047 		[QDF_MODULE_ID_WME] = QDF_TRACE_LEVEL_NONE,
4048 		[QDF_MODULE_ID_ACL] = QDF_TRACE_LEVEL_NONE,
4049 		[QDF_MODULE_ID_WPA] = QDF_TRACE_LEVEL_NONE,
4050 		[QDF_MODULE_ID_RADKEYS] = QDF_TRACE_LEVEL_NONE,
4051 		[QDF_MODULE_ID_RADDUMP] = QDF_TRACE_LEVEL_NONE,
4052 		[QDF_MODULE_ID_RADIUS] = QDF_TRACE_LEVEL_NONE,
4053 		[QDF_MODULE_ID_DOT1XSM] = QDF_TRACE_LEVEL_NONE,
4054 		[QDF_MODULE_ID_DOT1X] = QDF_TRACE_LEVEL_NONE,
4055 		[QDF_MODULE_ID_POWER] = QDF_TRACE_LEVEL_NONE,
4056 		[QDF_MODULE_ID_STATE] = QDF_TRACE_LEVEL_NONE,
4057 		[QDF_MODULE_ID_OUTPUT] = QDF_TRACE_LEVEL_NONE,
4058 		[QDF_MODULE_ID_SCAN] = QDF_TRACE_LEVEL_ERROR,
4059 		[QDF_MODULE_ID_AUTH] = QDF_TRACE_LEVEL_NONE,
4060 		[QDF_MODULE_ID_ASSOC] = QDF_TRACE_LEVEL_NONE,
4061 		[QDF_MODULE_ID_NODE] = QDF_TRACE_LEVEL_NONE,
4062 		[QDF_MODULE_ID_ELEMID] = QDF_TRACE_LEVEL_NONE,
4063 		[QDF_MODULE_ID_XRATE] = QDF_TRACE_LEVEL_NONE,
4064 		[QDF_MODULE_ID_INPUT] = QDF_TRACE_LEVEL_NONE,
4065 		[QDF_MODULE_ID_CRYPTO] = QDF_TRACE_LEVEL_NONE,
4066 		[QDF_MODULE_ID_DUMPPKTS] = QDF_TRACE_LEVEL_NONE,
4067 		[QDF_MODULE_ID_DEBUG] = QDF_TRACE_LEVEL_NONE,
4068 		[QDF_MODULE_ID_MLME] = QDF_TRACE_LEVEL_ERROR,
4069 		[QDF_MODULE_ID_RRM] = QDF_TRACE_LEVEL_NONE,
4070 		[QDF_MODULE_ID_WNM] = QDF_TRACE_LEVEL_NONE,
4071 		[QDF_MODULE_ID_P2P_PROT] = QDF_TRACE_LEVEL_NONE,
4072 		[QDF_MODULE_ID_PROXYARP] = QDF_TRACE_LEVEL_NONE,
4073 		[QDF_MODULE_ID_L2TIF] = QDF_TRACE_LEVEL_NONE,
4074 		[QDF_MODULE_ID_WIFIPOS] = QDF_TRACE_LEVEL_NONE,
4075 		[QDF_MODULE_ID_WRAP] = QDF_TRACE_LEVEL_NONE,
4076 		[QDF_MODULE_ID_DFS] = QDF_TRACE_LEVEL_NONE,
4077 		[QDF_MODULE_ID_ATF] = QDF_TRACE_LEVEL_ERROR,
4078 		[QDF_MODULE_ID_SPLITMAC] = QDF_TRACE_LEVEL_NONE,
4079 		[QDF_MODULE_ID_IOCTL] = QDF_TRACE_LEVEL_NONE,
4080 		[QDF_MODULE_ID_NAC] = QDF_TRACE_LEVEL_NONE,
4081 		[QDF_MODULE_ID_MESH] = QDF_TRACE_LEVEL_NONE,
4082 		[QDF_MODULE_ID_MBO] = QDF_TRACE_LEVEL_NONE,
4083 		[QDF_MODULE_ID_EXTIOCTL_CHANSWITCH] = QDF_TRACE_LEVEL_NONE,
4084 		[QDF_MODULE_ID_EXTIOCTL_CHANSSCAN] = QDF_TRACE_LEVEL_NONE,
4085 		[QDF_MODULE_ID_TLSHIM] = QDF_TRACE_LEVEL_NONE,
4086 		[QDF_MODULE_ID_WMI] = QDF_TRACE_LEVEL_ERROR,
4087 		[QDF_MODULE_ID_HTT] = QDF_TRACE_LEVEL_NONE,
4088 		[QDF_MODULE_ID_HDD] = QDF_TRACE_LEVEL_NONE,
4089 		[QDF_MODULE_ID_SME] = QDF_TRACE_LEVEL_NONE,
4090 		[QDF_MODULE_ID_PE] = QDF_TRACE_LEVEL_NONE,
4091 		[QDF_MODULE_ID_WMA] = QDF_TRACE_LEVEL_NONE,
4092 		[QDF_MODULE_ID_SYS] = QDF_TRACE_LEVEL_NONE,
4093 		[QDF_MODULE_ID_QDF] = QDF_TRACE_LEVEL_ERROR,
4094 		[QDF_MODULE_ID_SAP] = QDF_TRACE_LEVEL_NONE,
4095 		[QDF_MODULE_ID_HDD_SOFTAP] = QDF_TRACE_LEVEL_NONE,
4096 		[QDF_MODULE_ID_HDD_DATA] = QDF_TRACE_LEVEL_NONE,
4097 		[QDF_MODULE_ID_HDD_SAP_DATA] = QDF_TRACE_LEVEL_NONE,
4098 		[QDF_MODULE_ID_HIF] = QDF_TRACE_LEVEL_ERROR,
4099 		[QDF_MODULE_ID_HTC] = QDF_TRACE_LEVEL_NONE,
4100 		[QDF_MODULE_ID_TXRX] = QDF_TRACE_LEVEL_NONE,
4101 		[QDF_MODULE_ID_QDF_DEVICE] = QDF_TRACE_LEVEL_NONE,
4102 		[QDF_MODULE_ID_CFG] = QDF_TRACE_LEVEL_NONE,
4103 		[QDF_MODULE_ID_BMI] = QDF_TRACE_LEVEL_NONE,
4104 		[QDF_MODULE_ID_EPPING] = QDF_TRACE_LEVEL_NONE,
4105 		[QDF_MODULE_ID_QVIT] = QDF_TRACE_LEVEL_NONE,
4106 		[QDF_MODULE_ID_DP] = QDF_TRACE_LEVEL_FATAL,
4107 		[QDF_MODULE_ID_HAL] = QDF_TRACE_LEVEL_NONE,
4108 		[QDF_MODULE_ID_SOC] = QDF_TRACE_LEVEL_NONE,
4109 		[QDF_MODULE_ID_OS_IF] = QDF_TRACE_LEVEL_NONE,
4110 		[QDF_MODULE_ID_TARGET_IF] = QDF_TRACE_LEVEL_INFO,
4111 		[QDF_MODULE_ID_SCHEDULER] = QDF_TRACE_LEVEL_FATAL,
4112 		[QDF_MODULE_ID_MGMT_TXRX] = QDF_TRACE_LEVEL_NONE,
4113 		[QDF_MODULE_ID_SERIALIZATION] = QDF_TRACE_LEVEL_ERROR,
4114 		[QDF_MODULE_ID_PMO] = QDF_TRACE_LEVEL_NONE,
4115 		[QDF_MODULE_ID_P2P] = QDF_TRACE_LEVEL_NONE,
4116 		[QDF_MODULE_ID_POLICY_MGR] = QDF_TRACE_LEVEL_NONE,
4117 		[QDF_MODULE_ID_CONFIG] = QDF_TRACE_LEVEL_ERROR,
4118 		[QDF_MODULE_ID_REGULATORY] = QDF_TRACE_LEVEL_NONE,
4119 		[QDF_MODULE_ID_SA_API] = QDF_TRACE_LEVEL_NONE,
4120 		[QDF_MODULE_ID_NAN] = QDF_TRACE_LEVEL_NONE,
4121 		[QDF_MODULE_ID_OFFCHAN_TXRX] = QDF_TRACE_LEVEL_NONE,
4122 		[QDF_MODULE_ID_SON] = QDF_TRACE_LEVEL_NONE,
4123 		[QDF_MODULE_ID_SPECTRAL] = QDF_TRACE_LEVEL_ERROR,
4124 		[QDF_MODULE_ID_OBJ_MGR] = QDF_TRACE_LEVEL_FATAL,
4125 		[QDF_MODULE_ID_NSS] = QDF_TRACE_LEVEL_ERROR,
4126 		[QDF_MODULE_ID_ROAM_DEBUG] = QDF_TRACE_LEVEL_ERROR,
4127 		[QDF_MODULE_ID_CDP] = QDF_TRACE_LEVEL_NONE,
4128 		[QDF_MODULE_ID_DIRECT_BUF_RX] = QDF_TRACE_LEVEL_ERROR,
4129 		[QDF_MODULE_ID_DISA] = QDF_TRACE_LEVEL_NONE,
4130 		[QDF_MODULE_ID_GREEN_AP] = QDF_TRACE_LEVEL_ERROR,
4131 		[QDF_MODULE_ID_FTM] = QDF_TRACE_LEVEL_ERROR,
4132 		[QDF_MODULE_ID_FD] = QDF_TRACE_LEVEL_ERROR,
4133 		[QDF_MODULE_ID_OCB] = QDF_TRACE_LEVEL_ERROR,
4134 		[QDF_MODULE_ID_IPA] = QDF_TRACE_LEVEL_NONE,
4135 		[QDF_MODULE_ID_ACTION_OUI] = QDF_TRACE_LEVEL_NONE,
4136 		[QDF_MODULE_ID_CP_STATS] = QDF_TRACE_LEVEL_ERROR,
4137 		[QDF_MODULE_ID_DCS] = QDF_TRACE_LEVEL_ERROR,
4138 		[QDF_MODULE_ID_MBSSIE] = QDF_TRACE_LEVEL_INFO,
4139 		[QDF_MODULE_ID_FWOL] = QDF_TRACE_LEVEL_NONE,
4140 		[QDF_MODULE_ID_SM_ENGINE] = QDF_TRACE_LEVEL_ERROR,
4141 		[QDF_MODULE_ID_CMN_MLME] = QDF_TRACE_LEVEL_INFO,
4142 		[QDF_MODULE_ID_BSSCOLOR] = QDF_TRACE_LEVEL_ERROR,
4143 		[QDF_MODULE_ID_CFR] = QDF_TRACE_LEVEL_ERROR,
4144 		[QDF_MODULE_ID_DP_TX_CAPTURE] = QDF_TRACE_LEVEL_FATAL,
4145 		[QDF_MODULE_ID_INTEROP_ISSUES_AP] = QDF_TRACE_LEVEL_NONE,
4146 		[QDF_MODULE_ID_DENYLIST_MGR] = QDF_TRACE_LEVEL_NONE,
4147 		[QDF_MODULE_ID_QLD] = QDF_TRACE_LEVEL_ERROR,
4148 		[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = QDF_TRACE_LEVEL_INFO,
4149 		[QDF_MODULE_ID_COEX] = QDF_TRACE_LEVEL_ERROR,
4150 		[QDF_MODULE_ID_MON_FILTER] = QDF_TRACE_LEVEL_INFO,
4151 		[QDF_MODULE_ID_PKT_CAPTURE] = QDF_TRACE_LEVEL_NONE,
4152 		[QDF_MODULE_ID_RPTR] = QDF_TRACE_LEVEL_INFO,
4153 		[QDF_MODULE_ID_6GHZ] = QDF_TRACE_LEVEL_ERROR,
4154 		[QDF_MODULE_ID_IOT_SIM] = QDF_TRACE_LEVEL_ERROR,
4155 		[QDF_MODULE_ID_MSCS] = QDF_TRACE_LEVEL_INFO,
4156 		[QDF_MODULE_ID_GPIO] = QDF_TRACE_LEVEL_NONE,
4157 		[QDF_MODULE_ID_IFMGR] = QDF_TRACE_LEVEL_ERROR,
4158 		[QDF_MODULE_ID_DIAG] = QDF_TRACE_LEVEL_ERROR,
4159 		[QDF_MODULE_ID_DP_INIT] = QDF_TRACE_LEVEL_FATAL,
4160 		[QDF_MODULE_ID_DP_TX] = QDF_TRACE_LEVEL_FATAL,
4161 		[QDF_MODULE_ID_DP_RX] = QDF_TRACE_LEVEL_FATAL,
4162 		[QDF_MODULE_ID_DP_STATS] = QDF_TRACE_LEVEL_FATAL,
4163 		[QDF_MODULE_ID_DP_HTT] = QDF_TRACE_LEVEL_FATAL,
4164 		[QDF_MODULE_ID_DP_PEER] = QDF_TRACE_LEVEL_FATAL,
4165 		[QDF_MODULE_ID_DP_RX_ERROR] = QDF_TRACE_LEVEL_FATAL,
4166 		[QDF_MODULE_ID_DP_HTT_TX_STATS] = QDF_TRACE_LEVEL_FATAL,
4167 		[QDF_MODULE_ID_DP_RX_MON_STATUS] = QDF_TRACE_LEVEL_FATAL,
4168 		[QDF_MODULE_ID_DP_RX_MON_DEST] = QDF_TRACE_LEVEL_FATAL,
4169 		[QDF_MODULE_ID_DP_REO] = QDF_TRACE_LEVEL_FATAL,
4170 		[QDF_MODULE_ID_DP_TX_COMP] = QDF_TRACE_LEVEL_FATAL,
4171 		[QDF_MODULE_ID_DP_VDEV] = QDF_TRACE_LEVEL_FATAL,
4172 		[QDF_MODULE_ID_DP_CDP] = QDF_TRACE_LEVEL_FATAL,
4173 		[QDF_MODULE_ID_TSO] = QDF_TRACE_LEVEL_FATAL,
4174 		[QDF_MODULE_ID_ME] = QDF_TRACE_LEVEL_INFO,
4175 		[QDF_MODULE_ID_QWRAP] = QDF_TRACE_LEVEL_FATAL,
4176 		[QDF_MODULE_ID_DBDC_REP] = QDF_TRACE_LEVEL_FATAL,
4177 		[QDF_MODULE_ID_EXT_AP] = QDF_TRACE_LEVEL_NONE,
4178 		[QDF_MODULE_ID_MLO] = QDF_TRACE_LEVEL_INFO,
4179 		[QDF_MODULE_ID_MLOIE] = QDF_TRACE_LEVEL_INFO,
4180 		[QDF_MODULE_ID_MBSS] = QDF_TRACE_LEVEL_ERROR,
4181 		[QDF_MODULE_ID_MON] = QDF_TRACE_LEVEL_ERROR,
4182 		[QDF_MODULE_ID_MGMT_RX_REO] = QDF_TRACE_LEVEL_ERROR,
4183 		[QDF_MODULE_ID_TWT] = QDF_TRACE_LEVEL_ERROR,
4184 		[QDF_MODULE_ID_WLAN_PRE_CAC] = QDF_TRACE_LEVEL_ERROR,
4185 		[QDF_MODULE_ID_T2LM] = QDF_TRACE_LEVEL_ERROR,
4186 		[QDF_MODULE_ID_DP_SAWF] = QDF_TRACE_LEVEL_ERROR,
4187 		[QDF_MODULE_ID_SCS] = QDF_TRACE_LEVEL_ERROR,
4188 		[QDF_MODULE_ID_DP_UMAC_RESET] = QDF_TRACE_LEVEL_ERROR,
4189 		[QDF_MODULE_ID_COAP] = QDF_TRACE_LEVEL_ERROR,
4190 		[QDF_MODULE_ID_FTM_TIME_SYNC] = QDF_TRACE_LEVEL_NONE,
4191 		[QDF_MODULE_ID_AFC] = QDF_TRACE_LEVEL_NONE,
4192 		[QDF_MODULE_ID_WIFI_RADAR] = QDF_TRACE_LEVEL_NONE,
4193 		[QDF_MODULE_ID_TARGET] = QDF_TRACE_LEVEL_NONE,
4194 		[QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO,
4195 	};
4196 
4197 	for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
4198 		cinfo[i].category_verbose_mask = set_cumulative_verbose_mask(
4199 				module_trace_default_level[i]);
4200 	}
4201 }
4202 
4203 void qdf_shared_print_ctrl_init(void)
4204 {
4205 	int i;
4206 	struct category_info cinfo[MAX_SUPPORTED_CATEGORY];
4207 
4208 	set_default_trace_levels(cinfo);
4209 
4210 	/*
4211 	 * User specified across-module single debug level
4212 	 */
4213 	if ((qdf_dbg_mask >= 0) && (qdf_dbg_mask < QDF_TRACE_LEVEL_MAX)) {
4214 		pr_info("User specified module debug level of %d\n",
4215 			qdf_dbg_mask);
4216 		for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
4217 			cinfo[i].category_verbose_mask =
4218 			set_cumulative_verbose_mask(qdf_dbg_mask);
4219 		}
4220 	} else if (qdf_dbg_mask != QDF_TRACE_LEVEL_MAX) {
4221 		pr_info("qdf_dbg_mask value is invalid\n");
4222 		pr_info("Using the default module debug levels instead\n");
4223 	}
4224 
4225 	/*
4226 	 * Module ID-Level specified as array during module load
4227 	 */
4228 	for (i = 0; i < qdf_dbg_arr_cnt; i++) {
4229 		process_qdf_dbg_arr_param(cinfo, i);
4230 	}
4231 	qdf_pidx = qdf_print_ctrl_register(cinfo, NULL, NULL,
4232 			"LOG_SHARED_OBJ");
4233 }
4234 qdf_export_symbol(qdf_shared_print_ctrl_init);
4235 #endif
4236 
4237 #ifdef QCA_WIFI_MODULE_PARAMS_FROM_INI
4238 QDF_STATUS qdf_module_param_handler(void *context, const char *str_param,
4239 				    const char *str)
4240 {
4241 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4242 	uint16_t param = 0;
4243 	uint32_t flush_tmr_prd;
4244 	bool dump_flag;
4245 
4246 	while (param < QDF_PARAM_MAX) {
4247 		if (qdf_str_eq(qdf_module_param[param], str_param)) {
4248 			switch (param) {
4249 			case MEM_DEBUG_DISABLED:
4250 				status = qdf_mem_debug_disabled_config_set(str);
4251 				break;
4252 			case QDF_DBG_MASK:
4253 				status = qdf_int32_parse(str, &qdf_dbg_mask);
4254 				break;
4255 			case PREALLOC_DISABLED:
4256 				status = qdf_prealloc_disabled_config_set(str);
4257 				break;
4258 			case QDF_LOG_DUMP_AT_KERNEL_ENABLE:
4259 				status = qdf_bool_parse(str, &dump_flag);
4260 				qdf_log_dump_at_kernel_enable = dump_flag;
4261 				break;
4262 			case QDF_DBG_ARR:
4263 				qdf_dbg_arr[0] = (char *)str;
4264 				status = QDF_STATUS_SUCCESS;
4265 				break;
4266 			case QDF_LOG_FLUSH_TIMER_PERIOD:
4267 				status = qdf_uint32_parse(str, &flush_tmr_prd);
4268 				qdf_log_flush_timer_period = flush_tmr_prd;
4269 				break;
4270 			default:
4271 				break;
4272 			}
4273 			return status;
4274 		}
4275 		param++;
4276 	}
4277 
4278 	return QDF_STATUS_SUCCESS;
4279 }
4280 
4281 void qdf_initialize_module_param_from_ini(void)
4282 {
4283 	QDF_STATUS status;
4284 	char *path = QDF_WIFI_MODULE_PARAMS_FILE;
4285 
4286 	status = qdf_ini_parse(path, NULL, qdf_module_param_handler, NULL);
4287 	if (QDF_IS_STATUS_ERROR(status)) {
4288 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
4289 				"Failed to parse *.ini file @ %s; status:%d",
4290 				path, status);
4291 		return;
4292 	}
4293 }
4294 #endif
4295 
4296 QDF_STATUS qdf_print_set_category_verbose(unsigned int idx,
4297 						QDF_MODULE_ID category,
4298 						QDF_TRACE_LEVEL verbose,
4299 						bool is_set)
4300 {
4301 	/* Check if index passed is valid */
4302 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
4303 		pr_err("%s: Invalid index - %d\n", __func__, idx);
4304 		return QDF_STATUS_E_FAILURE;
4305 	}
4306 
4307 	/* Check if print control object is in use */
4308 	if (!print_ctrl_obj[idx].in_use) {
4309 		pr_err("%s: Invalid print control object\n", __func__);
4310 		return QDF_STATUS_E_FAILURE;
4311 	}
4312 
4313 	/* Check if category passed is valid */
4314 	if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
4315 		pr_err("%s: Invalid category: %d\n", __func__, category);
4316 		return QDF_STATUS_E_FAILURE;
4317 	}
4318 
4319 	/* Check if verbose mask is valid */
4320 	if (verbose < 0 || verbose >= QDF_TRACE_LEVEL_MAX) {
4321 		pr_err("%s: Invalid verbose level %d\n", __func__, verbose);
4322 		return QDF_STATUS_E_FAILURE;
4323 	}
4324 
4325 	if (verbose == QDF_TRACE_LEVEL_ALL) {
4326 		print_ctrl_obj[idx].cat_info[category].category_verbose_mask =
4327 				0xFFFF;
4328 		return QDF_STATUS_SUCCESS;
4329 	}
4330 
4331 	if (verbose == QDF_TRACE_LEVEL_NONE) {
4332 		print_ctrl_obj[idx].cat_info[category].category_verbose_mask =
4333 				QDF_TRACE_LEVEL_NONE;
4334 		return QDF_STATUS_SUCCESS;
4335 	}
4336 
4337 	if (!is_set) {
4338 		if (print_ctrl_obj[idx].cat_info[category].category_verbose_mask
4339 		    & QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) {
4340 			print_ctrl_obj[idx].cat_info[category]
4341 				.category_verbose_mask &=
4342 				~QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose);
4343 		}
4344 	} else {
4345 		print_ctrl_obj[idx].cat_info[category].category_verbose_mask |=
4346 				QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose);
4347 	}
4348 
4349 	pr_debug("%s: Print control object %d, Category %d, Verbose level %d\n",
4350 		__func__,
4351 		idx,
4352 		category,
4353 		print_ctrl_obj[idx].cat_info[category].category_verbose_mask);
4354 
4355 	return QDF_STATUS_SUCCESS;
4356 }
4357 qdf_export_symbol(qdf_print_set_category_verbose);
4358 
4359 void qdf_log_dump_at_kernel_level(bool enable)
4360 {
4361 	if (qdf_log_dump_at_kernel_enable == enable) {
4362 		QDF_TRACE_INFO(QDF_MODULE_ID_QDF,
4363 			       "qdf_log_dump_at_kernel_enable is already %d\n",
4364 			       enable);
4365 	}
4366 	qdf_log_dump_at_kernel_enable = enable;
4367 }
4368 
4369 qdf_export_symbol(qdf_log_dump_at_kernel_level);
4370 
4371 bool qdf_print_is_category_enabled(unsigned int idx, QDF_MODULE_ID category)
4372 {
4373 	QDF_TRACE_LEVEL verbose_mask;
4374 
4375 	/* Check if index passed is valid */
4376 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
4377 		pr_info("%s: Invalid index - %d\n", __func__, idx);
4378 		return false;
4379 	}
4380 
4381 	/* Check if print control object is in use */
4382 	if (!print_ctrl_obj[idx].in_use) {
4383 		pr_info("%s: Invalid print control object\n", __func__);
4384 		return false;
4385 	}
4386 
4387 	/* Check if category passed is valid */
4388 	if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
4389 		pr_info("%s: Invalid category: %d\n", __func__, category);
4390 		return false;
4391 	}
4392 
4393 	verbose_mask =
4394 		print_ctrl_obj[idx].cat_info[category].category_verbose_mask;
4395 
4396 	if (verbose_mask == QDF_TRACE_LEVEL_NONE)
4397 		return false;
4398 	else
4399 		return true;
4400 }
4401 qdf_export_symbol(qdf_print_is_category_enabled);
4402 
4403 bool qdf_print_is_verbose_enabled(unsigned int idx, QDF_MODULE_ID category,
4404 				  QDF_TRACE_LEVEL verbose)
4405 {
4406 	bool verbose_enabled = false;
4407 
4408 	/* Check if index passed is valid */
4409 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
4410 		pr_info("%s: Invalid index - %d\n", __func__, idx);
4411 		return verbose_enabled;
4412 	}
4413 
4414 	/* Check if print control object is in use */
4415 	if (!print_ctrl_obj[idx].in_use) {
4416 		pr_info("%s: Invalid print control object\n", __func__);
4417 		return verbose_enabled;
4418 	}
4419 
4420 	/* Check if category passed is valid */
4421 	if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
4422 		pr_info("%s: Invalid category: %d\n", __func__, category);
4423 		return verbose_enabled;
4424 	}
4425 
4426 	if ((verbose == QDF_TRACE_LEVEL_NONE) ||
4427 	    (verbose >= QDF_TRACE_LEVEL_MAX)) {
4428 		verbose_enabled = false;
4429 	} else if (verbose == QDF_TRACE_LEVEL_ALL) {
4430 		if (print_ctrl_obj[idx].cat_info[category]
4431 					.category_verbose_mask == 0xFFFF)
4432 			verbose_enabled = true;
4433 	} else {
4434 		verbose_enabled =
4435 		(print_ctrl_obj[idx].cat_info[category].category_verbose_mask &
4436 		 QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) ? true : false;
4437 	}
4438 
4439 	return verbose_enabled;
4440 }
4441 qdf_export_symbol(qdf_print_is_verbose_enabled);
4442 
4443 #ifdef DBG_LVL_MAC_FILTERING
4444 
4445 QDF_STATUS qdf_print_set_node_flag(unsigned int idx, uint8_t enable)
4446 {
4447 	/* Check if index passed is valid */
4448 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
4449 		pr_info("%s: Invalid index - %d\n", __func__, idx);
4450 		return QDF_STATUS_E_FAILURE;
4451 	}
4452 
4453 	/* Check if print control object is in use */
4454 	if (!print_ctrl_obj[idx].in_use) {
4455 		pr_info("%s: Invalid print control object\n", __func__);
4456 		return QDF_STATUS_E_FAILURE;
4457 	}
4458 
4459 	if (enable > 1) {
4460 		pr_info("%s: Incorrect input: Use 1 or 0 to enable or disable\n",
4461 			__func__);
4462 		return QDF_STATUS_E_FAILURE;
4463 	}
4464 
4465 	print_ctrl_obj[idx].dbglvlmac_on = enable;
4466 	pr_info("%s: DbgLVLmac feature %s\n",
4467 		__func__,
4468 		((enable) ? "enabled" : "disabled"));
4469 
4470 	return QDF_STATUS_SUCCESS;
4471 }
4472 qdf_export_symbol(qdf_print_set_node_flag);
4473 
4474 bool qdf_print_get_node_flag(unsigned int idx)
4475 {
4476 	bool node_flag = false;
4477 
4478 	/* Check if index passed is valid */
4479 	if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
4480 		pr_info("%s: Invalid index - %d\n", __func__, idx);
4481 		return node_flag;
4482 	}
4483 
4484 	/* Check if print control object is in use */
4485 	if (!print_ctrl_obj[idx].in_use) {
4486 		pr_info("%s: Invalid print control object\n", __func__);
4487 		return node_flag;
4488 	}
4489 
4490 	if (print_ctrl_obj[idx].dbglvlmac_on)
4491 		node_flag = true;
4492 
4493 	return node_flag;
4494 }
4495 qdf_export_symbol(qdf_print_get_node_flag);
4496 
4497 void qdf_print_clean_node_flag(unsigned int idx)
4498 {
4499 	/* Disable dbglvlmac_on during cleanup */
4500 	print_ctrl_obj[idx].dbglvlmac_on = 0;
4501 }
4502 
4503 #else
4504 
4505 void qdf_print_clean_node_flag(unsigned int idx)
4506 {
4507 	/* No operation in case of no support for DBG_LVL_MAC_FILTERING */
4508 	return;
4509 }
4510 #endif
4511 
4512 void QDF_PRINT_INFO(unsigned int idx, QDF_MODULE_ID module,
4513 		    QDF_TRACE_LEVEL level,
4514 		    char *str_format, ...)
4515 {
4516 	va_list args;
4517 
4518 	/* Generic wrapper API will compile qdf_vprint in order to
4519 	 * log the message. Once QDF converged debug framework is in
4520 	 * place, this will be changed to adapt to the framework, compiling
4521 	 * call to converged tracing API
4522 	 */
4523 	va_start(args, str_format);
4524 	qdf_vprint(str_format, args);
4525 	va_end(args);
4526 }
4527 qdf_export_symbol(QDF_PRINT_INFO);
4528 
4529 #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
4530 void qdf_logging_init(void)
4531 {
4532 	wlan_logging_sock_init_svc();
4533 	nl_srv_init(NULL, WLAN_NLINK_PROTO_FAMILY);
4534 	wlan_logging_notifier_init(qdf_log_dump_at_kernel_enable);
4535 	wlan_logging_set_flush_timer(qdf_log_flush_timer_period);
4536 }
4537 
4538 void qdf_logging_exit(void)
4539 {
4540 	wlan_logging_notifier_deinit(qdf_log_dump_at_kernel_enable);
4541 	nl_srv_exit();
4542 	wlan_logging_sock_deinit_svc();
4543 }
4544 
4545 int qdf_logging_set_flush_timer(uint32_t milliseconds)
4546 {
4547 	if (wlan_logging_set_flush_timer(milliseconds) == 0)
4548 		return QDF_STATUS_SUCCESS;
4549 	else
4550 		return QDF_STATUS_E_FAILURE;
4551 }
4552 
4553 void qdf_logging_flush_logs(void)
4554 {
4555 	wlan_flush_host_logs_for_fatal();
4556 }
4557 
4558 #else
4559 void qdf_logging_init(void)
4560 {
4561 	nl_srv_init(NULL, WLAN_NLINK_PROTO_FAMILY);
4562 }
4563 
4564 void qdf_logging_exit(void)
4565 {
4566 	nl_srv_exit();
4567 }
4568 
4569 int qdf_logging_set_flush_timer(uint32_t milliseconds)
4570 {
4571 	return QDF_STATUS_E_FAILURE;
4572 }
4573 
4574 void qdf_logging_flush_logs(void)
4575 {
4576 }
4577 #endif
4578 
4579 qdf_export_symbol(qdf_logging_set_flush_timer);
4580 qdf_export_symbol(qdf_logging_flush_logs);
4581 
4582 #ifdef CONFIG_KALLSYMS
4583 inline int qdf_sprint_symbol(char *buffer, void *addr)
4584 {
4585 	return sprint_symbol(buffer, (unsigned long)addr);
4586 }
4587 #else
4588 int qdf_sprint_symbol(char *buffer, void *addr)
4589 {
4590 	if (!buffer)
4591 		return 0;
4592 
4593 	buffer[0] = '\0';
4594 	return 1;
4595 }
4596 #endif
4597 qdf_export_symbol(qdf_sprint_symbol);
4598 
4599 void qdf_set_pidx(int pidx)
4600 {
4601 	qdf_pidx = pidx;
4602 }
4603 qdf_export_symbol(qdf_set_pidx);
4604 
4605 int qdf_get_pidx(void)
4606 {
4607 	return qdf_pidx;
4608 }
4609 qdf_export_symbol(qdf_get_pidx);
4610 
4611 #ifdef PANIC_ON_BUG
4612 #ifdef CONFIG_SLUB_DEBUG
4613 void __qdf_bug(void)
4614 {
4615 	BUG();
4616 }
4617 qdf_export_symbol(__qdf_bug);
4618 #endif /* CONFIG_SLUB_DEBUG */
4619 #endif /* PANIC_ON_BUG */
4620 
4621 #ifdef WLAN_QCOM_VA_MINIDUMP
4622 static bool qdf_va_md_initialized;
4623 static qdf_list_t qdf_va_md_list;
4624 static qdf_spinlock_t qdf_va_md_list_lock;
4625 #define QDF_MINIDUMP_LIST_SIZE 128
4626 
4627 struct qdf_va_md_entry {
4628 	qdf_list_node_t node;
4629 	struct va_md_entry data;
4630 };
4631 
4632 static int qdf_va_md_notif_handler(struct notifier_block *this,
4633 				   unsigned long event, void *ptr)
4634 {
4635 	struct qdf_va_md_entry *entry;
4636 	struct qdf_va_md_entry *next;
4637 
4638 	qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
4639 	qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
4640 		qcom_va_md_add_region(&entry->data);
4641 	}
4642 
4643 	qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
4644 	return NOTIFY_OK;
4645 }
4646 
4647 static struct notifier_block qdf_va_md_notif_blk = {
4648 	.notifier_call = qdf_va_md_notif_handler,
4649 	.priority = INT_MAX,
4650 };
4651 
4652 void __qdf_minidump_init(void)
4653 {
4654 	int ret;
4655 
4656 	if (qdf_va_md_initialized)
4657 		return;
4658 
4659 	qdf_spinlock_create(&qdf_va_md_list_lock);
4660 	qdf_list_create(&qdf_va_md_list, QDF_MINIDUMP_LIST_SIZE);
4661 	ret = qcom_va_md_register(qdf_trace_wlan_modname(),
4662 				  &qdf_va_md_notif_blk);
4663 	qdf_va_md_initialized = !ret;
4664 }
4665 
4666 qdf_export_symbol(__qdf_minidump_init);
4667 
4668 void __qdf_minidump_deinit(void)
4669 {
4670 	struct qdf_va_md_entry *entry;
4671 	struct qdf_va_md_entry *next;
4672 
4673 	if (!qdf_va_md_initialized)
4674 		return;
4675 
4676 	qdf_va_md_initialized = false;
4677 	qcom_va_md_unregister(qdf_trace_wlan_modname(),
4678 			      &qdf_va_md_notif_blk);
4679 	qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
4680 	qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
4681 		qdf_list_remove_node(&qdf_va_md_list, &entry->node);
4682 		qdf_mem_free(entry);
4683 	}
4684 
4685 	qdf_list_destroy(&qdf_va_md_list);
4686 	qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
4687 	qdf_spinlock_destroy(&qdf_va_md_list_lock);
4688 }
4689 
4690 qdf_export_symbol(__qdf_minidump_deinit);
4691 
4692 void __qdf_minidump_log(void *start_addr, size_t size, const char *name)
4693 {
4694 	struct qdf_va_md_entry *entry;
4695 	QDF_STATUS status;
4696 
4697 	if (!qdf_va_md_initialized)
4698 		return;
4699 
4700 	entry = qdf_mem_malloc(sizeof(*entry));
4701 	if (!entry) {
4702 		qdf_err("malloc failed for %s: %pK, %zu",
4703 			name, start_addr, size);
4704 		return;
4705 	}
4706 
4707 	qdf_str_lcopy(entry->data.owner, name, sizeof(entry->data.owner));
4708 	entry->data.vaddr = (unsigned long)start_addr;
4709 	entry->data.size = size;
4710 
4711 	qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
4712 	status = qdf_list_insert_front(&qdf_va_md_list, &entry->node);
4713 	qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
4714 	if (QDF_IS_STATUS_ERROR(status)) {
4715 		qdf_err("Failed to insert qdf va md entry, status %d", status);
4716 		qdf_mem_free(entry);
4717 	}
4718 }
4719 
4720 qdf_export_symbol(__qdf_minidump_log);
4721 
4722 void __qdf_minidump_remove(void *addr, size_t size, const char *name)
4723 {
4724 	struct qdf_va_md_entry *entry;
4725 	struct qdf_va_md_entry *next;
4726 
4727 	if (!qdf_va_md_initialized)
4728 		return;
4729 
4730 	qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
4731 	qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
4732 		if (entry->data.vaddr == (unsigned long)addr &&
4733 		    entry->data.size == size &&
4734 		    !qdf_str_cmp(entry->data.owner, name)) {
4735 			qdf_list_remove_node(&qdf_va_md_list, &entry->node);
4736 			qdf_mem_free(entry);
4737 			break;
4738 		}
4739 	}
4740 
4741 	qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
4742 }
4743 
4744 qdf_export_symbol(__qdf_minidump_remove);
4745 #endif
4746