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