xref: /wlan-dirver/qca-wifi-host-cmn/utils/logging/src/wlan_logging_sock_svc.c (revision 8cfe6b10058a04cafb17eed051f2ddf11bee8931)
1 /*
2  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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 * wlan_logging_sock_svc.c
22 *
23 ******************************************************************************/
24 
25 #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
26 #include <linux/vmalloc.h>
27 #include <wlan_logging_sock_svc.h>
28 #include <linux/kthread.h>
29 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0))
30 #include <linux/panic_notifier.h>
31 #endif
32 #include <qdf_time.h>
33 #include <qdf_trace.h>
34 #include <qdf_mc_timer.h>
35 #include <qdf_timer.h>
36 #include <qdf_lock.h>
37 #include <wlan_ptt_sock_svc.h>
38 #include <host_diag_core_event.h>
39 #include "host_diag_core_log.h"
40 #include <qdf_event.h>
41 #include <qdf_module.h>
42 #include <qdf_str.h>
43 #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
44 #include <wlan_connectivity_logging.h>
45 #endif
46 
47 #include "qdf_ssr_driver_dump.h"
48 #ifdef CNSS_GENL
49 #ifdef CONFIG_CNSS_OUT_OF_TREE
50 #include "cnss_nl.h"
51 #else
52 #include <net/cnss_nl.h>
53 #endif
54 #endif
55 
56 #if defined(FEATURE_FW_LOG_PARSING) || defined(FEATURE_WLAN_DIAG_SUPPORT) || \
57 	defined(CONNECTIVITY_PKTLOG)
58 #include <cds_api.h>
59 #include "ani_global.h"
60 #endif
61 
62 #ifdef CONNECTIVITY_PKTLOG
63 #include "wma.h"
64 #include "pktlog_ac.h"
65 #include <cdp_txrx_misc.h>
66 #endif
67 
68 /*
69  * The following commit was introduced in v5.17:
70  * cead18552660 ("exit: Rename complete_and_exit to kthread_complete_and_exit")
71  * Use the old name for kernels before 5.17
72  */
73 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
74 #define kthread_complete_and_exit(c, s) complete_and_exit(c, s)
75 #endif
76 
77 #define MAX_NUM_PKT_LOG 32
78 
79 #define LOGGING_TRACE(level, args ...) \
80 	QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args)
81 
82 /* Global variables */
83 
84 #define ANI_NL_MSG_LOG_TYPE 89
85 #define ANI_NL_MSG_READY_IND_TYPE 90
86 #ifndef MAX_LOGMSG_COUNT
87 #define MAX_LOGMSG_COUNT 256
88 #endif
89 #define MAX_LOGMSG_LENGTH 2048
90 #define MAX_SKBMSG_LENGTH 4096
91 
92 #define WLAN_LOG_BUFFER_SIZE 2048
93 #ifdef CONNECTIVITY_PKTLOG
94 /**
95  * Buffer to accommodate -
96  * pktlog buffer (2048 bytes)
97  * ath_pktlog_hdr (16 bytes)
98  * pkt_dump (8 bytes)
99  * extra padding (40 bytes)
100  *
101  * Note: pktlog buffer size is dependent on RX_BUFFER_SIZE and
102  * HTT_T2H_MAX_MSG_SIZE. Adjust WLAN_LOG_BUFFER_SIZE
103  * based on the above mentioned macros.
104  */
105 #define ATH_PKTLOG_HDR_SIZE (sizeof(struct ath_pktlog_hdr))
106 #define PKT_DUMP_HDR_SIZE (sizeof(struct packet_dump))
107 #define EXTRA_PADDING 40
108 
109 #define MAX_PKTSTATS_LENGTH \
110 	((WLAN_LOG_BUFFER_SIZE) + (ATH_PKTLOG_HDR_SIZE) + \
111 	 (PKT_DUMP_HDR_SIZE) + (EXTRA_PADDING))
112 #else
113 #define MAX_PKTSTATS_LENGTH WLAN_LOG_BUFFER_SIZE
114 #endif /* CONNECTIVITY_PKTLOG */
115 
116 #define MAX_PKTSTATS_BUFF   16
117 #define HOST_LOG_DRIVER_MSG              0x001
118 #define HOST_LOG_PER_PKT_STATS           0x002
119 #define HOST_LOG_FW_FLUSH_COMPLETE       0x003
120 #define HOST_LOG_DRIVER_CONNECTIVITY_MSG 0x004
121 
122 #define DIAG_TYPE_LOGS                 1
123 #define PTT_MSG_DIAG_CMDS_TYPE    0x5050
124 #define MAX_LOG_LINE 500
125 
126 /* default rate limit period - 2sec */
127 #define PANIC_WIFILOG_PRINT_RATE_LIMIT_PERIOD (2*HZ)
128 /* default burst for rate limit */
129 #define PANIC_WIFILOG_PRINT_RATE_LIMIT_BURST_DEFAULT 500
130 DEFINE_RATELIMIT_STATE(panic_wifilog_ratelimit,
131 		       PANIC_WIFILOG_PRINT_RATE_LIMIT_PERIOD,
132 		       PANIC_WIFILOG_PRINT_RATE_LIMIT_BURST_DEFAULT);
133 
134 #define FLUSH_LOG_COMPLETION_TIMEOUT 3000
135 
136 struct log_msg {
137 	struct list_head node;
138 	unsigned int radio;
139 	unsigned int index;
140 	/* indicates the current filled log length in logbuf */
141 	unsigned int filled_length;
142 	/*
143 	 * Buf to hold the log msg
144 	 * tAniHdr + log
145 	 */
146 	char logbuf[MAX_LOGMSG_LENGTH];
147 };
148 
149 /**
150  * struct packet_dump - This data structure contains the
151  * Tx/Rx packet stats
152  * @status: Status
153  * @type: Type
154  * @driver_ts: driver timestamp
155  * @fw_ts: fw timestamp
156  */
157 struct packet_dump {
158 	unsigned char status;
159 	unsigned char type;
160 	uint32_t driver_ts;
161 	uint16_t fw_ts;
162 } __attribute__((__packed__));
163 
164 /**
165  * struct pkt_stats_msg - This data structure contains the
166  * pkt stats node for link list
167  * @node: LinkList node
168  * @node: Pointer to skb
169  */
170 struct pkt_stats_msg {
171 	struct list_head node;
172 	struct sk_buff *skb;
173 };
174 
175 #define MAX_FLUSH_TIMER_PERIOD_VALUE 3600000 /* maximum of 1 hour (in ms) */
176 struct wlan_logging {
177 	/* Console log levels */
178 	uint32_t console_log_levels;
179 	/* Number of buffers to be used for logging */
180 	uint32_t num_buf;
181 	uint32_t buffer_length;
182 	/* Lock to synchronize access to shared logging resource */
183 	spinlock_t spin_lock;
184 	/* Holds the free node which can be used for filling logs */
185 	struct list_head free_list;
186 	/* Holds the filled nodes which needs to be indicated to APP */
187 	struct list_head filled_list;
188 	/* Holds nodes for console printing in case of kernel panic */
189 	struct list_head panic_list;
190 	/* Wait queue for Logger thread */
191 	wait_queue_head_t wait_queue;
192 	/* Logger thread */
193 	struct task_struct *thread;
194 	/* Logging thread sets this variable on exit */
195 	struct completion shutdown_comp;
196 	/* Indicates to logger thread to exit */
197 	bool exit;
198 	/* Holds number of dropped logs */
199 	unsigned int drop_count;
200 	/* current logbuf to which the log will be filled to */
201 	struct log_msg *pcur_node;
202 	/* Event flag used for wakeup and post indication*/
203 	unsigned long eventFlag;
204 	/* Indicates logger thread is activated */
205 	bool is_active;
206 	/* Flush completion check */
207 	bool is_flush_complete;
208 	/* parameters  for pkt stats */
209 	struct list_head pkt_stat_free_list;
210 	struct list_head pkt_stat_filled_list;
211 	struct pkt_stats_msg *pkt_stats_pcur_node;
212 	unsigned int pkt_stat_drop_cnt;
213 	spinlock_t pkt_stats_lock;
214 	unsigned int pkt_stats_msg_idx;
215 	qdf_timer_t flush_timer;
216 	bool is_flush_timer_initialized;
217 	uint32_t flush_timer_period;
218 	qdf_spinlock_t flush_timer_lock;
219 	qdf_event_t flush_log_completion;
220 	uint64_t wakup_ts;
221 	uint64_t start_ts;
222 	uint64_t reinitcompletion_ts;
223 	uint64_t set_exit_ts;
224 	uint64_t exit_ts;
225 };
226 
227 /* This global variable is intentionally not marked static because it
228  * is used by offline tools. Please do not use it outside this file.
229  */
230 struct wlan_logging gwlan_logging;
231 static struct pkt_stats_msg *gpkt_stats_buffers;
232 
233 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
234 
235 static struct log_msg *gplog_msg;
236 
237 static inline QDF_STATUS allocate_log_msg_buffer(void)
238 {
239 	gplog_msg = qdf_mem_valloc(MAX_LOGMSG_COUNT * sizeof(*gplog_msg));
240 
241 	return gplog_msg ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
242 }
243 
244 static inline void free_log_msg_buffer(void)
245 {
246 	qdf_mem_vfree(gplog_msg);
247 	gplog_msg = NULL;
248 }
249 
250 #else
251 static struct log_msg gplog_msg[MAX_LOGMSG_COUNT];
252 
253 static inline QDF_STATUS allocate_log_msg_buffer(void)
254 {
255 	qdf_minidump_log(gplog_msg, sizeof(gplog_msg), "wlan_logs");
256 	qdf_ssr_driver_dump_register_region("gwlan_logging", &gwlan_logging,
257 					    sizeof(gwlan_logging));
258 	qdf_ssr_driver_dump_register_region("wlan_logs", gplog_msg,
259 					    sizeof(gplog_msg));
260 	return QDF_STATUS_SUCCESS;
261 }
262 
263 static inline void free_log_msg_buffer(void)
264 {
265 	qdf_ssr_driver_dump_unregister_region("wlan_logs");
266 	qdf_ssr_driver_dump_unregister_region("gwlan_logging");
267 	qdf_minidump_remove(gplog_msg, sizeof(gplog_msg), "wlan_logs");
268 }
269 #endif
270 
271 /* Need to call this with spin_lock acquired */
272 static int wlan_queue_logmsg_for_app(void)
273 {
274 	char *ptr;
275 	int ret = 0;
276 	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
277 	ptr[gwlan_logging.pcur_node->filled_length] = '\0';
278 
279 	*(unsigned short *)(gwlan_logging.pcur_node->logbuf) =
280 		ANI_NL_MSG_LOG_TYPE;
281 	*(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) =
282 		gwlan_logging.pcur_node->filled_length;
283 	list_add_tail(&gwlan_logging.pcur_node->node,
284 		      &gwlan_logging.filled_list);
285 
286 	if (!list_empty(&gwlan_logging.free_list)) {
287 		/* Get buffer from free list */
288 		gwlan_logging.pcur_node =
289 			(struct log_msg *)(gwlan_logging.free_list.next);
290 		list_del_init(gwlan_logging.free_list.next);
291 	} else if (!list_empty(&gwlan_logging.filled_list)) {
292 		/* Get buffer from filled list */
293 		/* This condition will drop the packet from being
294 		 * indicated to app
295 		 */
296 		gwlan_logging.pcur_node =
297 			(struct log_msg *)(gwlan_logging.filled_list.next);
298 		++gwlan_logging.drop_count;
299 		list_del_init(gwlan_logging.filled_list.next);
300 		ret = 1;
301 	}
302 
303 	/* Reset the current node values */
304 	gwlan_logging.pcur_node->filled_length = 0;
305 	return ret;
306 }
307 
308 static const char *current_process_name(void)
309 {
310 	if (in_irq())
311 		return "irq";
312 
313 	if (in_softirq())
314 		return "soft_irq";
315 
316 	return current->comm;
317 }
318 
319 /**
320  * wlan_add_user_log_time_stamp() - populate firmware and kernel timestamps
321  * @tbuf: Pointer to time stamp buffer
322  * @tbuf_sz: Time buffer size
323  * @ts: Time stamp value
324  *
325  * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag
326  * to convert it into user visible time stamp. In adrstea FW also uses QTIMER
327  * raw ticks which is needed to synchronize host and fw log time stamps
328  *
329  * Also add logcat timestamp so that driver logs and
330  * logcat logs can be co-related
331  *
332  * For discrete solution e.g rome use system tick and convert it into
333  * seconds.milli seconds
334  *
335  * Return: number of characters written in target buffer not including
336  *		trailing '/0'
337  */
338 static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts)
339 {
340 	char time_buf[20];
341 
342 	qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
343 
344 	return scnprintf(tbuf, tbuf_sz, "[%.6s][0x%llx]%s",
345 			 current_process_name(), (unsigned long long)ts,
346 			 time_buf);
347 }
348 
349 #ifdef WLAN_MAX_LOGS_PER_SEC
350 static inline void wlan_panic_on_excessive_logging(void)
351 {
352 	if (qdf_detected_excessive_logging())
353 		QDF_DEBUG_PANIC("Exceeded %d logs per second",
354 				WLAN_MAX_LOGS_PER_SEC);
355 }
356 #else
357 static inline void wlan_panic_on_excessive_logging(void) {}
358 #endif /* WLAN_MAX_LOGS_PER_SEC */
359 
360 #ifdef QDF_TRACE_PRINT_ENABLE
361 static inline void
362 log_to_console(QDF_TRACE_LEVEL level, const char *timestamp, const char *msg)
363 {
364 	if (qdf_detected_excessive_logging()) {
365 		qdf_rl_print_suppressed_inc();
366 		return;
367 	}
368 
369 	qdf_rl_print_suppressed_log();
370 	pr_err("%s %s\n", timestamp, msg);
371 }
372 #else
373 static inline void
374 log_to_console(QDF_TRACE_LEVEL level, const char *timestamp, const char *msg)
375 {
376 	switch (level) {
377 	case QDF_TRACE_LEVEL_FATAL:
378 		pr_alert("%s %s\n", timestamp, msg);
379 		wlan_panic_on_excessive_logging();
380 		break;
381 	case QDF_TRACE_LEVEL_ERROR:
382 		pr_err("%s %s\n", timestamp, msg);
383 		wlan_panic_on_excessive_logging();
384 		break;
385 	case QDF_TRACE_LEVEL_WARN:
386 		pr_warn("%s %s\n", timestamp, msg);
387 		wlan_panic_on_excessive_logging();
388 		break;
389 	case QDF_TRACE_LEVEL_INFO:
390 		pr_info("%s %s\n", timestamp, msg);
391 		wlan_panic_on_excessive_logging();
392 		break;
393 	case QDF_TRACE_LEVEL_INFO_HIGH:
394 	case QDF_TRACE_LEVEL_INFO_MED:
395 	case QDF_TRACE_LEVEL_INFO_LOW:
396 	case QDF_TRACE_LEVEL_DEBUG:
397 	default:
398 		/* these levels should not be logged to console */
399 		break;
400 	}
401 }
402 #endif
403 
404 int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length)
405 {
406 	char *ptr;
407 	char tbuf[60];
408 	int tlen;
409 	int total_log_len;
410 	unsigned int *pfilled_length;
411 	bool wake_up_thread = false;
412 	unsigned long flags;
413 	uint64_t ts;
414 
415 	/* Add the current time stamp */
416 	ts = qdf_get_log_timestamp();
417 	tlen = wlan_add_user_log_time_stamp(tbuf, sizeof(tbuf), ts);
418 
419 	/* if logging isn't up yet, just dump to dmesg */
420 	if (!gwlan_logging.is_active) {
421 		log_to_console(log_level, tbuf, to_be_sent);
422 		return 0;
423 	}
424 
425 	/* 1+1 indicate '\n'+'\0' */
426 	total_log_len = length + tlen + 1 + 1;
427 
428 	spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
429 	/* wlan logging svc resources are not yet initialized */
430 	if (!gwlan_logging.pcur_node) {
431 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
432 		return -EIO;
433 	}
434 
435 	pfilled_length = &gwlan_logging.pcur_node->filled_length;
436 
437 	/* Check if we can accommodate more log into current node/buffer */
438 	if ((MAX_LOGMSG_LENGTH - (*pfilled_length +
439 			sizeof(tAniNlHdr))) < total_log_len) {
440 		wake_up_thread = true;
441 		wlan_queue_logmsg_for_app();
442 		pfilled_length = &gwlan_logging.pcur_node->filled_length;
443 	}
444 
445 	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
446 
447 	if (unlikely(MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len))) {
448 		/*
449 		 * Assumption here is that we receive logs which is less than
450 		 * MAX_LOGMSG_LENGTH, where we can accommodate the
451 		 * tAniNlHdr + [context][timestamp] + log
452 		 * If log length is over MAX_LOGMSG_LENGTH,
453 		 * the overflow part will be discarded.
454 		 */
455 		length = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - tlen - 2;
456 		/*
457 		 * QDF_ASSERT if complete log was not accommodated into
458 		 * the available buffer.
459 		 */
460 		QDF_ASSERT(0);
461 	}
462 
463 	memcpy(&ptr[*pfilled_length], tbuf, tlen);
464 	memcpy(&ptr[*pfilled_length + tlen], to_be_sent, length);
465 	*pfilled_length += tlen + length;
466 	ptr[*pfilled_length] = '\n';
467 	*pfilled_length += 1;
468 
469 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
470 
471 	/* Wakeup logger thread */
472 	if (wake_up_thread) {
473 		set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
474 		wake_up_interruptible(&gwlan_logging.wait_queue);
475 	}
476 
477 	if (gwlan_logging.console_log_levels & BIT(log_level))
478 		log_to_console(log_level, tbuf, to_be_sent);
479 
480 	return 0;
481 }
482 
483 /**
484  * nl_srv_bcast_host_logs() - Wrapper to send bcast msgs to host logs mcast grp
485  * @skb: sk buffer pointer
486  *
487  * Sends the bcast message to host logs multicast group with generic nl socket
488  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
489  *
490  * Return: zero on success, error code otherwise
491  */
492 #ifdef CNSS_GENL
493 static int nl_srv_bcast_host_logs(struct sk_buff *skb)
494 {
495 	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
496 }
497 #else
498 static int nl_srv_bcast_host_logs(struct sk_buff *skb)
499 {
500 	return nl_srv_bcast(skb);
501 }
502 #endif
503 
504 #ifdef CONNECTIVITY_PKTLOG
505 /**
506  * pkt_stats_fill_headers() - This function adds headers to skb
507  * @skb: skb to which headers need to be added
508  *
509  * Return: 0 on success or Errno on failure
510  */
511 static int pkt_stats_fill_headers(struct sk_buff *skb)
512 {
513 	struct host_log_pktlog_info cds_pktlog;
514 	int cds_pkt_size = sizeof(struct host_log_pktlog_info);
515 	tAniNlHdr msg_header;
516 	int extra_header_len, nl_payload_len;
517 	static int nlmsg_seq;
518 	int diag_type;
519 
520 	qdf_mem_zero(&cds_pktlog, cds_pkt_size);
521 	cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
522 	cds_pktlog.buf_len = skb->len;
523 	cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
524 	host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C);
525 	host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len +
526 				cds_pkt_size);
527 
528 	if (unlikely(skb_headroom(skb) < cds_pkt_size)) {
529 		qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
530 			     __LINE__, skb->head, skb->data,
531 			     sizeof(msg_header));
532 		return -EIO;
533 	}
534 
535 	qdf_mem_copy(skb_push(skb, cds_pkt_size),
536 			&cds_pktlog, cds_pkt_size);
537 
538 	if (unlikely(skb_headroom(skb) < sizeof(int))) {
539 		qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
540 			     __LINE__, skb->head, skb->data,
541 			     sizeof(int));
542 		return -EIO;
543 	}
544 
545 	diag_type = DIAG_TYPE_LOGS;
546 	qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int));
547 
548 	extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) +
549 				sizeof(struct nlmsghdr);
550 	nl_payload_len = extra_header_len + skb->len;
551 
552 	msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
553 	msg_header.nlh.nlmsg_len = nl_payload_len;
554 	msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
555 	msg_header.nlh.nlmsg_pid = 0;
556 	msg_header.nlh.nlmsg_seq = nlmsg_seq++;
557 	msg_header.radio = 0;
558 	msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
559 	msg_header.wmsg.length = cpu_to_be16(skb->len);
560 
561 	if (unlikely(skb_headroom(skb) < sizeof(msg_header))) {
562 		qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
563 			     __LINE__, skb->head, skb->data,
564 			     sizeof(msg_header));
565 		return -EIO;
566 	}
567 
568 	qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header,
569 			sizeof(msg_header));
570 
571 	return 0;
572 }
573 
574 /**
575  * nl_srv_bcast_diag() - Wrapper to send bcast msgs to diag events mcast grp
576  * @skb: sk buffer pointer
577  *
578  * Sends the bcast message to diag events multicast group with generic nl socket
579  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
580  *
581  * Return: zero on success, error code otherwise
582  */
583 static int nl_srv_bcast_diag(struct sk_buff *skb)
584 {
585 #ifdef CNSS_GENL
586 	return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
587 #else
588 	return nl_srv_bcast(skb);
589 #endif
590 }
591 
592 /**
593  * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per
594  * packet statistics to the user
595  *
596  * This function is used to send the per packet statistics to the user
597  *
598  * Return: Success if the message is posted to user
599  */
600 static int pktlog_send_per_pkt_stats_to_user(void)
601 {
602 	int ret = -1;
603 	struct pkt_stats_msg *pstats_msg;
604 	unsigned long flags;
605 	struct sk_buff *skb_new = NULL;
606 	static int rate_limit;
607 	bool free_old_skb = false;
608 
609 	while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
610 		&& !gwlan_logging.exit) {
611 		skb_new = dev_alloc_skb(MAX_SKBMSG_LENGTH);
612 		if (!skb_new) {
613 			if (!rate_limit) {
614 				qdf_err("dev_alloc_skb() failed for msg size[%d] drop count = %u",
615 					MAX_SKBMSG_LENGTH,
616 					gwlan_logging.drop_count);
617 			}
618 			rate_limit = 1;
619 			ret = -ENOMEM;
620 			break;
621 		}
622 
623 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
624 
625 		pstats_msg = (struct pkt_stats_msg *)
626 			(gwlan_logging.pkt_stat_filled_list.next);
627 		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
628 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
629 
630 		ret = pkt_stats_fill_headers(pstats_msg->skb);
631 		if (ret < 0) {
632 			qdf_err("Failed to fill headers %d", ret);
633 			free_old_skb = true;
634 			goto err;
635 		}
636 		ret = nl_srv_bcast_diag(pstats_msg->skb);
637 		if (ret < 0) {
638 			qdf_info("Send Failed %d drop_count = %u", ret,
639 				++gwlan_logging.pkt_stat_drop_cnt);
640 		} else {
641 			ret = 0;
642 		}
643 err:
644 	/*
645 	 * Free old skb in case or error before assigning new skb
646 	 * to the free list.
647 	 */
648 	if (free_old_skb)
649 		dev_kfree_skb(pstats_msg->skb);
650 
651 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
652 		pstats_msg->skb = skb_new;
653 		list_add_tail(&pstats_msg->node,
654 				&gwlan_logging.pkt_stat_free_list);
655 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
656 		ret = 0;
657 	}
658 
659 	return ret;
660 
661 }
662 #else
663 static inline
664 int pktlog_send_per_pkt_stats_to_user(void)
665 {
666 	return 0;
667 }
668 #endif
669 
670 static int send_filled_buffers_to_user(void)
671 {
672 	int ret = -1;
673 	struct log_msg *plog_msg;
674 	int payload_len;
675 	int tot_msg_len;
676 	tAniNlHdr *wnl;
677 	struct sk_buff *skb = NULL;
678 	struct nlmsghdr *nlh;
679 	static int nlmsg_seq;
680 	unsigned long flags;
681 	static int rate_limit;
682 
683 	while (!list_empty(&gwlan_logging.filled_list)
684 	       && !gwlan_logging.exit) {
685 
686 		skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
687 		if (!skb) {
688 			if (!rate_limit) {
689 				qdf_err("dev_alloc_skb() failed for msg size[%d] drop count = %u",
690 					MAX_LOGMSG_LENGTH,
691 					gwlan_logging.drop_count);
692 			}
693 			rate_limit = 1;
694 			ret = -ENOMEM;
695 			break;
696 		}
697 		rate_limit = 0;
698 
699 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
700 
701 		plog_msg = (struct log_msg *)
702 			   (gwlan_logging.filled_list.next);
703 		list_del_init(gwlan_logging.filled_list.next);
704 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
705 		/* 4 extra bytes for the radio idx */
706 		payload_len = plog_msg->filled_length +
707 			      sizeof(wnl->radio) + sizeof(tAniHdr);
708 
709 		tot_msg_len = NLMSG_SPACE(payload_len);
710 		nlh = nlmsg_put(skb, 0, nlmsg_seq++,
711 				ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST);
712 		if (!nlh) {
713 			spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
714 			list_add_tail(&plog_msg->node,
715 				      &gwlan_logging.free_list);
716 			spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
717 			qdf_err("drop_count = %u", ++gwlan_logging.drop_count);
718 			qdf_err("nlmsg_put() failed for msg size[%d]",
719 				tot_msg_len);
720 			dev_kfree_skb(skb);
721 			skb = NULL;
722 			ret = -EINVAL;
723 			continue;
724 		}
725 
726 		wnl = (tAniNlHdr *) nlh;
727 		wnl->radio = plog_msg->radio;
728 		memcpy(&wnl->wmsg, plog_msg->logbuf,
729 		       plog_msg->filled_length + sizeof(tAniHdr));
730 
731 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
732 		list_add_tail(&plog_msg->node, &gwlan_logging.free_list);
733 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
734 
735 		ret = nl_srv_bcast_host_logs(skb);
736 		/* print every 64th drop count */
737 		if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) {
738 			qdf_err("Send Failed %d drop_count = %u",
739 				ret, ++gwlan_logging.drop_count);
740 		}
741 	}
742 
743 	return ret;
744 }
745 
746 #ifdef FEATURE_WLAN_DIAG_SUPPORT
747 /**
748  * wlan_report_log_completion() - Report bug report completion to userspace
749  * @is_fatal: Type of event, fatal or not
750  * @indicator: Source of bug report, framework/host/firmware
751  * @reason_code: Reason for triggering bug report
752  * @ring_id: Ring id of logging entities
753  *
754  * This function is used to report the bug report completion to userspace
755  *
756  * Return: None
757  */
758 void wlan_report_log_completion(uint32_t is_fatal,
759 		uint32_t indicator,
760 		uint32_t reason_code,
761 		uint8_t ring_id)
762 {
763 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
764 			struct host_event_wlan_log_complete);
765 
766 	wlan_diag_event.is_fatal = is_fatal;
767 	wlan_diag_event.indicator = indicator;
768 	wlan_diag_event.reason_code = reason_code;
769 	wlan_diag_event.reserved = ring_id;
770 
771 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
772 }
773 #endif
774 
775 #ifdef FEATURE_WLAN_DIAG_SUPPORT
776 /**
777  * send_flush_completion_to_user() - Indicate flush completion to the user
778  * @ring_id:  Ring id of logging entities
779  *
780  * This function is used to send the flush completion message to user space
781  *
782  * Return: None
783  */
784 static void send_flush_completion_to_user(uint8_t ring_id)
785 {
786 	uint32_t is_fatal, indicator, reason_code;
787 	bool recovery_needed;
788 
789 	cds_get_and_reset_log_completion(&is_fatal,
790 		&indicator, &reason_code, &recovery_needed);
791 
792 	/* Error on purpose, so that it will get logged in the kmsg */
793 	LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
794 			"%s: Sending flush done to userspace reason code %d",
795 			__func__, reason_code);
796 
797 	wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id);
798 
799 	if (recovery_needed)
800 		cds_trigger_recovery(QDF_REASON_UNSPECIFIED);
801 }
802 #endif
803 
804 static void wlan_logging_set_flush_log_completion(void)
805 {
806 	qdf_event_set(&gwlan_logging.flush_log_completion);
807 }
808 
809 QDF_STATUS wlan_logging_wait_for_flush_log_completion(void)
810 {
811 	qdf_event_reset(&gwlan_logging.flush_log_completion);
812 
813 	return qdf_wait_for_event_completion(
814 					&gwlan_logging.flush_log_completion,
815 					FLUSH_LOG_COMPLETION_TIMEOUT);
816 }
817 
818 static void setup_flush_timer(void)
819 {
820 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
821 	if (!gwlan_logging.is_flush_timer_initialized ||
822 	    (gwlan_logging.flush_timer_period == 0)) {
823 		qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
824 		return;
825 	}
826 	qdf_timer_mod(&gwlan_logging.flush_timer,
827 		      gwlan_logging.flush_timer_period);
828 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
829 }
830 
831 #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
832 static QDF_STATUS
833 wlan_logging_send_connectivity_event(void)
834 {
835 	return wlan_connectivity_log_dequeue();
836 }
837 #else
838 static inline QDF_STATUS
839 wlan_logging_send_connectivity_event(void)
840 {
841 	return QDF_STATUS_E_NOSUPPORT;
842 }
843 #endif
844 
845 /**
846  * wlan_logging_thread() - The WLAN Logger thread
847  * @Arg - pointer to the HDD context
848  *
849  * This thread logs log message to App registered for the logs.
850  */
851 static int wlan_logging_thread(void *Arg)
852 {
853 	int ret_wait_status = 0;
854 	int ret = 0;
855 	unsigned long flags;
856 
857 	gwlan_logging.start_ts = qdf_get_log_timestamp();
858 
859 	while (!gwlan_logging.exit) {
860 		setup_flush_timer();
861 		ret_wait_status =
862 			wait_event_interruptible(gwlan_logging.wait_queue,
863 						 (!list_empty
864 							  (&gwlan_logging.filled_list)
865 						  || test_bit(
866 						     HOST_LOG_DRIVER_MSG,
867 						     &gwlan_logging.eventFlag)
868 						  || test_bit(
869 						     HOST_LOG_PER_PKT_STATS,
870 						     &gwlan_logging.eventFlag)
871 						  || test_bit(
872 						     HOST_LOG_FW_FLUSH_COMPLETE,
873 						     &gwlan_logging.eventFlag)
874 						  || test_bit(
875 						     HOST_LOG_DRIVER_CONNECTIVITY_MSG,
876 						     &gwlan_logging.eventFlag)
877 						  || gwlan_logging.exit));
878 
879 		if (ret_wait_status == -ERESTARTSYS) {
880 			qdf_err("wait_event_interruptible returned -ERESTARTSYS");
881 			break;
882 		}
883 
884 		if (gwlan_logging.exit)
885 			break;
886 
887 
888 		if (test_and_clear_bit(HOST_LOG_DRIVER_MSG,
889 					&gwlan_logging.eventFlag)) {
890 			ret = send_filled_buffers_to_user();
891 			if (-ENOMEM == ret)
892 				msleep(200);
893 #ifdef FEATURE_WLAN_DIAG_SUPPORT
894 			if (WLAN_LOG_INDICATOR_HOST_ONLY ==
895 			   cds_get_log_indicator()) {
896 				send_flush_completion_to_user(
897 						RING_ID_DRIVER_DEBUG);
898 			}
899 #endif
900 		}
901 
902 		if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS,
903 					&gwlan_logging.eventFlag)) {
904 			ret = pktlog_send_per_pkt_stats_to_user();
905 			if (-ENOMEM == ret)
906 				msleep(200);
907 		}
908 
909 		if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE,
910 					&gwlan_logging.eventFlag)) {
911 			/* Flush bit could have been set while we were mid
912 			 * way in the logging thread. So, need to check other
913 			 * buffers like log messages, per packet stats again
914 			 * to flush any residual data in them
915 			 */
916 			if (gwlan_logging.is_flush_complete == true) {
917 				gwlan_logging.is_flush_complete = false;
918 #ifdef FEATURE_WLAN_DIAG_SUPPORT
919 				send_flush_completion_to_user(
920 						RING_ID_DRIVER_DEBUG);
921 #endif
922 				wlan_logging_set_flush_log_completion();
923 			} else {
924 				gwlan_logging.is_flush_complete = true;
925 				/* Flush all current host logs*/
926 				spin_lock_irqsave(&gwlan_logging.spin_lock,
927 					flags);
928 				wlan_queue_logmsg_for_app();
929 				spin_unlock_irqrestore(&gwlan_logging.spin_lock,
930 					flags);
931 				set_bit(HOST_LOG_DRIVER_MSG,
932 						&gwlan_logging.eventFlag);
933 				set_bit(HOST_LOG_PER_PKT_STATS,
934 						&gwlan_logging.eventFlag);
935 				set_bit(HOST_LOG_FW_FLUSH_COMPLETE,
936 						&gwlan_logging.eventFlag);
937 				wake_up_interruptible(
938 						&gwlan_logging.wait_queue);
939 			}
940 		}
941 
942 		/* Dequeue the connectivity_log */
943 		wlan_logging_send_connectivity_event();
944 		clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG,
945 			  &gwlan_logging.eventFlag);
946 	}
947 
948 	gwlan_logging.exit_ts = qdf_get_log_timestamp();
949 	kthread_complete_and_exit(&gwlan_logging.shutdown_comp, 0);
950 
951 	return 0;
952 }
953 
954 void wlan_logging_set_active(bool active)
955 {
956 	gwlan_logging.is_active = active;
957 }
958 
959 void wlan_set_console_log_levels(uint32_t console_log_levels)
960 {
961 	gwlan_logging.console_log_levels = console_log_levels;
962 }
963 
964 qdf_export_symbol(wlan_set_console_log_levels);
965 
966 static void flush_log_buffers_timer(void *dummy)
967 {
968 	wlan_flush_host_logs_for_fatal();
969 }
970 
971 int wlan_logging_set_flush_timer(uint32_t milliseconds)
972 {
973 	if (milliseconds > MAX_FLUSH_TIMER_PERIOD_VALUE) {
974 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
975 				"ERROR! value should be (0 - %d)\n",
976 				MAX_FLUSH_TIMER_PERIOD_VALUE);
977 		return -EINVAL;
978 	}
979 	if (!gwlan_logging.is_active) {
980 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
981 				"WLAN-Logging not active");
982 		return -EINVAL;
983 	}
984 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
985 	if (!gwlan_logging.is_flush_timer_initialized) {
986 		qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
987 		return -EINVAL;
988 	}
989 	gwlan_logging.flush_timer_period = milliseconds;
990 	if (milliseconds) {
991 		qdf_timer_mod(&gwlan_logging.flush_timer,
992 			      gwlan_logging.flush_timer_period);
993 	}
994 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
995 	return 0;
996 }
997 
998 static int panic_wifilog_ratelimit_print(void)
999 {
1000 	return __ratelimit(&panic_wifilog_ratelimit);
1001 }
1002 
1003 /**
1004  * wlan_logging_dump_last_logs() - Panic notifier callback's helper function
1005  *
1006  * This function prints buffered logs one line at a time.
1007  */
1008 static void wlan_logging_dump_last_logs(void)
1009 {
1010 	char *log;
1011 	struct log_msg *plog_msg;
1012 	char textbuf[MAX_LOG_LINE];
1013 	unsigned int filled_length;
1014 	unsigned int text_len;
1015 	unsigned long flags;
1016 
1017 	/* Iterate over panic list */
1018 	pr_err("\n");
1019 	while (!list_empty(&gwlan_logging.panic_list)) {
1020 		plog_msg = (struct log_msg *)
1021 			   (gwlan_logging.panic_list.next);
1022 		list_del_init(gwlan_logging.panic_list.next);
1023 		log = &plog_msg->logbuf[sizeof(tAniHdr)];
1024 		filled_length = plog_msg->filled_length;
1025 		while (filled_length) {
1026 			text_len = qdf_str_copy_all_before_char(log, filled_length,
1027 								textbuf,
1028 								sizeof(textbuf) - 1,
1029 								'\n');
1030 			textbuf[text_len] = '\0';
1031 			if (panic_wifilog_ratelimit_print())
1032 				pr_err("%s\n", textbuf);
1033 
1034 			if (log[text_len] == '\n')
1035 				text_len += 1; /* skip newline */
1036 			log += text_len;
1037 			filled_length -= text_len;
1038 		}
1039 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
1040 		list_add_tail(&plog_msg->node,
1041 			      &gwlan_logging.free_list);
1042 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
1043 	}
1044 }
1045 
1046 /**
1047  * wlan_logging_panic_handler() - Panic notifier callback
1048  *
1049  * This function extracts log buffers in filled list and
1050  * current node.Sends them to helper function for printing.
1051  */
1052 static int wlan_logging_panic_handler(struct notifier_block *this,
1053 				      unsigned long event, void *ptr)
1054 {
1055 	char *log;
1056 	struct log_msg *plog_msg;
1057 	unsigned long flags;
1058 
1059 	spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
1060 	/* Iterate over nodes queued for app */
1061 	while (!list_empty(&gwlan_logging.filled_list)) {
1062 		plog_msg = (struct log_msg *)
1063 			   (gwlan_logging.filled_list.next);
1064 		list_del_init(gwlan_logging.filled_list.next);
1065 		list_add_tail(&plog_msg->node,
1066 			      &gwlan_logging.panic_list);
1067 	}
1068 	/* Check current node */
1069 	if (gwlan_logging.pcur_node &&
1070 	    gwlan_logging.pcur_node->filled_length) {
1071 		plog_msg = gwlan_logging.pcur_node;
1072 		log = &plog_msg->logbuf[sizeof(tAniHdr)];
1073 		log[plog_msg->filled_length] = '\0';
1074 		list_add_tail(&gwlan_logging.pcur_node->node,
1075 			      &gwlan_logging.panic_list);
1076 		if (!list_empty(&gwlan_logging.free_list)) {
1077 			gwlan_logging.pcur_node =
1078 				(struct log_msg *)(gwlan_logging.free_list.next);
1079 			list_del_init(gwlan_logging.free_list.next);
1080 			gwlan_logging.pcur_node->filled_length = 0;
1081 		} else
1082 			gwlan_logging.pcur_node = NULL;
1083 	}
1084 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
1085 
1086 	wlan_logging_dump_last_logs();
1087 
1088 	return NOTIFY_DONE;
1089 }
1090 
1091 static struct notifier_block panic_nb = {
1092 	.notifier_call  = wlan_logging_panic_handler,
1093 };
1094 
1095 int wlan_logging_notifier_init(bool dump_at_kernel_enable)
1096 {
1097 	int ret;
1098 
1099 	if (gwlan_logging.is_active &&
1100 	    !dump_at_kernel_enable) {
1101 		ret = atomic_notifier_chain_register(&panic_notifier_list,
1102 						     &panic_nb);
1103 		if (ret) {
1104 			QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
1105 					"Failed to register panic notifier");
1106 			return -EINVAL;
1107 		}
1108 	}
1109 
1110 	return 0;
1111 }
1112 
1113 int wlan_logging_notifier_deinit(bool dump_at_kernel_enable)
1114 {
1115 	if (gwlan_logging.is_active &&
1116 	    !dump_at_kernel_enable) {
1117 		atomic_notifier_chain_unregister(&panic_notifier_list,
1118 						 &panic_nb);
1119 	}
1120 
1121 	return 0;
1122 }
1123 
1124 static void flush_timer_init(void)
1125 {
1126 	qdf_spinlock_create(&gwlan_logging.flush_timer_lock);
1127 	qdf_timer_init(NULL, &gwlan_logging.flush_timer,
1128 		       flush_log_buffers_timer, NULL,
1129 		       QDF_TIMER_TYPE_SW);
1130 	gwlan_logging.is_flush_timer_initialized = true;
1131 	gwlan_logging.flush_timer_period = 0;
1132 }
1133 
1134 static void flush_timer_deinit(void)
1135 {
1136 	gwlan_logging.is_flush_timer_initialized = false;
1137 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
1138 	qdf_timer_stop(&gwlan_logging.flush_timer);
1139 	qdf_timer_free(&gwlan_logging.flush_timer);
1140 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
1141 	qdf_spinlock_destroy(&gwlan_logging.flush_timer_lock);
1142 }
1143 
1144 int wlan_logging_sock_init_svc(void)
1145 {
1146 	int i = 0, j, pkt_stats_size;
1147 	unsigned long irq_flag;
1148 	QDF_STATUS status;
1149 
1150 	spin_lock_init(&gwlan_logging.spin_lock);
1151 	spin_lock_init(&gwlan_logging.pkt_stats_lock);
1152 
1153 	gwlan_logging.console_log_levels = 0;
1154 	gwlan_logging.num_buf = MAX_LOGMSG_COUNT;
1155 	gwlan_logging.buffer_length = MAX_LOGMSG_LENGTH;
1156 
1157 	if (allocate_log_msg_buffer() != QDF_STATUS_SUCCESS) {
1158 		qdf_err("Could not allocate memory for log_msg");
1159 		return -ENOMEM;
1160 	}
1161 
1162 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
1163 	INIT_LIST_HEAD(&gwlan_logging.free_list);
1164 	INIT_LIST_HEAD(&gwlan_logging.filled_list);
1165 	INIT_LIST_HEAD(&gwlan_logging.panic_list);
1166 
1167 	for (i = 0; i < gwlan_logging.num_buf; i++) {
1168 		list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
1169 		gplog_msg[i].index = i;
1170 	}
1171 	gwlan_logging.pcur_node = (struct log_msg *)
1172 				  (gwlan_logging.free_list.next);
1173 	list_del_init(gwlan_logging.free_list.next);
1174 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
1175 
1176 	flush_timer_init();
1177 
1178 	/* Initialize the pktStats data structure here */
1179 	pkt_stats_size = sizeof(struct pkt_stats_msg);
1180 	gpkt_stats_buffers = qdf_mem_valloc(MAX_PKTSTATS_BUFF * pkt_stats_size);
1181 	if (!gpkt_stats_buffers) {
1182 		qdf_err("Could not allocate memory for Pkt stats");
1183 		goto err1;
1184 	}
1185 	qdf_mem_zero(gpkt_stats_buffers,
1186 			MAX_PKTSTATS_BUFF * pkt_stats_size);
1187 
1188 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1189 	gwlan_logging.pkt_stats_msg_idx = 0;
1190 	INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
1191 	INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
1192 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1193 
1194 
1195 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
1196 		gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH);
1197 		if (!gpkt_stats_buffers[i].skb) {
1198 			qdf_err("Memory alloc failed for skb");
1199 			/* free previously allocated skb and return */
1200 			for (j = 0; j < i ; j++)
1201 				dev_kfree_skb(gpkt_stats_buffers[j].skb);
1202 			goto err2;
1203 		}
1204 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1205 		list_add(&gpkt_stats_buffers[i].node,
1206 			&gwlan_logging.pkt_stat_free_list);
1207 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1208 	}
1209 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1210 	gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
1211 		(gwlan_logging.pkt_stat_free_list.next);
1212 	list_del_init(gwlan_logging.pkt_stat_free_list.next);
1213 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1214 	/* Pkt Stats initialization done */
1215 
1216 	init_waitqueue_head(&gwlan_logging.wait_queue);
1217 	gwlan_logging.exit = false;
1218 	clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
1219 	clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1220 	clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
1221 	clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
1222 	init_completion(&gwlan_logging.shutdown_comp);
1223 	gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
1224 					      "wlan_logging_thread");
1225 	if (IS_ERR(gwlan_logging.thread)) {
1226 		qdf_err("Could not Create LogMsg Thread Controller");
1227 		goto err3;
1228 	}
1229 	wake_up_process(gwlan_logging.thread);
1230 	gwlan_logging.wakup_ts = qdf_get_log_timestamp();
1231 
1232 	gwlan_logging.is_active = true;
1233 	gwlan_logging.is_flush_complete = false;
1234 
1235 	status = qdf_event_create(&gwlan_logging.flush_log_completion);
1236 	if (!QDF_IS_STATUS_SUCCESS(status)) {
1237 		qdf_err("Flush log completion event init failed");
1238 		goto err3;
1239 	}
1240 
1241 	return 0;
1242 
1243 err3:
1244 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
1245 		if (gpkt_stats_buffers[i].skb)
1246 			dev_kfree_skb(gpkt_stats_buffers[i].skb);
1247 	}
1248 err2:
1249 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1250 	gwlan_logging.pkt_stats_pcur_node = NULL;
1251 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1252 	qdf_mem_vfree(gpkt_stats_buffers);
1253 	gpkt_stats_buffers = NULL;
1254 err1:
1255 	flush_timer_deinit();
1256 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
1257 	gwlan_logging.pcur_node = NULL;
1258 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
1259 	free_log_msg_buffer();
1260 
1261 	return -ENOMEM;
1262 }
1263 
1264 int wlan_logging_sock_deinit_svc(void)
1265 {
1266 	unsigned long irq_flag;
1267 	int i;
1268 
1269 	if (!gwlan_logging.pcur_node)
1270 		return 0;
1271 
1272 	qdf_event_destroy(&gwlan_logging.flush_log_completion);
1273 
1274 	gwlan_logging.reinitcompletion_ts = qdf_get_log_timestamp();
1275 	INIT_COMPLETION(gwlan_logging.shutdown_comp);
1276 	qdf_wmb();
1277 	gwlan_logging.exit = true;
1278 	qdf_wmb();
1279 	gwlan_logging.set_exit_ts = qdf_get_log_timestamp();
1280 
1281 	gwlan_logging.is_active = false;
1282 #if defined(FEATURE_FW_LOG_PARSING) || defined(FEATURE_WLAN_DIAG_SUPPORT)
1283 	cds_set_multicast_logging(0);
1284 #endif
1285 	gwlan_logging.is_flush_complete = false;
1286 	clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
1287 	clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1288 	clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
1289 	clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
1290 	wake_up_interruptible(&gwlan_logging.wait_queue);
1291 	wait_for_completion(&gwlan_logging.shutdown_comp);
1292 
1293 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1294 	gwlan_logging.pkt_stats_pcur_node = NULL;
1295 	gwlan_logging.pkt_stats_msg_idx = 0;
1296 	gwlan_logging.pkt_stat_drop_cnt = 0;
1297 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
1298 		if (gpkt_stats_buffers[i].skb)
1299 			dev_kfree_skb(gpkt_stats_buffers[i].skb);
1300 	}
1301 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1302 	qdf_mem_vfree(gpkt_stats_buffers);
1303 	gpkt_stats_buffers = NULL;
1304 
1305 	/* Delete the Flush timer then mark pcur_node NULL */
1306 	flush_timer_deinit();
1307 
1308 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
1309 	gwlan_logging.pcur_node = NULL;
1310 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
1311 
1312 	free_log_msg_buffer();
1313 
1314 	return 0;
1315 }
1316 
1317 /**
1318  * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging
1319  *
1320  * This function is used to send signal to the logger thread for logging per
1321  * packet stats
1322  *
1323  * Return: None
1324  *
1325  */
1326 void wlan_logging_set_per_pkt_stats(void)
1327 {
1328 	if (gwlan_logging.is_active == false)
1329 		return;
1330 
1331 	set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1332 	wake_up_interruptible(&gwlan_logging.wait_queue);
1333 }
1334 
1335 void wlan_logging_set_connectivity_log(void)
1336 {
1337 	if (gwlan_logging.is_active == false)
1338 		return;
1339 
1340 	set_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
1341 	wake_up_interruptible(&gwlan_logging.wait_queue);
1342 }
1343 
1344 /*
1345  * wlan_logging_set_fw_flush_complete() - FW log flush completion
1346  *
1347  * This function is used to send signal to the logger thread to indicate
1348  * that the flushing of FW logs is complete by the FW
1349  *
1350  * Return: None
1351  *
1352  */
1353 void wlan_logging_set_fw_flush_complete(void)
1354 {
1355 	if (!gwlan_logging.is_active)
1356 		return;
1357 
1358 	set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
1359 	wake_up_interruptible(&gwlan_logging.wait_queue);
1360 }
1361 
1362 /**
1363  * wlan_flush_host_logs_for_fatal() - Flush host logs
1364  *
1365  * This function is used to send signal to the logger thread to
1366  * Flush the host logs
1367  *
1368  * Return: None
1369  */
1370 void wlan_flush_host_logs_for_fatal(void)
1371 {
1372 	unsigned long flags;
1373 
1374 	if (gwlan_logging.flush_timer_period == 0)
1375 		qdf_info("Flush all host logs Setting HOST_LOG_POST_MAS");
1376 	spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
1377 	wlan_queue_logmsg_for_app();
1378 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
1379 	set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
1380 	wake_up_interruptible(&gwlan_logging.wait_queue);
1381 }
1382 
1383 #ifdef CONNECTIVITY_PKTLOG
1384 
1385 static uint8_t gtx_count;
1386 static uint8_t grx_count;
1387 
1388 /**
1389  * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats
1390  *
1391  * This function is used to get the free node for pkt stats from
1392  * free list/filled list
1393  *
1394  * Return: int
1395  *
1396  */
1397 static int wlan_get_pkt_stats_free_node(void)
1398 {
1399 	int ret = 0;
1400 
1401 	list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
1402 			&gwlan_logging.pkt_stat_filled_list);
1403 
1404 	if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
1405 		/* Get buffer from free list */
1406 		gwlan_logging.pkt_stats_pcur_node =
1407 		(struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
1408 		list_del_init(gwlan_logging.pkt_stat_free_list.next);
1409 	} else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
1410 		/* Get buffer from filled list. This condition will drop the
1411 		 * packet from being indicated to app
1412 		 */
1413 		gwlan_logging.pkt_stats_pcur_node =
1414 			(struct pkt_stats_msg *)
1415 				(gwlan_logging.pkt_stat_filled_list.next);
1416 		++gwlan_logging.pkt_stat_drop_cnt;
1417 		/* print every 64th drop count */
1418 		if (
1419 			cds_is_multicast_logging() &&
1420 			(!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
1421 			qdf_err("drop_count = %u",
1422 				gwlan_logging.pkt_stat_drop_cnt);
1423 		}
1424 		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
1425 		ret = 1;
1426 	}
1427 
1428 	/* Reset the skb values, essential if dequeued from filled list */
1429 	skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0);
1430 	return ret;
1431 }
1432 
1433 /**
1434  * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB
1435  * @pl_hdr: Pointer to pl_hdr
1436  * @pkt_dump: Pointer to pkt_dump
1437  * @data: Pointer to data
1438  *
1439  * This function adds the pktstats hdr and data to current
1440  * skb node of free list.
1441  *
1442  * Return: None
1443  */
1444 void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
1445 {
1446 	struct ath_pktlog_hdr *pktlog_hdr;
1447 	struct packet_dump *pkt_stats_dump;
1448 	int total_stats_len = 0;
1449 	bool wake_up_thread = false;
1450 	unsigned long flags;
1451 	struct sk_buff *ptr;
1452 	int hdr_size;
1453 
1454 	pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr;
1455 
1456 	if (!pktlog_hdr) {
1457 		qdf_err("Invalid pkt_stats_header");
1458 		return;
1459 	}
1460 
1461 	pkt_stats_dump = (struct packet_dump *)pkt_dump;
1462 	total_stats_len = sizeof(struct ath_pktlog_hdr) +
1463 					pktlog_hdr->size;
1464 
1465 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
1466 
1467 	if (!gwlan_logging.pkt_stats_pcur_node) {
1468 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
1469 		return;
1470 	}
1471 
1472 	/* Check if we can accommodate more log into current node/buffer */
1473 	hdr_size = sizeof(struct host_log_pktlog_info) +
1474 			sizeof(tAniNlHdr);
1475 	if ((total_stats_len +  hdr_size) >=
1476 		skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
1477 		wake_up_thread = true;
1478 		wlan_get_pkt_stats_free_node();
1479 	}
1480 
1481 	ptr = gwlan_logging.pkt_stats_pcur_node->skb;
1482 	qdf_mem_copy(skb_put(ptr,
1483 			sizeof(struct ath_pktlog_hdr)),
1484 			pktlog_hdr,
1485 			sizeof(struct ath_pktlog_hdr));
1486 
1487 	if (pkt_stats_dump) {
1488 		qdf_mem_copy(skb_put(ptr,
1489 				sizeof(struct packet_dump)),
1490 				pkt_stats_dump,
1491 				sizeof(struct packet_dump));
1492 		pktlog_hdr->size -= sizeof(struct packet_dump);
1493 	}
1494 
1495 	if (data)
1496 		qdf_mem_copy(skb_put(ptr,
1497 				pktlog_hdr->size),
1498 				data, pktlog_hdr->size);
1499 
1500 	if (pkt_stats_dump && pkt_stats_dump->type == STOP_MONITOR) {
1501 		wake_up_thread = true;
1502 		wlan_get_pkt_stats_free_node();
1503 	}
1504 
1505 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
1506 
1507 	/* Wakeup logger thread */
1508 	if (true == wake_up_thread) {
1509 		set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1510 		wake_up_interruptible(&gwlan_logging.wait_queue);
1511 	}
1512 }
1513 
1514 /**
1515  * qdf_hal_tx_status_map() - map Tx completion status with
1516  * packet dump Tx status
1517  * @status: Tx completion status
1518  *
1519  * Return: packet dump tx_status enum
1520  */
1521 static inline enum tx_pkt_fate
1522 qdf_hal_tx_status_map(enum qdf_dp_tx_rx_status status)
1523 {
1524 	switch (status) {
1525 	case QDF_TX_RX_STATUS_OK:
1526 		return TX_PKT_FATE_ACKED;
1527 	case QDF_TX_RX_STATUS_FW_DISCARD:
1528 		return TX_PKT_FATE_FW_DROP_OTHER;
1529 	case QDF_TX_RX_STATUS_NO_ACK:
1530 		return TX_PKT_FATE_SENT;
1531 	case QDF_TX_RX_STATUS_DROP:
1532 		return TX_PKT_FATE_DRV_DROP_OTHER;
1533 	case QDF_TX_RX_STATUS_DOWNLOAD_SUCC:
1534 		return TX_PKT_FATE_DRV_QUEUED;
1535 	default:
1536 		return TX_PKT_FATE_DRV_DROP_OTHER;
1537 	}
1538 }
1539 
1540 /**
1541  * qdf_hal_rx_status_map() - map Rx status with
1542  * packet dump Rx status
1543  * @status: Rx status
1544  *
1545  * Return: packet dump rx_status enum
1546  */
1547 static inline enum rx_pkt_fate
1548 qdf_hal_rx_status_map(enum qdf_dp_tx_rx_status status)
1549 {
1550 	switch (status) {
1551 	case QDF_TX_RX_STATUS_OK:
1552 		return RX_PKT_FATE_SUCCESS;
1553 	case QDF_TX_RX_STATUS_FW_DISCARD:
1554 		return RX_PKT_FATE_FW_DROP_OTHER;
1555 	case QDF_TX_RX_STATUS_DROP:
1556 		return RX_PKT_FATE_DRV_DROP_OTHER;
1557 	case QDF_TX_RX_STATUS_DOWNLOAD_SUCC:
1558 		return RX_PKT_FATE_DRV_QUEUED;
1559 	default:
1560 		return RX_PKT_FATE_DRV_DROP_OTHER;
1561 	}
1562 }
1563 
1564 /**
1565  * qdf_hal_pkt_type_map() - map qdf packet type with
1566  * packet dump packet type
1567  * @type: packet type
1568  *
1569  * Return: Packet dump packet type
1570  */
1571 static inline enum pkt_type
1572 qdf_hal_pkt_type_map(enum qdf_pkt_type type)
1573 {
1574 	switch (type) {
1575 	case QDF_TX_MGMT_PKT:
1576 		return TX_MGMT_PKT;
1577 	case QDF_TX_DATA_PKT:
1578 		return TX_DATA_PKT;
1579 	case QDF_RX_MGMT_PKT:
1580 		return RX_MGMT_PKT;
1581 	case QDF_RX_DATA_PKT:
1582 		return RX_DATA_PKT;
1583 	default:
1584 		return INVALID_PKT;
1585 	}
1586 }
1587 
1588 /*
1589  * send_packetdump() - send packet dump
1590  * @soc: soc handle
1591  * @vdev_id: ID of the virtual device handle
1592  * @netbuf: netbuf
1593  * @status: status of tx packet
1594  * @type: type of packet
1595  *
1596  * This function is used to send packet dump to HAL layer
1597  * using wlan_pkt_stats_to_logger_thread
1598  *
1599  * Return: None
1600  *
1601  */
1602 static void send_packetdump(ol_txrx_soc_handle soc,
1603 			    uint8_t vdev_id, qdf_nbuf_t netbuf,
1604 			    uint8_t status, uint8_t type)
1605 {
1606 	struct ath_pktlog_hdr pktlog_hdr = {0};
1607 	struct packet_dump pd_hdr = {0};
1608 
1609 	if (!netbuf) {
1610 		qdf_err("Invalid netbuf");
1611 		return;
1612 	}
1613 
1614 	/* Send packet dump only for STA interface */
1615 	if (wlan_op_mode_sta != cdp_get_opmode(soc, vdev_id))
1616 		return;
1617 
1618 	pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
1619 
1620 	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
1621 	pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
1622 
1623 	pd_hdr.status = status;
1624 	pd_hdr.type = type;
1625 	pd_hdr.driver_ts = qdf_get_monotonic_boottime();
1626 
1627 	if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
1628 		gtx_count++;
1629 	else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
1630 		grx_count++;
1631 
1632 	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
1633 }
1634 
1635 
1636 /*
1637  * send_packetdump_monitor() - sends start/stop packet dump indication
1638  * @type: type of packet
1639  *
1640  * This function is used to indicate HAL layer to start/stop monitoring
1641  * of packets
1642  *
1643  * Return: None
1644  *
1645  */
1646 static void send_packetdump_monitor(uint8_t type)
1647 {
1648 	struct ath_pktlog_hdr pktlog_hdr = {0};
1649 	struct packet_dump pd_hdr = {0};
1650 
1651 	pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
1652 
1653 	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
1654 	pktlog_hdr.size = sizeof(pd_hdr);
1655 
1656 	pd_hdr.type = type;
1657 
1658 	LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1659 			"fate Tx-Rx %s: type: %d", __func__, type);
1660 
1661 	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
1662 }
1663 
1664 void wlan_deregister_txrx_packetdump(uint8_t pdev_id)
1665 {
1666 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1667 
1668 	if (!soc)
1669 		return;
1670 
1671 	if (gtx_count || grx_count) {
1672 		cdp_deregister_packetdump_cb(soc, pdev_id);
1673 		wma_deregister_packetdump_callback();
1674 		send_packetdump_monitor(STOP_MONITOR);
1675 		csr_packetdump_timer_stop();
1676 
1677 		gtx_count = 0;
1678 		grx_count = 0;
1679 	} else
1680 		LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1681 			"%s: deregistered packetdump already", __func__);
1682 }
1683 
1684 /*
1685  * check_txrx_packetdump_count() - function to check
1686  * tx/rx packet dump global counts
1687  * @pdev_id: datapath pdev identifier
1688  *
1689  * This function is used to check global counts of tx/rx
1690  * packet dump functionality.
1691  *
1692  * Return: 1 if either gtx_count or grx_count reached 32
1693  *             0 otherwise
1694  *
1695  */
1696 static bool check_txrx_packetdump_count(uint8_t pdev_id)
1697 {
1698 	if (gtx_count == MAX_NUM_PKT_LOG ||
1699 		grx_count == MAX_NUM_PKT_LOG) {
1700 		LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1701 			"%s gtx_count: %d grx_count: %d deregister packetdump",
1702 			__func__, gtx_count, grx_count);
1703 		wlan_deregister_txrx_packetdump(pdev_id);
1704 		return 1;
1705 	}
1706 	return 0;
1707 }
1708 
1709 /*
1710  * tx_packetdump_cb() - tx packet dump callback
1711  * @soc: soc handle
1712  * @pdev_id: datapath pdev id
1713  * @vdev_id: vdev id
1714  * @netbuf: netbuf
1715  * @status: status of tx packet
1716  * @type: packet type
1717  *
1718  * This function is used to send tx packet dump to HAL layer
1719  * and deregister packet dump callbacks
1720  *
1721  * Return: None
1722  *
1723  */
1724 static void tx_packetdump_cb(ol_txrx_soc_handle soc,
1725 			     uint8_t pdev_id, uint8_t vdev_id,
1726 			     qdf_nbuf_t netbuf,
1727 			     enum qdf_dp_tx_rx_status status,
1728 			     enum qdf_pkt_type type)
1729 {
1730 	bool temp;
1731 	enum tx_pkt_fate tx_status = qdf_hal_tx_status_map(status);
1732 	enum pkt_type pkt_type = qdf_hal_pkt_type_map(type);
1733 
1734 	if (!soc)
1735 		return;
1736 
1737 	temp = check_txrx_packetdump_count(pdev_id);
1738 	if (temp)
1739 		return;
1740 
1741 	send_packetdump(soc, vdev_id, netbuf, tx_status, pkt_type);
1742 }
1743 
1744 
1745 /*
1746  * rx_packetdump_cb() - rx packet dump callback
1747  * @soc: soc handle
1748  * @pdev_id: datapath pdev id
1749  * @vdev_id: vdev id
1750  * @netbuf: netbuf
1751  * @status: status of rx packet
1752  * @type: packet type
1753  *
1754  * This function is used to send rx packet dump to HAL layer
1755  * and deregister packet dump callbacks
1756  *
1757  * Return: None
1758  *
1759  */
1760 static void rx_packetdump_cb(ol_txrx_soc_handle soc,
1761 			     uint8_t pdev_id, uint8_t vdev_id,
1762 			     qdf_nbuf_t netbuf,
1763 			     enum qdf_dp_tx_rx_status status,
1764 			     enum qdf_pkt_type type)
1765 {
1766 	bool temp;
1767 	enum rx_pkt_fate rx_status = qdf_hal_rx_status_map(status);
1768 	enum pkt_type pkt_type = qdf_hal_pkt_type_map(type);
1769 
1770 	if (!soc)
1771 		return;
1772 
1773 	temp = check_txrx_packetdump_count(pdev_id);
1774 	if (temp)
1775 		return;
1776 
1777 	send_packetdump(soc, vdev_id, netbuf, rx_status, pkt_type);
1778 }
1779 
1780 void wlan_register_txrx_packetdump(uint8_t pdev_id)
1781 {
1782 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1783 
1784 	if (!soc)
1785 		return;
1786 
1787 	cdp_register_packetdump_cb(soc, pdev_id,
1788 				   tx_packetdump_cb, rx_packetdump_cb);
1789 	wma_register_packetdump_callback(tx_packetdump_cb,
1790 			rx_packetdump_cb);
1791 	send_packetdump_monitor(START_MONITOR);
1792 
1793 	gtx_count = 0;
1794 	grx_count = 0;
1795 
1796 	csr_packetdump_timer_start();
1797 }
1798 #endif /* CONNECTIVITY_PKTLOG */
1799 #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
1800