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