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