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