1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * 22 * Permission to use, copy, modify, and/or distribute this software for any 23 * purpose with or without fee is hereby granted, provided that the above 24 * copyright notice and this permission notice appear in all copies. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 27 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 28 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 29 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 30 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 31 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 32 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 */ 34 35 #ifndef REMOVE_PKT_LOG 36 37 #include "qdf_mem.h" 38 #include "athdefs.h" 39 #include "pktlog_ac_i.h" 40 #include "cds_api.h" 41 #include "wma_types.h" 42 #include "htc.h" 43 #include <cdp_txrx_cmn_struct.h> 44 #include <cdp_txrx_ctrl.h> 45 #ifdef PKTLOG_LEGACY 46 #include "pktlog_wifi2.h" 47 #else 48 #include "pktlog_wifi3.h" 49 #endif /* PKTLOG_LEGACY */ 50 51 wdi_event_subscribe PKTLOG_TX_SUBSCRIBER; 52 wdi_event_subscribe PKTLOG_RX_SUBSCRIBER; 53 wdi_event_subscribe PKTLOG_RX_REMOTE_SUBSCRIBER; 54 wdi_event_subscribe PKTLOG_RCFIND_SUBSCRIBER; 55 wdi_event_subscribe PKTLOG_RCUPDATE_SUBSCRIBER; 56 wdi_event_subscribe PKTLOG_SW_EVENT_SUBSCRIBER; 57 wdi_event_subscribe PKTLOG_LITE_T2H_SUBSCRIBER; 58 wdi_event_subscribe PKTLOG_LITE_RX_SUBSCRIBER; 59 wdi_event_subscribe PKTLOG_OFFLOAD_SUBSCRIBER; 60 #ifdef BE_PKTLOG_SUPPORT 61 wdi_event_subscribe PKTLOG_HYBRID_SUBSCRIBER; 62 #endif 63 64 struct ol_pl_arch_dep_funcs ol_pl_funcs = { 65 .pktlog_init = pktlog_init, 66 .pktlog_enable = pktlog_enable, 67 .pktlog_setsize = pktlog_setsize, 68 .pktlog_disable = pktlog_disable, /* valid for f/w disable */ 69 }; 70 71 struct pktlog_dev_t pl_dev = { 72 .pl_funcs = &ol_pl_funcs, 73 }; 74 75 void pktlog_sethandle(struct pktlog_dev_t **pl_handle, 76 struct hif_opaque_softc *scn) 77 { 78 pl_dev.scn = (ol_ath_generic_softc_handle) scn; 79 *pl_handle = &pl_dev; 80 } 81 82 void pktlog_set_pdev_id(struct pktlog_dev_t *pl_dev, uint8_t pdev_id) 83 { 84 pl_dev->pdev_id = pdev_id; 85 } 86 87 void pktlog_set_callback_regtype( 88 enum pktlog_callback_regtype callback_type) 89 { 90 struct pktlog_dev_t *pl_dev = get_pktlog_handle(); 91 92 if (!pl_dev) { 93 qdf_print("Invalid pl_dev"); 94 return; 95 } 96 97 pl_dev->callback_type = callback_type; 98 } 99 100 struct pktlog_dev_t *get_pktlog_handle(void) 101 { 102 uint8_t pdev_id = WMI_PDEV_ID_SOC; 103 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 104 105 return cdp_get_pldev(soc, pdev_id); 106 } 107 108 static A_STATUS pktlog_wma_post_msg(WMI_PKTLOG_EVENT event_types, 109 WMI_CMD_ID cmd_id, bool ini_triggered, 110 uint8_t user_triggered) 111 { 112 struct scheduler_msg msg = { 0 }; 113 QDF_STATUS status; 114 struct ath_pktlog_wmi_params *param; 115 116 param = qdf_mem_malloc(sizeof(struct ath_pktlog_wmi_params)); 117 118 if (!param) 119 return A_NO_MEMORY; 120 121 param->cmd_id = cmd_id; 122 param->pktlog_event = event_types; 123 param->ini_triggered = ini_triggered; 124 param->user_triggered = user_triggered; 125 126 msg.type = WMA_PKTLOG_ENABLE_REQ; 127 msg.bodyptr = param; 128 msg.bodyval = 0; 129 130 status = scheduler_post_message(QDF_MODULE_ID_WMA, 131 QDF_MODULE_ID_WMA, 132 QDF_MODULE_ID_WMA, &msg); 133 134 if (status != QDF_STATUS_SUCCESS) { 135 qdf_mem_free(param); 136 return A_ERROR; 137 } 138 139 return A_OK; 140 } 141 142 static inline A_STATUS 143 pktlog_enable_tgt(struct hif_opaque_softc *_scn, uint32_t log_state, 144 bool ini_triggered, uint8_t user_triggered) 145 { 146 uint32_t types = 0; 147 148 if (log_state & ATH_PKTLOG_TX) 149 types |= WMI_PKTLOG_EVENT_TX; 150 151 if (log_state & ATH_PKTLOG_RX) 152 types |= WMI_PKTLOG_EVENT_RX; 153 154 if (log_state & ATH_PKTLOG_RCFIND) 155 types |= WMI_PKTLOG_EVENT_RCF; 156 157 if (log_state & ATH_PKTLOG_RCUPDATE) 158 types |= WMI_PKTLOG_EVENT_RCU; 159 160 if (log_state & ATH_PKTLOG_SW_EVENT) 161 types |= WMI_PKTLOG_EVENT_SW; 162 163 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, 164 "%s: Pktlog events: %d", __func__, types); 165 166 return pktlog_wma_post_msg(types, WMI_PDEV_PKTLOG_ENABLE_CMDID, 167 ini_triggered, user_triggered); 168 } 169 170 #ifdef PKTLOG_LEGACY 171 /** 172 * wdi_pktlog_subscribe() - Subscribe pktlog callbacks 173 * @pdev_id: pdev id 174 * @log_state: Pktlog registration 175 * 176 * Return: zero on success, non-zero on failure 177 */ 178 static inline A_STATUS 179 wdi_pktlog_subscribe(uint8_t pdev_id, int32_t log_state) 180 { 181 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 182 183 if (pdev_id < 0) { 184 qdf_print("Invalid pdev"); 185 return A_ERROR; 186 } 187 188 if (log_state & ATH_PKTLOG_TX) { 189 if (cdp_wdi_event_sub(soc, pdev_id, &PKTLOG_TX_SUBSCRIBER, 190 WDI_EVENT_TX_STATUS)) { 191 return A_ERROR; 192 } 193 } 194 if (log_state & ATH_PKTLOG_RX) { 195 if (cdp_wdi_event_sub(soc, pdev_id, &PKTLOG_RX_SUBSCRIBER, 196 WDI_EVENT_RX_DESC)) { 197 return A_ERROR; 198 } 199 if (cdp_wdi_event_sub(soc, pdev_id, 200 &PKTLOG_RX_REMOTE_SUBSCRIBER, 201 WDI_EVENT_RX_DESC_REMOTE)) { 202 return A_ERROR; 203 } 204 } 205 if (log_state & ATH_PKTLOG_RCFIND) { 206 if (cdp_wdi_event_sub(soc, pdev_id, 207 &PKTLOG_RCFIND_SUBSCRIBER, 208 WDI_EVENT_RATE_FIND)) { 209 return A_ERROR; 210 } 211 } 212 if (log_state & ATH_PKTLOG_RCUPDATE) { 213 if (cdp_wdi_event_sub(soc, pdev_id, 214 &PKTLOG_RCUPDATE_SUBSCRIBER, 215 WDI_EVENT_RATE_UPDATE)) { 216 return A_ERROR; 217 } 218 } 219 if (log_state & ATH_PKTLOG_SW_EVENT) { 220 if (cdp_wdi_event_sub(soc, pdev_id, 221 &PKTLOG_SW_EVENT_SUBSCRIBER, 222 WDI_EVENT_SW_EVENT)) { 223 return A_ERROR; 224 } 225 } 226 227 return A_OK; 228 } 229 #else 230 static inline A_STATUS 231 wdi_pktlog_subscribe(uint8_t pdev_id, int32_t log_state) 232 { 233 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 234 235 if (pdev_id < 0) { 236 qdf_print("Invalid pdev"); 237 return A_ERROR; 238 } 239 240 if ((log_state & ATH_PKTLOG_TX) || 241 (log_state & ATH_PKTLOG_RCFIND) || 242 (log_state & ATH_PKTLOG_RCUPDATE) || 243 (log_state & ATH_PKTLOG_SW_EVENT)) { 244 if (cdp_wdi_event_sub(soc, 245 pdev_id, 246 &PKTLOG_OFFLOAD_SUBSCRIBER, 247 WDI_EVENT_OFFLOAD_ALL)) { 248 return A_ERROR; 249 } 250 } 251 252 if (log_state & ATH_PKTLOG_RX) { 253 if (cdp_wdi_event_sub(soc, pdev_id, 254 &PKTLOG_RX_SUBSCRIBER, 255 WDI_EVENT_RX_DESC)) { 256 return A_ERROR; 257 } 258 } 259 260 if (log_state & ATH_PKTLOG_SW_EVENT) { 261 if (cdp_wdi_event_sub(soc, pdev_id, 262 &PKTLOG_SW_EVENT_SUBSCRIBER, 263 WDI_EVENT_SW_EVENT)) { 264 return A_ERROR; 265 } 266 } 267 268 if (log_state & ATH_PKTLOG_LITE_T2H) { 269 if (cdp_wdi_event_sub(soc, pdev_id, 270 &PKTLOG_LITE_T2H_SUBSCRIBER, 271 WDI_EVENT_LITE_T2H)) { 272 return A_ERROR; 273 } 274 } 275 276 if (log_state & ATH_PKTLOG_LITE_RX) { 277 if (cdp_wdi_event_sub(soc, pdev_id, 278 &PKTLOG_LITE_RX_SUBSCRIBER, 279 WDI_EVENT_LITE_RX)) { 280 return A_ERROR; 281 } 282 } 283 284 return A_OK; 285 } 286 #endif 287 288 void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data, 289 u_int16_t peer_id, uint32_t status) 290 { 291 switch (event) { 292 case WDI_EVENT_OFFLOAD_ALL: 293 { 294 if (process_offload_pktlog_wifi3(pdev, log_data)) { 295 qdf_print("Unable to process offload info"); 296 return; 297 } 298 break; 299 } 300 case WDI_EVENT_TX_STATUS: 301 { 302 /* 303 * process TX message 304 */ 305 if (process_tx_info(pdev, log_data)) { 306 qdf_print("Unable to process TX info"); 307 return; 308 } 309 break; 310 } 311 case WDI_EVENT_RX_DESC: 312 { 313 /* 314 * process RX message for local frames 315 */ 316 if (process_rx_info(pdev, log_data)) { 317 qdf_print("Unable to process RX info"); 318 return; 319 } 320 break; 321 } 322 case WDI_EVENT_RX_DESC_REMOTE: 323 { 324 /* 325 * process RX message for remote frames 326 */ 327 if (process_rx_info_remote(pdev, log_data)) { 328 qdf_print("Unable to process RX info"); 329 return; 330 } 331 break; 332 } 333 case WDI_EVENT_RATE_FIND: 334 { 335 /* 336 * process RATE_FIND message 337 */ 338 if (process_rate_find(pdev, log_data)) { 339 qdf_print("Unable to process RC_FIND info"); 340 return; 341 } 342 break; 343 } 344 case WDI_EVENT_RATE_UPDATE: 345 { 346 /* 347 * process RATE_UPDATE message 348 */ 349 if (process_rate_update(pdev, log_data)) { 350 qdf_print("Unable to process RC_UPDATE"); 351 return; 352 } 353 break; 354 } 355 case WDI_EVENT_SW_EVENT: 356 { 357 /* 358 * process SW EVENT message 359 */ 360 if (process_sw_event(pdev, log_data)) { 361 qdf_print("Unable to process SW_EVENT"); 362 return; 363 } 364 break; 365 } 366 default: 367 break; 368 } 369 } 370 371 void 372 lit_pktlog_callback(void *context, enum WDI_EVENT event, void *log_data, 373 u_int16_t peer_id, uint32_t status) 374 { 375 switch (event) { 376 case WDI_EVENT_RX_DESC: 377 { 378 if (process_rx_desc_remote_wifi3(context, log_data)) { 379 qdf_print("Unable to process RX info"); 380 return; 381 } 382 break; 383 } 384 case WDI_EVENT_LITE_T2H: 385 { 386 if (process_pktlog_lite_wifi3(context, log_data, 387 PKTLOG_TYPE_LITE_T2H)) { 388 qdf_print("Unable to process lite_t2h"); 389 return; 390 } 391 break; 392 } 393 case WDI_EVENT_LITE_RX: 394 { 395 if (process_pktlog_lite_wifi3(context, log_data, 396 PKTLOG_TYPE_LITE_RX)) { 397 qdf_print("Unable to process lite_rx"); 398 return; 399 } 400 break; 401 } 402 default: 403 break; 404 } 405 } 406 407 #ifdef PKTLOG_LEGACY 408 A_STATUS 409 wdi_pktlog_unsubscribe(uint8_t pdev_id, uint32_t log_state) 410 { 411 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 412 /* TODO: WIN implementation to get soc */ 413 414 if (log_state & ATH_PKTLOG_TX) { 415 if (cdp_wdi_event_unsub(soc, pdev_id, 416 &PKTLOG_TX_SUBSCRIBER, 417 WDI_EVENT_TX_STATUS)) { 418 return A_ERROR; 419 } 420 } 421 if (log_state & ATH_PKTLOG_RX) { 422 if (cdp_wdi_event_unsub(soc, pdev_id, 423 &PKTLOG_RX_SUBSCRIBER, 424 WDI_EVENT_RX_DESC)) { 425 return A_ERROR; 426 } 427 if (cdp_wdi_event_unsub(soc, pdev_id, 428 &PKTLOG_RX_REMOTE_SUBSCRIBER, 429 WDI_EVENT_RX_DESC_REMOTE)) { 430 return A_ERROR; 431 } 432 } 433 434 if (log_state & ATH_PKTLOG_RCFIND) { 435 if (cdp_wdi_event_unsub(soc, pdev_id, 436 &PKTLOG_RCFIND_SUBSCRIBER, 437 WDI_EVENT_RATE_FIND)) { 438 return A_ERROR; 439 } 440 } 441 if (log_state & ATH_PKTLOG_RCUPDATE) { 442 if (cdp_wdi_event_unsub(soc, pdev_id, 443 &PKTLOG_RCUPDATE_SUBSCRIBER, 444 WDI_EVENT_RATE_UPDATE)) { 445 return A_ERROR; 446 } 447 } 448 if (log_state & ATH_PKTLOG_RCUPDATE) { 449 if (cdp_wdi_event_unsub(soc, pdev_id, 450 &PKTLOG_SW_EVENT_SUBSCRIBER, 451 WDI_EVENT_SW_EVENT)) { 452 return A_ERROR; 453 } 454 } 455 456 return A_OK; 457 } 458 #else 459 A_STATUS 460 wdi_pktlog_unsubscribe(uint8_t pdev_id, uint32_t log_state) 461 { 462 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 463 464 if ((log_state & ATH_PKTLOG_TX) || 465 (log_state & ATH_PKTLOG_RCFIND) || 466 (log_state & ATH_PKTLOG_RCUPDATE) || 467 (log_state & ATH_PKTLOG_SW_EVENT)) { 468 if (cdp_wdi_event_unsub(soc, 469 pdev_id, 470 &PKTLOG_OFFLOAD_SUBSCRIBER, 471 WDI_EVENT_OFFLOAD_ALL)) { 472 return A_ERROR; 473 } 474 } 475 if (log_state & ATH_PKTLOG_RX) { 476 if (cdp_wdi_event_unsub(soc, pdev_id, 477 &PKTLOG_RX_SUBSCRIBER, 478 WDI_EVENT_RX_DESC)) { 479 return A_ERROR; 480 } 481 } 482 if (log_state & ATH_PKTLOG_LITE_T2H) { 483 if (cdp_wdi_event_unsub(soc, pdev_id, 484 &PKTLOG_LITE_T2H_SUBSCRIBER, 485 WDI_EVENT_LITE_T2H)) { 486 return A_ERROR; 487 } 488 } 489 if (log_state & ATH_PKTLOG_LITE_RX) { 490 if (cdp_wdi_event_unsub(soc, pdev_id, 491 &PKTLOG_LITE_RX_SUBSCRIBER, 492 WDI_EVENT_LITE_RX)) { 493 return A_ERROR; 494 } 495 } 496 497 return A_OK; 498 } 499 #endif 500 501 int pktlog_disable(struct hif_opaque_softc *scn) 502 { 503 struct pktlog_dev_t *pl_dev; 504 struct ath_pktlog_info *pl_info; 505 uint8_t save_pktlog_state; 506 uint8_t pdev_id = WMI_PDEV_ID_SOC; 507 508 pl_dev = get_pktlog_handle(); 509 510 if (!pl_dev) { 511 qdf_print("Invalid pl_dev"); 512 return -EINVAL; 513 } 514 515 pl_info = pl_dev->pl_info; 516 517 if (!pl_dev->pl_info) { 518 qdf_print("Invalid pl_info"); 519 return -EINVAL; 520 } 521 522 if (pdev_id < 0) { 523 qdf_print("Invalid pdev"); 524 return -EINVAL; 525 } 526 527 if (pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS || 528 pl_info->curr_pkt_state == 529 PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED || 530 pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE || 531 pl_info->curr_pkt_state == 532 PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) 533 return -EBUSY; 534 535 save_pktlog_state = pl_info->curr_pkt_state; 536 pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; 537 538 if (pktlog_wma_post_msg(0, WMI_PDEV_PKTLOG_DISABLE_CMDID, 0, 0)) { 539 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 540 qdf_print("Failed to disable pktlog in target"); 541 return -EINVAL; 542 } 543 544 if (pl_dev->is_pktlog_cb_subscribed && 545 wdi_pktlog_unsubscribe(pdev_id, pl_info->log_state)) { 546 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 547 qdf_print("Cannot unsubscribe pktlog from the WDI"); 548 return -EINVAL; 549 } 550 pl_dev->is_pktlog_cb_subscribed = false; 551 if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_START) 552 pl_info->curr_pkt_state = 553 PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED; 554 else 555 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 556 return 0; 557 } 558 559 #ifdef PKTLOG_LEGACY 560 /** 561 * pktlog_callback_registration() - Register pktlog handlers based on 562 * on callback type 563 * @callback_type: pktlog full or lite registration 564 * 565 * Return: None 566 */ 567 static void pktlog_callback_registration(uint8_t callback_type) 568 { 569 if (callback_type == PKTLOG_DEFAULT_CALLBACK_REGISTRATION) { 570 PKTLOG_TX_SUBSCRIBER.callback = pktlog_callback; 571 PKTLOG_RX_SUBSCRIBER.callback = pktlog_callback; 572 PKTLOG_RX_REMOTE_SUBSCRIBER.callback = pktlog_callback; 573 PKTLOG_RCFIND_SUBSCRIBER.callback = pktlog_callback; 574 PKTLOG_RCUPDATE_SUBSCRIBER.callback = pktlog_callback; 575 PKTLOG_SW_EVENT_SUBSCRIBER.callback = pktlog_callback; 576 } 577 } 578 #else 579 static void pktlog_callback_registration(uint8_t callback_type) 580 { 581 if (callback_type == PKTLOG_DEFAULT_CALLBACK_REGISTRATION) { 582 PKTLOG_RX_SUBSCRIBER.callback = lit_pktlog_callback; 583 PKTLOG_LITE_T2H_SUBSCRIBER.callback = lit_pktlog_callback; 584 PKTLOG_OFFLOAD_SUBSCRIBER.callback = pktlog_callback; 585 } else if (callback_type == PKTLOG_LITE_CALLBACK_REGISTRATION) { 586 PKTLOG_LITE_T2H_SUBSCRIBER.callback = lit_pktlog_callback; 587 PKTLOG_LITE_RX_SUBSCRIBER.callback = lit_pktlog_callback; 588 } 589 } 590 #endif 591 592 #define ONE_MEGABYTE (1024 * 1024) 593 594 void pktlog_init(struct hif_opaque_softc *scn) 595 { 596 struct pktlog_dev_t *pl_dev = get_pktlog_handle(); 597 struct ath_pktlog_info *pl_info; 598 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 599 uint32_t buff_size; 600 601 if (!pl_dev || !pl_dev->pl_info) { 602 qdf_print("pl_dev or pl_info is invalid"); 603 return; 604 } 605 606 pl_info = pl_dev->pl_info; 607 608 OS_MEMZERO(pl_info, sizeof(*pl_info)); 609 PKTLOG_LOCK_INIT(pl_info); 610 mutex_init(&pl_info->pktlog_mutex); 611 612 buff_size = cdp_cfg_get(soc, cfg_dp_pktlog_buffer_size) * ONE_MEGABYTE; 613 614 pl_info->buf_size = (buff_size ? buff_size : ONE_MEGABYTE); 615 pl_info->buf = NULL; 616 pl_info->log_state = 0; 617 pl_info->init_saved_state = 0; 618 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 619 pl_info->sack_thr = PKTLOG_DEFAULT_SACK_THR; 620 pl_info->tail_length = PKTLOG_DEFAULT_TAIL_LENGTH; 621 pl_info->thruput_thresh = PKTLOG_DEFAULT_THRUPUT_THRESH; 622 pl_info->per_thresh = PKTLOG_DEFAULT_PER_THRESH; 623 pl_info->phyerr_thresh = PKTLOG_DEFAULT_PHYERR_THRESH; 624 pl_info->trigger_interval = PKTLOG_DEFAULT_TRIGGER_INTERVAL; 625 pl_info->pktlen = 0; 626 pl_info->start_time_thruput = 0; 627 pl_info->start_time_per = 0; 628 pl_dev->vendor_cmd_send = false; 629 630 pktlog_callback_registration(pl_dev->callback_type); 631 } 632 633 int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, 634 bool ini_triggered, uint8_t user_triggered, 635 uint32_t is_iwpriv_command) 636 { 637 struct pktlog_dev_t *pl_dev; 638 struct ath_pktlog_info *pl_info; 639 uint8_t pdev_id; 640 int error; 641 642 if (!scn) { 643 qdf_print("Invalid scn context"); 644 ASSERT(0); 645 return -EINVAL; 646 } 647 648 pl_dev = get_pktlog_handle(); 649 if (!pl_dev) { 650 qdf_print("Invalid pktlog context"); 651 ASSERT(0); 652 return -EINVAL; 653 } 654 655 pdev_id = WMI_PDEV_ID_SOC; 656 if (pdev_id < 0) { 657 qdf_print("Invalid txrx context"); 658 ASSERT(0); 659 return -EINVAL; 660 } 661 662 pl_info = pl_dev->pl_info; 663 if (!pl_info) { 664 qdf_print("Invalid pl_info context"); 665 ASSERT(0); 666 return -EINVAL; 667 } 668 669 if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) 670 return -EBUSY; 671 672 pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; 673 /* is_iwpriv_command : 0 indicates its a vendor command 674 * log_state: 0 indicates pktlog disable command 675 * vendor_cmd_send flag; false means no vendor pktlog enable 676 * command was sent previously 677 */ 678 if (is_iwpriv_command == 0 && log_state == 0 && 679 pl_dev->vendor_cmd_send == false) { 680 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 681 qdf_print("pktlog operation not in progress"); 682 return 0; 683 } 684 685 if (!pl_dev->tgt_pktlog_alloced) { 686 if (!pl_info->buf) { 687 error = pktlog_alloc_buf(scn); 688 689 if (error != 0) { 690 pl_info->curr_pkt_state = 691 PKTLOG_OPR_NOT_IN_PROGRESS; 692 qdf_print("pktlog buff alloc failed"); 693 return -ENOMEM; 694 } 695 696 if (!pl_info->buf) { 697 pl_info->curr_pkt_state = 698 PKTLOG_OPR_NOT_IN_PROGRESS; 699 qdf_print("pktlog buf alloc failed"); 700 ASSERT(0); 701 return -ENOMEM; 702 } 703 704 } 705 706 qdf_spin_lock_bh(&pl_info->log_lock); 707 pl_info->buf->bufhdr.version = CUR_PKTLOG_VER; 708 pl_info->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM; 709 pl_info->buf->wr_offset = 0; 710 pl_info->buf->rd_offset = -1; 711 /* These below variables are used by per packet stats*/ 712 pl_info->buf->bytes_written = 0; 713 pl_info->buf->msg_index = 1; 714 pl_info->buf->offset = PKTLOG_READ_OFFSET; 715 qdf_spin_unlock_bh(&pl_info->log_lock); 716 717 pl_info->start_time_thruput = os_get_timestamp(); 718 pl_info->start_time_per = pl_info->start_time_thruput; 719 720 pl_dev->tgt_pktlog_alloced = true; 721 } 722 if (log_state != 0) { 723 /* WDI subscribe */ 724 if (!pl_dev->is_pktlog_cb_subscribed) { 725 error = wdi_pktlog_subscribe(pdev_id, log_state); 726 if (error) { 727 pl_info->curr_pkt_state = 728 PKTLOG_OPR_NOT_IN_PROGRESS; 729 qdf_print("Unable to subscribe to the WDI"); 730 return -EINVAL; 731 } 732 } else { 733 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 734 qdf_print("Unable to subscribe %d to the WDI", 735 log_state); 736 return -EINVAL; 737 } 738 /* WMI command to enable pktlog on the firmware */ 739 if (pktlog_enable_tgt(scn, log_state, ini_triggered, 740 user_triggered)) { 741 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 742 qdf_print("Device cannot be enabled"); 743 return -EINVAL; 744 } 745 pl_dev->is_pktlog_cb_subscribed = true; 746 747 if (is_iwpriv_command == 0) 748 pl_dev->vendor_cmd_send = true; 749 } else { 750 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 751 pl_dev->pl_funcs->pktlog_disable(scn); 752 if (is_iwpriv_command == 0) 753 pl_dev->vendor_cmd_send = false; 754 } 755 756 pl_info->log_state = log_state; 757 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 758 return 0; 759 } 760 761 int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, 762 bool ini_triggered, uint8_t user_triggered, 763 uint32_t is_iwpriv_command) 764 { 765 struct pktlog_dev_t *pl_dev; 766 struct ath_pktlog_info *pl_info; 767 int err; 768 769 pl_dev = get_pktlog_handle(); 770 771 if (!pl_dev) { 772 qdf_print("Invalid pl_dev handle"); 773 return -EINVAL; 774 } 775 776 pl_info = pl_dev->pl_info; 777 778 if (!pl_info) { 779 qdf_print("Invalid pl_info handle"); 780 return -EINVAL; 781 } 782 783 mutex_lock(&pl_info->pktlog_mutex); 784 err = __pktlog_enable(scn, log_state, ini_triggered, 785 user_triggered, is_iwpriv_command); 786 mutex_unlock(&pl_info->pktlog_mutex); 787 return err; 788 } 789 790 static int __pktlog_setsize(struct hif_opaque_softc *scn, int32_t size) 791 { 792 struct pktlog_dev_t *pl_dev; 793 struct ath_pktlog_info *pl_info; 794 uint8_t pdev_id = WMI_PDEV_ID_SOC; 795 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 796 uint32_t buff_size; 797 uint32_t max_allowed_buff_size; 798 799 pl_dev = get_pktlog_handle(); 800 801 if (!pl_dev) { 802 qdf_print("Invalid pl_dev handle"); 803 return -EINVAL; 804 } 805 806 pl_info = pl_dev->pl_info; 807 808 if (!pl_info) { 809 qdf_print("Invalid pl_dev handle"); 810 return -EINVAL; 811 } 812 813 if (pdev_id < 0) { 814 qdf_print("Invalid pdev"); 815 return -EINVAL; 816 } 817 818 if (pl_info->curr_pkt_state < PKTLOG_OPR_NOT_IN_PROGRESS) { 819 qdf_print("pktlog is not configured"); 820 return -EBUSY; 821 } 822 823 pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; 824 825 buff_size = cdp_cfg_get(soc, cfg_dp_pktlog_buffer_size) * ONE_MEGABYTE; 826 max_allowed_buff_size = (buff_size ? buff_size : ONE_MEGABYTE); 827 828 if (size < ONE_MEGABYTE || size > max_allowed_buff_size) { 829 qdf_print("Cannot Set Pktlog Buffer size of %d bytes.Min required is %d MB and Max allowed is %d MB", 830 size, (ONE_MEGABYTE / ONE_MEGABYTE), 831 (max_allowed_buff_size / ONE_MEGABYTE)); 832 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 833 qdf_print("Invalid requested buff size"); 834 return -EINVAL; 835 } 836 837 if (size == pl_info->buf_size) { 838 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 839 qdf_print("Pktlog Buff Size is already of same size"); 840 return 0; 841 } 842 843 if (pl_info->log_state) { 844 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 845 qdf_print("Logging should be disabled before changing buffer size"); 846 return -EINVAL; 847 } 848 849 qdf_spin_lock_bh(&pl_info->log_lock); 850 if (pl_info->buf) { 851 if (pl_dev->is_pktlog_cb_subscribed && 852 wdi_pktlog_unsubscribe(pdev_id, pl_info->log_state)) { 853 pl_info->curr_pkt_state = 854 PKTLOG_OPR_NOT_IN_PROGRESS; 855 qdf_spin_unlock_bh(&pl_info->log_lock); 856 qdf_print("Cannot unsubscribe pktlog from the WDI"); 857 return -EFAULT; 858 } 859 pktlog_release_buf(scn); 860 pl_dev->is_pktlog_cb_subscribed = false; 861 pl_dev->tgt_pktlog_alloced = false; 862 } 863 864 if (size != 0) { 865 qdf_print("New Pktlog Buff Size is %d", size); 866 pl_info->buf_size = size; 867 } 868 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 869 qdf_spin_unlock_bh(&pl_info->log_lock); 870 return 0; 871 } 872 873 int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size) 874 { 875 struct pktlog_dev_t *pl_dev; 876 struct ath_pktlog_info *pl_info; 877 int status; 878 879 pl_dev = get_pktlog_handle(); 880 881 if (!pl_dev) { 882 qdf_print("Invalid pl_dev handle"); 883 return -EINVAL; 884 } 885 886 pl_info = pl_dev->pl_info; 887 888 if (!pl_info) { 889 qdf_print("Invalid pl_dev handle"); 890 return -EINVAL; 891 } 892 893 mutex_lock(&pl_info->pktlog_mutex); 894 status = __pktlog_setsize(scn, size); 895 mutex_unlock(&pl_info->pktlog_mutex); 896 897 return status; 898 } 899 900 int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff) 901 { 902 struct pktlog_dev_t *pl_dev; 903 struct ath_pktlog_info *pl_info; 904 uint8_t save_pktlog_state; 905 906 pl_dev = get_pktlog_handle(); 907 908 if (!pl_dev) { 909 qdf_print("Invalid pl_dev handle"); 910 return -EINVAL; 911 } 912 913 pl_info = pl_dev->pl_info; 914 915 if (!pl_info) { 916 qdf_print("Invalid pl_dev handle"); 917 return -EINVAL; 918 } 919 920 if (!clear_buff) 921 return -EINVAL; 922 923 if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE || 924 pl_info->curr_pkt_state == 925 PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) 926 return -EBUSY; 927 928 save_pktlog_state = pl_info->curr_pkt_state; 929 pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; 930 931 if (pl_info->log_state) { 932 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 933 qdf_print("Logging should be disabled before clearing pktlog buffer"); 934 return -EINVAL; 935 } 936 937 if (pl_info->buf) { 938 if (pl_info->buf_size > 0) { 939 qdf_debug("pktlog buffer is cleared"); 940 memset(pl_info->buf, 0, pl_info->buf_size); 941 pl_dev->is_pktlog_cb_subscribed = false; 942 pl_dev->tgt_pktlog_alloced = false; 943 pl_info->buf->rd_offset = -1; 944 } else { 945 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 946 qdf_print("pktlog buffer size is not proper. " 947 "Existing Buf size %d", 948 pl_info->buf_size); 949 return -EFAULT; 950 } 951 } else { 952 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 953 qdf_print("pktlog buff is NULL"); 954 return -EFAULT; 955 } 956 957 if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE) 958 pl_info->curr_pkt_state = 959 PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE; 960 else 961 pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; 962 963 return 0; 964 } 965 966 void pktlog_process_fw_msg(uint8_t pdev_id, uint32_t *buff, uint32_t len) 967 { 968 uint32_t *pl_hdr; 969 uint32_t log_type; 970 struct ol_fw_data pl_fw_data; 971 972 if (pdev_id == OL_TXRX_INVALID_PDEV_ID) { 973 qdf_print("txrx pdev_id is invalid"); 974 return; 975 } 976 pl_hdr = buff; 977 pl_fw_data.data = pl_hdr; 978 pl_fw_data.len = len; 979 980 log_type = 981 (*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> 982 ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; 983 984 if ((log_type == PKTLOG_TYPE_TX_CTRL) 985 || (log_type == PKTLOG_TYPE_TX_STAT) 986 || (log_type == PKTLOG_TYPE_TX_MSDU_ID) 987 || (log_type == PKTLOG_TYPE_TX_FRM_HDR) 988 || (log_type == PKTLOG_TYPE_TX_VIRT_ADDR)) 989 wdi_event_handler(WDI_EVENT_TX_STATUS, 990 pdev_id, &pl_fw_data); 991 else if (log_type == PKTLOG_TYPE_RC_FIND) 992 wdi_event_handler(WDI_EVENT_RATE_FIND, 993 pdev_id, &pl_fw_data); 994 else if (log_type == PKTLOG_TYPE_RC_UPDATE) 995 wdi_event_handler(WDI_EVENT_RATE_UPDATE, 996 pdev_id, &pl_fw_data); 997 else if (log_type == PKTLOG_TYPE_RX_STAT) 998 wdi_event_handler(WDI_EVENT_RX_DESC, 999 pdev_id, &pl_fw_data); 1000 else if (log_type == PKTLOG_TYPE_SW_EVENT) 1001 wdi_event_handler(WDI_EVENT_SW_EVENT, 1002 pdev_id, &pl_fw_data); 1003 } 1004 1005 #if defined(QCA_WIFI_3_0_ADRASTEA) 1006 static inline int pktlog_nbuf_check_sanity(qdf_nbuf_t nbuf) 1007 { 1008 int rc = 0; /* sane */ 1009 1010 if ((!nbuf) || 1011 (nbuf->data < nbuf->head) || 1012 ((nbuf->data + skb_headlen(nbuf)) > skb_end_pointer(nbuf))) 1013 rc = -EINVAL; 1014 1015 return rc; 1016 } 1017 /** 1018 * pktlog_t2h_msg_handler() - Target to host message handler 1019 * @context: pdev context 1020 * @pkt: HTC packet 1021 * 1022 * Return: None 1023 */ 1024 static void pktlog_t2h_msg_handler(void *context, HTC_PACKET *pkt) 1025 { 1026 struct pktlog_dev_t *pdev = (struct pktlog_dev_t *)context; 1027 qdf_nbuf_t pktlog_t2h_msg = (qdf_nbuf_t) pkt->pPktContext; 1028 uint32_t *msg_word; 1029 uint32_t msg_len; 1030 1031 /* check for sanity of the packet, have seen corrupted pkts */ 1032 if (pktlog_nbuf_check_sanity(pktlog_t2h_msg)) { 1033 qdf_print("packet 0x%pK corrupted? Leaking...", 1034 pktlog_t2h_msg); 1035 /* do not free; may crash! */ 1036 QDF_ASSERT(0); 1037 return; 1038 } 1039 1040 /* check for successful message reception */ 1041 if (pkt->Status != QDF_STATUS_SUCCESS) { 1042 if (pkt->Status != QDF_STATUS_E_CANCELED) 1043 pdev->htc_err_cnt++; 1044 qdf_nbuf_free(pktlog_t2h_msg); 1045 return; 1046 } 1047 1048 /* confirm alignment */ 1049 qdf_assert((((unsigned long)qdf_nbuf_data(pktlog_t2h_msg)) & 0x3) == 0); 1050 1051 msg_word = (uint32_t *) qdf_nbuf_data(pktlog_t2h_msg); 1052 msg_len = qdf_nbuf_len(pktlog_t2h_msg); 1053 pktlog_process_fw_msg(pdev->pdev_id, msg_word, msg_len); 1054 1055 qdf_nbuf_free(pktlog_t2h_msg); 1056 } 1057 1058 /** 1059 * pktlog_tx_resume_handler() - resume callback 1060 * @context: pdev context 1061 * 1062 * Return: None 1063 */ 1064 static void pktlog_tx_resume_handler(void *context) 1065 { 1066 qdf_print("Not expected"); 1067 qdf_assert(0); 1068 } 1069 1070 /** 1071 * pktlog_h2t_send_complete() - send complete indication 1072 * @context: pdev context 1073 * @htc_pkt: HTC packet 1074 * 1075 * Return: None 1076 */ 1077 static void pktlog_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) 1078 { 1079 qdf_print("Not expected"); 1080 qdf_assert(0); 1081 } 1082 1083 /** 1084 * pktlog_h2t_full() - queue full indication 1085 * @context: pdev context 1086 * @pkt: HTC packet 1087 * 1088 * Return: HTC action 1089 */ 1090 static enum htc_send_full_action pktlog_h2t_full(void *context, HTC_PACKET *pkt) 1091 { 1092 return HTC_SEND_FULL_KEEP; 1093 } 1094 1095 /** 1096 * pktlog_htc_connect_service() - create new endpoint for packetlog 1097 * @pdev - pktlog pdev 1098 * 1099 * Return: 0 for success/failure 1100 */ 1101 static int pktlog_htc_connect_service(struct pktlog_dev_t *pdev) 1102 { 1103 struct htc_service_connect_req connect; 1104 struct htc_service_connect_resp response; 1105 QDF_STATUS status; 1106 1107 qdf_mem_zero(&connect, sizeof(connect)); 1108 qdf_mem_zero(&response, sizeof(response)); 1109 1110 connect.pMetaData = NULL; 1111 connect.MetaDataLength = 0; 1112 connect.EpCallbacks.pContext = pdev; 1113 connect.EpCallbacks.EpTxComplete = pktlog_h2t_send_complete; 1114 connect.EpCallbacks.EpTxCompleteMultiple = NULL; 1115 connect.EpCallbacks.EpRecv = pktlog_t2h_msg_handler; 1116 connect.EpCallbacks.ep_resume_tx_queue = pktlog_tx_resume_handler; 1117 1118 /* rx buffers currently are provided by HIF, not by EpRecvRefill */ 1119 connect.EpCallbacks.EpRecvRefill = NULL; 1120 connect.EpCallbacks.RecvRefillWaterMark = 1; 1121 /* N/A, fill is done by HIF */ 1122 1123 connect.EpCallbacks.EpSendFull = pktlog_h2t_full; 1124 /* 1125 * Specify how deep to let a queue get before htc_send_pkt will 1126 * call the EpSendFull function due to excessive send queue depth. 1127 */ 1128 connect.MaxSendQueueDepth = PKTLOG_MAX_SEND_QUEUE_DEPTH; 1129 1130 /* disable flow control for HTT data message service */ 1131 connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; 1132 1133 /* connect to control service */ 1134 connect.service_id = PACKET_LOG_SVC; 1135 1136 status = htc_connect_service(pdev->htc_pdev, &connect, &response); 1137 1138 if (status != QDF_STATUS_SUCCESS) { 1139 pdev->mt_pktlog_enabled = false; 1140 return -EIO; /* failure */ 1141 } 1142 1143 pdev->htc_endpoint = response.Endpoint; 1144 pdev->mt_pktlog_enabled = true; 1145 1146 return 0; /* success */ 1147 } 1148 1149 /** 1150 * pktlog_htc_attach() - attach pktlog HTC service 1151 * 1152 * Return: 0 for success/failure 1153 */ 1154 int pktlog_htc_attach(void) 1155 { 1156 struct pktlog_dev_t *pl_pdev = get_pktlog_handle(); 1157 void *htc_pdev = cds_get_context(QDF_MODULE_ID_HTC); 1158 1159 if ((!pl_pdev) || (!htc_pdev)) { 1160 qdf_print("Invalid pl_dev or htc_pdev handle"); 1161 return -EINVAL; 1162 } 1163 1164 pl_pdev->htc_pdev = htc_pdev; 1165 return pktlog_htc_connect_service(pl_pdev); 1166 } 1167 #else 1168 int pktlog_htc_attach(void) 1169 { 1170 struct pktlog_dev_t *pl_dev = get_pktlog_handle(); 1171 1172 if (!pl_dev) { 1173 qdf_print("Invalid pl_dev handle"); 1174 return -EINVAL; 1175 } 1176 1177 pl_dev->mt_pktlog_enabled = false; 1178 return 0; 1179 } 1180 #endif 1181 #endif /* REMOVE_PKT_LOG */ 1182