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