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