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