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