xref: /wlan-dirver/qca-wifi-host-cmn/utils/logging/src/wlan_logging_sock_svc.c (revision 0626a4da6c07f30da06dd6747e8cc290a60371d8)
1 /*
2  * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /******************************************************************************
20 * wlan_logging_sock_svc.c
21 *
22 ******************************************************************************/
23 
24 #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
25 #include <linux/vmalloc.h>
26 #ifdef CONFIG_MCL
27 #include <cds_api.h>
28 #include <host_diag_core_event.h>
29 #include "cds_utils.h"
30 #include "csr_api.h"
31 #include "wlan_hdd_main.h"
32 #include "wma.h"
33 #include "ol_txrx_api.h"
34 #include "pktlog_ac.h"
35 #endif
36 #include <wlan_logging_sock_svc.h>
37 #include <linux/kthread.h>
38 #include <qdf_time.h>
39 #include <qdf_trace.h>
40 #include <qdf_mc_timer.h>
41 #include <qdf_timer.h>
42 #include <qdf_lock.h>
43 #include <wlan_ptt_sock_svc.h>
44 #include <host_diag_core_event.h>
45 #include "host_diag_core_log.h"
46 
47 #ifdef CNSS_GENL
48 #include <net/cnss_nl.h>
49 #endif
50 
51 #define MAX_NUM_PKT_LOG 32
52 
53 #define ALLOWED_LOG_LEVELS_TO_CONSOLE(level) \
54 	((QDF_TRACE_LEVEL_FATAL == (level)) || \
55 	 (QDF_TRACE_LEVEL_ERROR == (level)) || \
56 	 (QDF_TRACE_LEVEL_WARN == (level)) || \
57 	 (QDF_TRACE_LEVEL_INFO == (level)))
58 
59 /**
60  * struct tx_status - tx status
61  * @tx_status_ok: successfully sent + acked
62  * @tx_status_discard: discard - not sent (congestion control)
63  * @tx_status_no_ack: no_ack - sent, but no ack
64  * @tx_status_download_fail: download_fail -
65  * the host could not deliver the tx frame to the target
66  * @tx_status_peer_del: peer_del - tx completion for
67  * alreay deleted peer used for HL case
68  *
69  * This enum has tx status types
70  */
71 enum tx_status {
72 	tx_status_ok,
73 	tx_status_discard,
74 	tx_status_no_ack,
75 	tx_status_download_fail,
76 	tx_status_peer_del,
77 };
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 #define MAX_PKTSTATS_LENGTH 2048
92 #define MAX_PKTSTATS_BUFF   16
93 
94 #define HOST_LOG_DRIVER_MSG        0x001
95 #define HOST_LOG_PER_PKT_STATS     0x002
96 #define HOST_LOG_FW_FLUSH_COMPLETE 0x003
97 #define DIAG_TYPE_LOGS                 1
98 #define PTT_MSG_DIAG_CMDS_TYPE    0x5050
99 
100 struct log_msg {
101 	struct list_head node;
102 	unsigned int radio;
103 	unsigned int index;
104 	/* indicates the current filled log length in logbuf */
105 	unsigned int filled_length;
106 	/*
107 	 * Buf to hold the log msg
108 	 * tAniHdr + log
109 	 */
110 	char logbuf[MAX_LOGMSG_LENGTH];
111 };
112 
113 /**
114  * struct packet_dump - This data structure contains the
115  * Tx/Rx packet stats
116  * @status: Status
117  * @type: Type
118  * @driver_ts: driver timestamp
119  * @fw_ts: fw timestamp
120  */
121 struct packet_dump {
122 	unsigned char status;
123 	unsigned char type;
124 	uint32_t driver_ts;
125 	uint16_t fw_ts;
126 } __attribute__((__packed__));
127 
128 /**
129  * struct pkt_stats_msg - This data structure contains the
130  * pkt stats node for link list
131  * @node: LinkList node
132  * @node: Pointer to skb
133  */
134 struct pkt_stats_msg {
135 	struct list_head node;
136 	struct sk_buff *skb;
137 };
138 
139 #define MAX_FLUSH_TIMER_PERIOD_VALUE 3600000 /* maximum of 1 hour (in ms) */
140 struct wlan_logging {
141 	/* Log Fatal and ERROR to console */
142 	bool log_to_console;
143 	/* Number of buffers to be used for logging */
144 	uint32_t num_buf;
145 	uint32_t buffer_length;
146 	/* Lock to synchronize access to shared logging resource */
147 	spinlock_t spin_lock;
148 	/* Holds the free node which can be used for filling logs */
149 	struct list_head free_list;
150 	/* Holds the filled nodes which needs to be indicated to APP */
151 	struct list_head filled_list;
152 	/* Wait queue for Logger thread */
153 	wait_queue_head_t wait_queue;
154 	/* Logger thread */
155 	struct task_struct *thread;
156 	/* Logging thread sets this variable on exit */
157 	struct completion shutdown_comp;
158 	/* Indicates to logger thread to exit */
159 	bool exit;
160 	/* Holds number of dropped logs */
161 	unsigned int drop_count;
162 	/* current logbuf to which the log will be filled to */
163 	struct log_msg *pcur_node;
164 	/* Event flag used for wakeup and post indication*/
165 	unsigned long eventFlag;
166 	/* Indicates logger thread is activated */
167 	bool is_active;
168 	/* Flush completion check */
169 	bool is_flush_complete;
170 	/* paramaters  for pkt stats */
171 	struct list_head pkt_stat_free_list;
172 	struct list_head pkt_stat_filled_list;
173 	struct pkt_stats_msg *pkt_stats_pcur_node;
174 	unsigned int pkt_stat_drop_cnt;
175 	spinlock_t pkt_stats_lock;
176 	unsigned int pkt_stats_msg_idx;
177 	qdf_timer_t flush_timer;
178 	bool is_flush_timer_initialized;
179 	uint32_t flush_timer_period;
180 	qdf_spinlock_t flush_timer_lock;
181 };
182 
183 static struct wlan_logging gwlan_logging;
184 static struct pkt_stats_msg *gpkt_stats_buffers;
185 
186 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
187 
188 static struct log_msg *gplog_msg;
189 
190 static inline QDF_STATUS allocate_log_msg_buffer(void)
191 {
192 	gplog_msg = vzalloc(MAX_LOGMSG_COUNT * sizeof(*gplog_msg));
193 
194 	return gplog_msg ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
195 }
196 
197 static inline void free_log_msg_buffer(void)
198 {
199 	vfree(gplog_msg);
200 	gplog_msg = NULL;
201 }
202 
203 #else
204 static struct log_msg gplog_msg[MAX_LOGMSG_COUNT];
205 
206 static inline QDF_STATUS allocate_log_msg_buffer(void)
207 {
208 	return QDF_STATUS_SUCCESS;
209 }
210 
211 static inline void free_log_msg_buffer(void)
212 { }
213 #endif
214 
215 /* Need to call this with spin_lock acquired */
216 static int wlan_queue_logmsg_for_app(void)
217 {
218 	char *ptr;
219 	int ret = 0;
220 	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
221 	ptr[gwlan_logging.pcur_node->filled_length] = '\0';
222 
223 	*(unsigned short *)(gwlan_logging.pcur_node->logbuf) =
224 		ANI_NL_MSG_LOG_TYPE;
225 	*(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) =
226 		gwlan_logging.pcur_node->filled_length;
227 	list_add_tail(&gwlan_logging.pcur_node->node,
228 		      &gwlan_logging.filled_list);
229 
230 	if (!list_empty(&gwlan_logging.free_list)) {
231 		/* Get buffer from free list */
232 		gwlan_logging.pcur_node =
233 			(struct log_msg *)(gwlan_logging.free_list.next);
234 		list_del_init(gwlan_logging.free_list.next);
235 	} else if (!list_empty(&gwlan_logging.filled_list)) {
236 		/* Get buffer from filled list */
237 		/* This condition will drop the packet from being
238 		 * indicated to app
239 		 */
240 		gwlan_logging.pcur_node =
241 			(struct log_msg *)(gwlan_logging.filled_list.next);
242 		++gwlan_logging.drop_count;
243 		list_del_init(gwlan_logging.filled_list.next);
244 		ret = 1;
245 	}
246 
247 	/* Reset the current node values */
248 	gwlan_logging.pcur_node->filled_length = 0;
249 	return ret;
250 }
251 
252 static const char *current_process_name(void)
253 {
254 	if (in_irq())
255 		return "irq";
256 
257 	if (in_softirq())
258 		return "soft_irq";
259 
260 	return current->comm;
261 }
262 
263 #ifdef QCA_WIFI_3_0_ADRASTEA
264 /**
265  * wlan_add_user_log_time_stamp() - populate firmware and kernel timestamps
266  * @tbuf: Pointer to time stamp buffer
267  * @tbuf_sz: Time buffer size
268  * @ts: Time stamp value
269  *
270  * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag
271  * to convert it into user visible time stamp. In adrstea FW also uses QTIMER
272  * raw ticks which is needed to synchronize host and fw log time stamps
273  *
274  * Also add logcat timestamp so that driver logs and
275  * logcat logs can be co-related
276  *
277  * For discrete solution e.g rome use system tick and convert it into
278  * seconds.milli seconds
279  *
280  * Return: number of characters written in target buffer not including
281  *		trailing '/0'
282  */
283 static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts)
284 {
285 	char time_buf[20];
286 
287 	qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
288 
289 	return scnprintf(tbuf, tbuf_sz, "[%.16s][0x%llx]%s",
290 			 current_process_name(), ts, time_buf);
291 }
292 #else
293 static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts)
294 {
295 	uint32_t rem;
296 	char time_buf[20];
297 
298 	qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
299 
300 	rem = do_div(ts, QDF_MC_TIMER_TO_SEC_UNIT);
301 	return scnprintf(tbuf, tbuf_sz, "[%.16s][%lu.%06lu]%s",
302 			 current_process_name(), (unsigned long)ts,
303 			 (unsigned long)rem, time_buf);
304 }
305 #endif /* QCA_WIFI_3_0_ADRASTEA */
306 
307 #ifdef CONFIG_MCL
308 static inline void print_to_console(char *tbuf, char *to_be_sent)
309 {
310 	pr_err("%s %s\n", tbuf, to_be_sent);
311 }
312 #else
313 #define print_to_console(str1, str2)
314 #endif
315 
316 int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length)
317 {
318 	char *ptr;
319 	char tbuf[60];
320 	int tlen;
321 	int total_log_len;
322 	unsigned int *pfilled_length;
323 	bool wake_up_thread = false;
324 	unsigned long flags;
325 	uint64_t ts;
326 
327 	/* if logging isn't up yet, just dump to dmesg */
328 	if (!gwlan_logging.is_active) {
329 		pr_info("%s\n", to_be_sent);
330 		return 0;
331 	}
332 
333 	/* Add the current time stamp */
334 	ts = qdf_get_log_timestamp();
335 	tlen = wlan_add_user_log_time_stamp(tbuf, sizeof(tbuf), ts);
336 
337 	/* 1+1 indicate '\n'+'\0' */
338 	total_log_len = length + tlen + 1 + 1;
339 
340 	spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
341 	/* wlan logging svc resources are not yet initialized */
342 	if (!gwlan_logging.pcur_node) {
343 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
344 		return -EIO;
345 	}
346 
347 	pfilled_length = &gwlan_logging.pcur_node->filled_length;
348 
349 	/* Check if we can accommodate more log into current node/buffer */
350 	if ((MAX_LOGMSG_LENGTH - (*pfilled_length +
351 			sizeof(tAniNlHdr))) < total_log_len) {
352 		wake_up_thread = true;
353 		wlan_queue_logmsg_for_app();
354 		pfilled_length = &gwlan_logging.pcur_node->filled_length;
355 	}
356 
357 	ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
358 
359 	if (unlikely(MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len))) {
360 		/*
361 		 * Assumption here is that we receive logs which is less than
362 		 * MAX_LOGMSG_LENGTH, where we can accommodate the
363 		 * tAniNlHdr + [context][timestamp] + log
364 		 * If log length is over MAX_LOGMSG_LENGTH,
365 		 * the overflow part will be discarded.
366 		 */
367 		length = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - tlen - 2;
368 		/*
369 		 * QDF_ASSERT if complete log was not accommodated into
370 		 * the available buffer.
371 		 */
372 		QDF_ASSERT(0);
373 	}
374 
375 	memcpy(&ptr[*pfilled_length], tbuf, tlen);
376 	memcpy(&ptr[*pfilled_length + tlen], to_be_sent, length);
377 	*pfilled_length += tlen + length;
378 	ptr[*pfilled_length] = '\n';
379 	*pfilled_length += 1;
380 
381 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
382 
383 	/* Wakeup logger thread */
384 	if (wake_up_thread) {
385 		set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
386 		wake_up_interruptible(&gwlan_logging.wait_queue);
387 	}
388 
389 	if (gwlan_logging.log_to_console
390 	    && ALLOWED_LOG_LEVELS_TO_CONSOLE(log_level)) {
391 		print_to_console(tbuf, to_be_sent);
392 	}
393 
394 	return 0;
395 }
396 
397 /**
398  * nl_srv_bcast_host_logs() - Wrapper to send bcast msgs to host logs mcast grp
399  * @skb: sk buffer pointer
400  *
401  * Sends the bcast message to host logs multicast group with generic nl socket
402  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
403  *
404  * Return: zero on success, error code otherwise
405  */
406 #ifdef CNSS_GENL
407 static int nl_srv_bcast_host_logs(struct sk_buff *skb)
408 {
409 	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
410 }
411 #else
412 static int nl_srv_bcast_host_logs(struct sk_buff *skb)
413 {
414 	return nl_srv_bcast(skb);
415 }
416 #endif
417 
418 #ifndef REMOVE_PKT_LOG
419 /**
420  * pkt_stats_fill_headers() - This function adds headers to skb
421  * @skb: skb to which headers need to be added
422  *
423  * Return: 0 on success or Errno on failure
424  */
425 static int pkt_stats_fill_headers(struct sk_buff *skb)
426 {
427 	struct host_log_pktlog_info cds_pktlog;
428 	int cds_pkt_size = sizeof(struct host_log_pktlog_info);
429 	tAniNlHdr msg_header;
430 	int extra_header_len, nl_payload_len;
431 	static int nlmsg_seq;
432 	int diag_type;
433 
434 	qdf_mem_zero(&cds_pktlog, cds_pkt_size);
435 	cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
436 	cds_pktlog.buf_len = skb->len;
437 	cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
438 #ifdef CONFIG_MCL
439 	host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C);
440 	host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len +
441 				cds_pkt_size);
442 #endif
443 
444 	if (unlikely(skb_headroom(skb) < cds_pkt_size)) {
445 		pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
446 			__LINE__, skb->head, skb->data, sizeof(msg_header));
447 		return -EIO;
448 	}
449 
450 	qdf_mem_copy(skb_push(skb, cds_pkt_size),
451 			&cds_pktlog, cds_pkt_size);
452 
453 	if (unlikely(skb_headroom(skb) < sizeof(int))) {
454 		pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
455 			__LINE__, skb->head, skb->data, sizeof(int));
456 		return -EIO;
457 	}
458 
459 	diag_type = DIAG_TYPE_LOGS;
460 	qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int));
461 
462 	extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) +
463 				sizeof(struct nlmsghdr);
464 	nl_payload_len = extra_header_len + skb->len;
465 
466 	msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
467 	msg_header.nlh.nlmsg_len = nl_payload_len;
468 	msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
469 	msg_header.nlh.nlmsg_pid = 0;
470 	msg_header.nlh.nlmsg_seq = nlmsg_seq++;
471 	msg_header.radio = 0;
472 	msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
473 	msg_header.wmsg.length = cpu_to_be16(skb->len);
474 
475 	if (unlikely(skb_headroom(skb) < sizeof(msg_header))) {
476 		pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
477 			__LINE__, skb->head, skb->data, sizeof(msg_header));
478 		return -EIO;
479 	}
480 
481 	qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header,
482 			sizeof(msg_header));
483 
484 	return 0;
485 }
486 
487 /**
488  * nl_srv_bcast_diag() - Wrapper to send bcast msgs to diag events mcast grp
489  * @skb: sk buffer pointer
490  *
491  * Sends the bcast message to diag events multicast group with generic nl socket
492  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
493  *
494  * Return: zero on success, error code otherwise
495  */
496 static int nl_srv_bcast_diag(struct sk_buff *skb)
497 {
498 #ifdef CNSS_GENL
499 	return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
500 #else
501 	return nl_srv_bcast(skb);
502 #endif
503 }
504 
505 /**
506  * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per
507  * packet statistics to the user
508  *
509  * This function is used to send the per packet statistics to the user
510  *
511  * Return: Success if the message is posted to user
512  */
513 static int pktlog_send_per_pkt_stats_to_user(void)
514 {
515 	int ret = -1;
516 	struct pkt_stats_msg *pstats_msg;
517 	unsigned long flags;
518 	struct sk_buff *skb_new = NULL;
519 	static int rate_limit;
520 	bool free_old_skb = false;
521 
522 	while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
523 		&& !gwlan_logging.exit) {
524 		skb_new = dev_alloc_skb(MAX_SKBMSG_LENGTH);
525 		if (skb_new == NULL) {
526 			if (!rate_limit) {
527 				pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
528 					__func__, MAX_SKBMSG_LENGTH,
529 					gwlan_logging.drop_count);
530 			}
531 			rate_limit = 1;
532 			ret = -ENOMEM;
533 			break;
534 		}
535 
536 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
537 
538 		pstats_msg = (struct pkt_stats_msg *)
539 			(gwlan_logging.pkt_stat_filled_list.next);
540 		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
541 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
542 
543 		ret = pkt_stats_fill_headers(pstats_msg->skb);
544 		if (ret < 0) {
545 			pr_err("%s failed to fill headers %d\n", __func__, ret);
546 			free_old_skb = true;
547 			goto err;
548 		}
549 		ret = nl_srv_bcast_diag(pstats_msg->skb);
550 		if (ret < 0) {
551 			pr_info("%s: Send Failed %d drop_count = %u\n",
552 				__func__, ret,
553 				++gwlan_logging.pkt_stat_drop_cnt);
554 		} else {
555 			ret = 0;
556 		}
557 err:
558 	/*
559 	 * Free old skb in case or error before assigning new skb
560 	 * to the free list.
561 	 */
562 	if (free_old_skb)
563 		dev_kfree_skb(pstats_msg->skb);
564 
565 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
566 		pstats_msg->skb = skb_new;
567 		list_add_tail(&pstats_msg->node,
568 				&gwlan_logging.pkt_stat_free_list);
569 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
570 		ret = 0;
571 	}
572 
573 	return ret;
574 
575 }
576 #else
577 static inline
578 int pktlog_send_per_pkt_stats_to_user(void)
579 {
580 	return 0;
581 }
582 #endif
583 
584 static int send_filled_buffers_to_user(void)
585 {
586 	int ret = -1;
587 	struct log_msg *plog_msg;
588 	int payload_len;
589 	int tot_msg_len;
590 	tAniNlHdr *wnl;
591 	struct sk_buff *skb = NULL;
592 	struct nlmsghdr *nlh;
593 	static int nlmsg_seq;
594 	unsigned long flags;
595 	static int rate_limit;
596 
597 	while (!list_empty(&gwlan_logging.filled_list)
598 	       && !gwlan_logging.exit) {
599 
600 		skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
601 		if (skb == NULL) {
602 			if (!rate_limit) {
603 				pr_err
604 					("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
605 					__func__, MAX_LOGMSG_LENGTH,
606 					gwlan_logging.drop_count);
607 			}
608 			rate_limit = 1;
609 			ret = -ENOMEM;
610 			break;
611 		}
612 		rate_limit = 0;
613 
614 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
615 
616 		plog_msg = (struct log_msg *)
617 			   (gwlan_logging.filled_list.next);
618 		list_del_init(gwlan_logging.filled_list.next);
619 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
620 		/* 4 extra bytes for the radio idx */
621 		payload_len = plog_msg->filled_length +
622 			      sizeof(wnl->radio) + sizeof(tAniHdr);
623 
624 		tot_msg_len = NLMSG_SPACE(payload_len);
625 		nlh = nlmsg_put(skb, 0, nlmsg_seq++,
626 				ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST);
627 		if (NULL == nlh) {
628 			spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
629 			list_add_tail(&plog_msg->node,
630 				      &gwlan_logging.free_list);
631 			spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
632 			pr_err("%s: drop_count = %u\n", __func__,
633 			       ++gwlan_logging.drop_count);
634 			pr_err("%s: nlmsg_put() failed for msg size[%d]\n",
635 			       __func__, tot_msg_len);
636 			dev_kfree_skb(skb);
637 			skb = NULL;
638 			ret = -EINVAL;
639 			continue;
640 		}
641 
642 		wnl = (tAniNlHdr *) nlh;
643 		wnl->radio = plog_msg->radio;
644 		memcpy(&wnl->wmsg, plog_msg->logbuf,
645 		       plog_msg->filled_length + sizeof(tAniHdr));
646 
647 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
648 		list_add_tail(&plog_msg->node, &gwlan_logging.free_list);
649 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
650 
651 		ret = nl_srv_bcast_host_logs(skb);
652 		/* print every 64th drop count */
653 		if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) {
654 			pr_err("%s: Send Failed %d drop_count = %u\n",
655 			       __func__, ret, ++gwlan_logging.drop_count);
656 		}
657 	}
658 
659 	return ret;
660 }
661 
662 #ifdef FEATURE_WLAN_DIAG_SUPPORT
663 /**
664  * wlan_report_log_completion() - Report bug report completion to userspace
665  * @is_fatal: Type of event, fatal or not
666  * @indicator: Source of bug report, framework/host/firmware
667  * @reason_code: Reason for triggering bug report
668  * @ring_id: Ring id of logging entities
669  *
670  * This function is used to report the bug report completion to userspace
671  *
672  * Return: None
673  */
674 void wlan_report_log_completion(uint32_t is_fatal,
675 		uint32_t indicator,
676 		uint32_t reason_code,
677 		uint8_t ring_id)
678 {
679 	WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
680 			struct host_event_wlan_log_complete);
681 
682 	wlan_diag_event.is_fatal = is_fatal;
683 	wlan_diag_event.indicator = indicator;
684 	wlan_diag_event.reason_code = reason_code;
685 	wlan_diag_event.reserved = ring_id;
686 
687 	WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
688 }
689 #endif
690 
691 #ifdef CONFIG_MCL
692 /**
693  * send_flush_completion_to_user() - Indicate flush completion to the user
694  * @ring_id:  Ring id of logging entities
695  *
696  * This function is used to send the flush completion message to user space
697  *
698  * Return: None
699  */
700 static void send_flush_completion_to_user(uint8_t ring_id)
701 {
702 	uint32_t is_fatal, indicator, reason_code;
703 	bool recovery_needed;
704 
705 	cds_get_and_reset_log_completion(&is_fatal,
706 		&indicator, &reason_code, &recovery_needed);
707 
708 	/* Error on purpose, so that it will get logged in the kmsg */
709 	LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
710 			"%s: Sending flush done to userspace reason code %d",
711 			__func__, reason_code);
712 
713 	wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id);
714 
715 	if (recovery_needed)
716 		cds_trigger_recovery(QDF_REASON_UNSPECIFIED);
717 }
718 #endif
719 
720 static void setup_flush_timer(void)
721 {
722 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
723 	if (!gwlan_logging.is_flush_timer_initialized ||
724 	    (gwlan_logging.flush_timer_period == 0)) {
725 		qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
726 		return;
727 	}
728 	qdf_timer_mod(&gwlan_logging.flush_timer,
729 		      gwlan_logging.flush_timer_period);
730 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
731 }
732 
733 /**
734  * wlan_logging_thread() - The WLAN Logger thread
735  * @Arg - pointer to the HDD context
736  *
737  * This thread logs log message to App registered for the logs.
738  */
739 static int wlan_logging_thread(void *Arg)
740 {
741 	int ret_wait_status = 0;
742 	int ret = 0;
743 	unsigned long flags;
744 
745 	while (!gwlan_logging.exit) {
746 		setup_flush_timer();
747 		ret_wait_status =
748 			wait_event_interruptible(gwlan_logging.wait_queue,
749 						 (!list_empty
750 							  (&gwlan_logging.filled_list)
751 						  || test_bit(
752 						     HOST_LOG_DRIVER_MSG,
753 						     &gwlan_logging.eventFlag)
754 						  || test_bit(
755 						     HOST_LOG_PER_PKT_STATS,
756 						     &gwlan_logging.eventFlag)
757 						  || test_bit(
758 						     HOST_LOG_FW_FLUSH_COMPLETE,
759 						     &gwlan_logging.eventFlag)
760 						  || gwlan_logging.exit));
761 
762 		if (ret_wait_status == -ERESTARTSYS) {
763 			pr_err
764 				("%s: wait_event_interruptible returned -ERESTARTSYS",
765 				__func__);
766 			break;
767 		}
768 
769 		if (gwlan_logging.exit)
770 			break;
771 
772 
773 		if (test_and_clear_bit(HOST_LOG_DRIVER_MSG,
774 					&gwlan_logging.eventFlag)) {
775 			ret = send_filled_buffers_to_user();
776 			if (-ENOMEM == ret)
777 				msleep(200);
778 #ifdef CONFIG_MCL
779 			if (WLAN_LOG_INDICATOR_HOST_ONLY ==
780 			   cds_get_log_indicator()) {
781 				send_flush_completion_to_user(
782 						RING_ID_DRIVER_DEBUG);
783 			}
784 #endif
785 		}
786 
787 		if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS,
788 					&gwlan_logging.eventFlag)) {
789 			ret = pktlog_send_per_pkt_stats_to_user();
790 			if (-ENOMEM == ret)
791 				msleep(200);
792 		}
793 
794 		if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE,
795 					&gwlan_logging.eventFlag)) {
796 			/* Flush bit could have been set while we were mid
797 			 * way in the logging thread. So, need to check other
798 			 * buffers like log messages, per packet stats again
799 			 * to flush any residual data in them
800 			 */
801 			if (gwlan_logging.is_flush_complete == true) {
802 				gwlan_logging.is_flush_complete = false;
803 #ifdef CONFIG_MCL
804 				send_flush_completion_to_user(
805 						RING_ID_DRIVER_DEBUG);
806 #endif
807 			} else {
808 				gwlan_logging.is_flush_complete = true;
809 				/* Flush all current host logs*/
810 				spin_lock_irqsave(&gwlan_logging.spin_lock,
811 					flags);
812 				wlan_queue_logmsg_for_app();
813 				spin_unlock_irqrestore(&gwlan_logging.spin_lock,
814 					flags);
815 				set_bit(HOST_LOG_DRIVER_MSG,
816 						&gwlan_logging.eventFlag);
817 				set_bit(HOST_LOG_PER_PKT_STATS,
818 						&gwlan_logging.eventFlag);
819 				set_bit(HOST_LOG_FW_FLUSH_COMPLETE,
820 						&gwlan_logging.eventFlag);
821 				wake_up_interruptible(
822 						&gwlan_logging.wait_queue);
823 			}
824 		}
825 	}
826 
827 	complete_and_exit(&gwlan_logging.shutdown_comp, 0);
828 
829 	return 0;
830 }
831 
832 void wlan_logging_set_active(bool active)
833 {
834 	gwlan_logging.is_active = active;
835 }
836 
837 void wlan_logging_set_log_to_console(bool log_to_console)
838 {
839 	gwlan_logging.log_to_console = log_to_console;
840 }
841 
842 static void flush_log_buffers_timer(void *dummy)
843 {
844 	wlan_flush_host_logs_for_fatal();
845 }
846 
847 int wlan_logging_set_flush_timer(uint32_t milliseconds)
848 {
849 	if (milliseconds > MAX_FLUSH_TIMER_PERIOD_VALUE) {
850 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
851 				"ERROR! value should be (0 - %d)\n",
852 				MAX_FLUSH_TIMER_PERIOD_VALUE);
853 		return -EINVAL;
854 	}
855 	if (!gwlan_logging.is_active) {
856 		QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
857 				"WLAN-Logging not active");
858 		return -EINVAL;
859 	}
860 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
861 	if (!gwlan_logging.is_flush_timer_initialized) {
862 		qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
863 		return -EINVAL;
864 	}
865 	gwlan_logging.flush_timer_period = milliseconds;
866 	if (milliseconds) {
867 		qdf_timer_mod(&gwlan_logging.flush_timer,
868 			      gwlan_logging.flush_timer_period);
869 	}
870 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
871 	return 0;
872 }
873 
874 static void flush_timer_init(void)
875 {
876 	qdf_spinlock_create(&gwlan_logging.flush_timer_lock);
877 	qdf_timer_init(NULL, &gwlan_logging.flush_timer,
878 		       flush_log_buffers_timer, NULL,
879 		       QDF_TIMER_TYPE_SW);
880 	gwlan_logging.is_flush_timer_initialized = true;
881 	gwlan_logging.flush_timer_period = 0;
882 }
883 
884 int wlan_logging_sock_init_svc(void)
885 {
886 	int i = 0, j, pkt_stats_size;
887 	unsigned long irq_flag;
888 
889 	flush_timer_init();
890 	spin_lock_init(&gwlan_logging.spin_lock);
891 	spin_lock_init(&gwlan_logging.pkt_stats_lock);
892 
893 	gwlan_logging.log_to_console = true;
894 	gwlan_logging.num_buf = MAX_LOGMSG_COUNT;
895 	gwlan_logging.buffer_length = MAX_LOGMSG_LENGTH;
896 
897 	if (allocate_log_msg_buffer() != QDF_STATUS_SUCCESS) {
898 		pr_err("%s: Could not allocate memory for log_msg\n",
899 		       __func__);
900 		return -ENOMEM;
901 	}
902 
903 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
904 	INIT_LIST_HEAD(&gwlan_logging.free_list);
905 	INIT_LIST_HEAD(&gwlan_logging.filled_list);
906 
907 	for (i = 0; i < gwlan_logging.num_buf; i++) {
908 		list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
909 		gplog_msg[i].index = i;
910 	}
911 	gwlan_logging.pcur_node = (struct log_msg *)
912 				  (gwlan_logging.free_list.next);
913 	list_del_init(gwlan_logging.free_list.next);
914 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
915 
916 	/* Initialize the pktStats data structure here */
917 	pkt_stats_size = sizeof(struct pkt_stats_msg);
918 	gpkt_stats_buffers = vmalloc(MAX_PKTSTATS_BUFF * pkt_stats_size);
919 	if (!gpkt_stats_buffers) {
920 		pr_err("%s: Could not allocate memory for Pkt stats\n",
921 			__func__);
922 		goto err1;
923 	}
924 	qdf_mem_zero(gpkt_stats_buffers,
925 			MAX_PKTSTATS_BUFF * pkt_stats_size);
926 
927 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
928 	gwlan_logging.pkt_stats_msg_idx = 0;
929 	INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
930 	INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
931 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
932 
933 
934 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
935 		gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH);
936 		if (gpkt_stats_buffers[i].skb == NULL) {
937 			pr_err("%s: Memory alloc failed for skb", __func__);
938 			/* free previously allocated skb and return */
939 			for (j = 0; j < i ; j++)
940 				dev_kfree_skb(gpkt_stats_buffers[j].skb);
941 			goto err2;
942 		}
943 		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
944 		list_add(&gpkt_stats_buffers[i].node,
945 			&gwlan_logging.pkt_stat_free_list);
946 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
947 	}
948 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
949 	gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
950 		(gwlan_logging.pkt_stat_free_list.next);
951 	list_del_init(gwlan_logging.pkt_stat_free_list.next);
952 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
953 	/* Pkt Stats intialization done */
954 
955 	init_waitqueue_head(&gwlan_logging.wait_queue);
956 	gwlan_logging.exit = false;
957 	clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
958 	clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
959 	clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
960 	init_completion(&gwlan_logging.shutdown_comp);
961 	gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
962 					      "wlan_logging_thread");
963 	if (IS_ERR(gwlan_logging.thread)) {
964 		pr_err("%s: Could not Create LogMsg Thread Controller",
965 		       __func__);
966 		goto err3;
967 	}
968 	wake_up_process(gwlan_logging.thread);
969 	gwlan_logging.is_active = true;
970 	gwlan_logging.is_flush_complete = false;
971 
972 	return 0;
973 
974 err3:
975 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
976 		if (gpkt_stats_buffers[i].skb)
977 			dev_kfree_skb(gpkt_stats_buffers[i].skb);
978 	}
979 err2:
980 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
981 	gwlan_logging.pkt_stats_pcur_node = NULL;
982 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
983 	vfree(gpkt_stats_buffers);
984 	gpkt_stats_buffers = NULL;
985 err1:
986 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
987 	gwlan_logging.pcur_node = NULL;
988 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
989 	free_log_msg_buffer();
990 
991 	return -ENOMEM;
992 }
993 
994 static void flush_timer_deinit(void)
995 {
996 	gwlan_logging.is_flush_timer_initialized = false;
997 	qdf_spin_lock(&gwlan_logging.flush_timer_lock);
998 	qdf_timer_stop(&gwlan_logging.flush_timer);
999 	qdf_timer_free(&gwlan_logging.flush_timer);
1000 	qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
1001 	qdf_spinlock_destroy(&gwlan_logging.flush_timer_lock);
1002 }
1003 
1004 int wlan_logging_sock_deinit_svc(void)
1005 {
1006 	unsigned long irq_flag;
1007 	int i;
1008 
1009 	if (!gwlan_logging.pcur_node)
1010 		return 0;
1011 
1012 #ifdef CONFIG_MCL
1013 	INIT_COMPLETION(gwlan_logging.shutdown_comp);
1014 #endif
1015 	gwlan_logging.exit = true;
1016 	gwlan_logging.is_active = false;
1017 #ifdef CONFIG_MCL
1018 	cds_set_multicast_logging(0);
1019 #endif
1020 	gwlan_logging.is_flush_complete = false;
1021 	clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
1022 	clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1023 	clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
1024 	wake_up_interruptible(&gwlan_logging.wait_queue);
1025 	wait_for_completion(&gwlan_logging.shutdown_comp);
1026 
1027 	spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
1028 	gwlan_logging.pcur_node = NULL;
1029 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
1030 
1031 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
1032 	gwlan_logging.pkt_stats_pcur_node = NULL;
1033 	gwlan_logging.pkt_stats_msg_idx = 0;
1034 	gwlan_logging.pkt_stat_drop_cnt = 0;
1035 	for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
1036 		if (gpkt_stats_buffers[i].skb)
1037 			dev_kfree_skb(gpkt_stats_buffers[i].skb);
1038 	}
1039 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
1040 
1041 	vfree(gpkt_stats_buffers);
1042 	gpkt_stats_buffers = NULL;
1043 	free_log_msg_buffer();
1044 	flush_timer_deinit();
1045 
1046 	return 0;
1047 }
1048 
1049 /**
1050  * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging
1051  *
1052  * This function is used to send signal to the logger thread for logging per
1053  * packet stats
1054  *
1055  * Return: None
1056  *
1057  */
1058 void wlan_logging_set_per_pkt_stats(void)
1059 {
1060 	if (gwlan_logging.is_active == false)
1061 		return;
1062 
1063 	set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1064 	wake_up_interruptible(&gwlan_logging.wait_queue);
1065 }
1066 
1067 /*
1068  * wlan_logging_set_fw_flush_complete() - FW log flush completion
1069  *
1070  * This function is used to send signal to the logger thread to indicate
1071  * that the flushing of FW logs is complete by the FW
1072  *
1073  * Return: None
1074  *
1075  */
1076 void wlan_logging_set_fw_flush_complete(void)
1077 {
1078 	if (gwlan_logging.is_active == false
1079 #ifdef CONFIG_MCL
1080 	    || !cds_is_fatal_event_enabled()
1081 #endif
1082 	   )
1083 		return;
1084 
1085 	set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
1086 	wake_up_interruptible(&gwlan_logging.wait_queue);
1087 }
1088 
1089 /**
1090  * wlan_flush_host_logs_for_fatal() - Flush host logs
1091  *
1092  * This function is used to send signal to the logger thread to
1093  * Flush the host logs
1094  *
1095  * Return: None
1096  */
1097 void wlan_flush_host_logs_for_fatal(void)
1098 {
1099 	unsigned long flags;
1100 
1101 #ifdef CONFIG_MCL
1102 	if (cds_is_log_report_in_progress()) {
1103 #endif
1104 		if (gwlan_logging.flush_timer_period == 0)
1105 			pr_info("%s:flush all host logs Setting HOST_LOG_POST_MASK\n",
1106 				__func__);
1107 		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
1108 		wlan_queue_logmsg_for_app();
1109 		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
1110 		set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
1111 		wake_up_interruptible(&gwlan_logging.wait_queue);
1112 #ifdef CONFIG_MCL
1113 	}
1114 #endif
1115 }
1116 
1117 #ifdef CONFIG_MCL
1118 #ifndef REMOVE_PKT_LOG
1119 
1120 static uint8_t gtx_count;
1121 static uint8_t grx_count;
1122 
1123 /**
1124  * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats
1125  *
1126  * This function is used to get the free node for pkt stats from
1127  * free list/filles list
1128  *
1129  * Return: int
1130  *
1131  */
1132 static int wlan_get_pkt_stats_free_node(void)
1133 {
1134 	int ret = 0;
1135 
1136 	list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
1137 			&gwlan_logging.pkt_stat_filled_list);
1138 
1139 	if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
1140 		/* Get buffer from free list */
1141 		gwlan_logging.pkt_stats_pcur_node =
1142 		(struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
1143 		list_del_init(gwlan_logging.pkt_stat_free_list.next);
1144 	} else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
1145 		/* Get buffer from filled list. This condition will drop the
1146 		 * packet from being indicated to app
1147 		 */
1148 		gwlan_logging.pkt_stats_pcur_node =
1149 			(struct pkt_stats_msg *)
1150 				(gwlan_logging.pkt_stat_filled_list.next);
1151 		++gwlan_logging.pkt_stat_drop_cnt;
1152 		/* print every 64th drop count */
1153 		if (
1154 			cds_is_multicast_logging() &&
1155 			(!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
1156 			pr_err("%s: drop_count = %u\n",
1157 				__func__, gwlan_logging.pkt_stat_drop_cnt);
1158 		}
1159 		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
1160 		ret = 1;
1161 	}
1162 
1163 	/* Reset the skb values, essential if dequeued from filled list */
1164 	skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0);
1165 	return ret;
1166 }
1167 
1168 /**
1169  * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB
1170  * @pl_hdr: Pointer to pl_hdr
1171  * @pkt_dump: Pointer to pkt_dump
1172  * @data: Pointer to data
1173  *
1174  * This function adds the pktstats hdr and data to current
1175  * skb node of free list.
1176  *
1177  * Return: None
1178  */
1179 void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
1180 {
1181 	struct ath_pktlog_hdr *pktlog_hdr;
1182 	struct packet_dump *pkt_stats_dump;
1183 	int total_stats_len = 0;
1184 	bool wake_up_thread = false;
1185 	unsigned long flags;
1186 	struct sk_buff *ptr;
1187 	int hdr_size;
1188 
1189 	pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr;
1190 
1191 	if (pktlog_hdr == NULL) {
1192 		pr_err("%s : Invalid pkt_stats_header\n", __func__);
1193 		return;
1194 	}
1195 
1196 	pkt_stats_dump = (struct packet_dump *)pkt_dump;
1197 	total_stats_len = sizeof(struct ath_pktlog_hdr) +
1198 					pktlog_hdr->size;
1199 
1200 	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
1201 
1202 	if (!gwlan_logging.pkt_stats_pcur_node || (NULL == pkt_stats_dump)) {
1203 		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
1204 		return;
1205 	}
1206 
1207 	/* Check if we can accommodate more log into current node/buffer */
1208 	hdr_size = sizeof(struct host_log_pktlog_info) +
1209 			sizeof(tAniNlHdr);
1210 	if ((total_stats_len +  hdr_size) >=
1211 		skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
1212 		wake_up_thread = true;
1213 		wlan_get_pkt_stats_free_node();
1214 	}
1215 
1216 	ptr = gwlan_logging.pkt_stats_pcur_node->skb;
1217 	qdf_mem_copy(skb_put(ptr,
1218 			sizeof(struct ath_pktlog_hdr)),
1219 			pktlog_hdr,
1220 			sizeof(struct ath_pktlog_hdr));
1221 
1222 	if (pkt_stats_dump) {
1223 		qdf_mem_copy(skb_put(ptr,
1224 				sizeof(struct packet_dump)),
1225 				pkt_stats_dump,
1226 				sizeof(struct packet_dump));
1227 		pktlog_hdr->size -= sizeof(struct packet_dump);
1228 	}
1229 
1230 	if (data)
1231 		qdf_mem_copy(skb_put(ptr,
1232 				pktlog_hdr->size),
1233 				data, pktlog_hdr->size);
1234 
1235 	if (pkt_stats_dump->type == STOP_MONITOR) {
1236 		wake_up_thread = true;
1237 		wlan_get_pkt_stats_free_node();
1238 	}
1239 
1240 	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
1241 
1242 	/* Wakeup logger thread */
1243 	if (true == wake_up_thread) {
1244 		set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
1245 		wake_up_interruptible(&gwlan_logging.wait_queue);
1246 	}
1247 }
1248 
1249 /**
1250  * driver_hal_status_map() - maps driver to hal
1251  * status
1252  * @status: status to be mapped
1253  *
1254  * This function is used to map driver to hal status
1255  *
1256  * Return: None
1257  *
1258  */
1259 static void driver_hal_status_map(uint8_t *status)
1260 {
1261 	switch (*status) {
1262 	case tx_status_ok:
1263 		*status = TX_PKT_FATE_ACKED;
1264 		break;
1265 	case tx_status_discard:
1266 		*status = TX_PKT_FATE_DRV_DROP_OTHER;
1267 		break;
1268 	case tx_status_no_ack:
1269 		*status = TX_PKT_FATE_SENT;
1270 		break;
1271 	case tx_status_download_fail:
1272 		*status = TX_PKT_FATE_FW_QUEUED;
1273 		break;
1274 	default:
1275 		*status = TX_PKT_FATE_DRV_DROP_OTHER;
1276 		break;
1277 	}
1278 }
1279 
1280 /*
1281  * send_packetdump() - send packet dump
1282  * @netbuf: netbuf
1283  * @status: status of tx packet
1284  * @vdev_id: virtual device id
1285  * @type: type of packet
1286  *
1287  * This function is used to send packet dump to HAL layer
1288  * using wlan_pkt_stats_to_logger_thread
1289  *
1290  * Return: None
1291  *
1292  */
1293 static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status,
1294 				uint8_t vdev_id, uint8_t type)
1295 {
1296 	struct ath_pktlog_hdr pktlog_hdr = {0};
1297 	struct packet_dump pd_hdr = {0};
1298 	struct hdd_context *hdd_ctx;
1299 	struct hdd_adapter *adapter;
1300 
1301 	hdd_ctx = (struct hdd_context *)cds_get_context(QDF_MODULE_ID_HDD);
1302 	if (!hdd_ctx)
1303 		return;
1304 
1305 	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
1306 	if (!adapter)
1307 		return;
1308 
1309 	/* Send packet dump only for STA interface */
1310 	if (adapter->device_mode != QDF_STA_MODE)
1311 		return;
1312 
1313 #if defined(HELIUMPLUS)
1314 	pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
1315 #endif
1316 
1317 	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
1318 	pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
1319 
1320 	pd_hdr.status = status;
1321 	pd_hdr.type = type;
1322 	pd_hdr.driver_ts = qdf_get_monotonic_boottime();
1323 
1324 	if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
1325 		gtx_count++;
1326 	else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
1327 		grx_count++;
1328 
1329 	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
1330 }
1331 
1332 
1333 /*
1334  * send_packetdump_monitor() - sends start/stop packet dump indication
1335  * @type: type of packet
1336  *
1337  * This function is used to indicate HAL layer to start/stop monitoring
1338  * of packets
1339  *
1340  * Return: None
1341  *
1342  */
1343 static void send_packetdump_monitor(uint8_t type)
1344 {
1345 	struct ath_pktlog_hdr pktlog_hdr = {0};
1346 	struct packet_dump pd_hdr = {0};
1347 
1348 #if defined(HELIUMPLUS)
1349 	pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
1350 #endif
1351 
1352 	pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
1353 	pktlog_hdr.size = sizeof(pd_hdr);
1354 
1355 	pd_hdr.type = type;
1356 
1357 	LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1358 			"fate Tx-Rx %s: type: %d", __func__, type);
1359 
1360 	wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
1361 }
1362 
1363 /**
1364  * wlan_deregister_txrx_packetdump() - tx/rx packet dump
1365  *  deregistration
1366  *
1367  * This function is used to deregister tx/rx packet dump callbacks
1368  * with ol, pe and htt layers
1369  *
1370  * Return: None
1371  *
1372  */
1373 void wlan_deregister_txrx_packetdump(void)
1374 {
1375 	if (gtx_count || grx_count) {
1376 		ol_deregister_packetdump_callback();
1377 		wma_deregister_packetdump_callback();
1378 		send_packetdump_monitor(STOP_MONITOR);
1379 		csr_packetdump_timer_stop();
1380 
1381 		gtx_count = 0;
1382 		grx_count = 0;
1383 	} else
1384 		LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1385 			"%s: deregistered packetdump already", __func__);
1386 }
1387 
1388 /*
1389  * check_txrx_packetdump_count() - function to check
1390  * tx/rx packet dump global counts
1391  *
1392  * This function is used to check global counts of tx/rx
1393  * packet dump functionality.
1394  *
1395  * Return: 1 if either gtx_count or grx_count reached 32
1396  *             0 otherwise
1397  *
1398  */
1399 static bool check_txrx_packetdump_count(void)
1400 {
1401 	if (gtx_count == MAX_NUM_PKT_LOG ||
1402 		grx_count == MAX_NUM_PKT_LOG) {
1403 		LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
1404 			"%s gtx_count: %d grx_count: %d deregister packetdump",
1405 			__func__, gtx_count, grx_count);
1406 		wlan_deregister_txrx_packetdump();
1407 		return 1;
1408 	}
1409 	return 0;
1410 }
1411 
1412 /*
1413  * tx_packetdump_cb() - tx packet dump callback
1414  * @netbuf: netbuf
1415  * @status: status of tx packet
1416  * @vdev_id: virtual device id
1417  * @type: packet type
1418  *
1419  * This function is used to send tx packet dump to HAL layer
1420  * and deregister packet dump callbacks
1421  *
1422  * Return: None
1423  *
1424  */
1425 static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
1426 				uint8_t vdev_id, uint8_t type)
1427 {
1428 	bool temp;
1429 
1430 	temp = check_txrx_packetdump_count();
1431 	if (temp)
1432 		return;
1433 
1434 	driver_hal_status_map(&status);
1435 	send_packetdump(netbuf, status, vdev_id, type);
1436 }
1437 
1438 
1439 /*
1440  * rx_packetdump_cb() - rx packet dump callback
1441  * @netbuf: netbuf
1442  * @status: status of rx packet
1443  * @vdev_id: virtual device id
1444  * @type: packet type
1445  *
1446  * This function is used to send rx packet dump to HAL layer
1447  * and deregister packet dump callbacks
1448  *
1449  * Return: None
1450  *
1451  */
1452 static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
1453 				uint8_t vdev_id, uint8_t type)
1454 {
1455 	bool temp;
1456 
1457 	temp = check_txrx_packetdump_count();
1458 	if (temp)
1459 		return;
1460 
1461 	send_packetdump(netbuf, status, vdev_id, type);
1462 }
1463 
1464 
1465 /**
1466  * wlan_register_txrx_packetdump() - tx/rx packet dump
1467  * registration
1468  *
1469  * This function is used to register tx/rx packet dump callbacks
1470  * with ol, pe and htt layers
1471  *
1472  * Return: None
1473  *
1474  */
1475 void wlan_register_txrx_packetdump(void)
1476 {
1477 	ol_register_packetdump_callback(tx_packetdump_cb,
1478 			rx_packetdump_cb);
1479 	wma_register_packetdump_callback(tx_packetdump_cb,
1480 			rx_packetdump_cb);
1481 	send_packetdump_monitor(START_MONITOR);
1482 
1483 	gtx_count = 0;
1484 	grx_count = 0;
1485 }
1486 #endif /* REMOVE_PKT_LOG */
1487 #endif /* CONFIG_MCL */
1488 #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
1489