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