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 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 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 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 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 */ 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 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 */ 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 675 int pktlog_send_per_pkt_stats_to_user(void) 676 { 677 return 0; 678 } 679 #endif 680 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 */ 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 */ 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 817 static void wlan_logging_set_flush_log_completion(void) 818 { 819 qdf_event_set(&gwlan_logging.flush_log_completion); 820 } 821 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 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 846 wlan_logging_send_connectivity_event(void) 847 { 848 return wlan_connectivity_log_dequeue(); 849 } 850 #else 851 static inline QDF_STATUS 852 wlan_logging_send_connectivity_event(void) 853 { 854 return QDF_STATUS_E_NOSUPPORT; 855 } 856 #endif 857 858 #ifdef WLAN_CHIPSET_STATS 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 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 869 static int wlan_logging_cstats_send_host_buf_to_usr(void) 870 { 871 return 0; 872 } 873 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 */ 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 1015 void wlan_logging_set_active(bool active) 1016 { 1017 gwlan_logging.is_active = active; 1018 } 1019 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 1027 static void flush_log_buffers_timer(void *dummy) 1028 { 1029 wlan_flush_host_logs_for_fatal(); 1030 } 1031 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 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 */ 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 */ 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 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 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 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 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 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 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 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