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