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