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