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