1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 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 #include "htc_debug.h" 21 #include "htc_internal.h" 22 #include "htc_credit_history.h" 23 #include "htc_hang_event.h" 24 #include <hif.h> 25 #include <qdf_nbuf.h> /* qdf_nbuf_t */ 26 #include <qdf_types.h> /* qdf_print */ 27 28 #define MAX_HTC_RX_BUNDLE 2 29 30 #if defined(WLAN_DEBUG) || defined(DEBUG) 31 static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = { 32 {ATH_DEBUG_SEND, "Send"}, 33 {ATH_DEBUG_RECV, "Recv"}, 34 {ATH_DEBUG_SYNC, "Sync"}, 35 {ATH_DEBUG_DUMP, "Dump Data (RX or TX)"}, 36 {ATH_DEBUG_SETUP, "Setup"}, 37 }; 38 39 ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc, 40 "htc", 41 "Host Target Communications", 42 ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | 43 ATH_DEBUG_SETUP, 44 ATH_DEBUG_DESCRIPTION_COUNT 45 (g_htc_debug_description), 46 g_htc_debug_description); 47 48 #endif 49 50 #if defined(WMI_MULTI_MAC_SVC) 51 static const uint32_t svc_id[] = {WMI_CONTROL_SVC, WMI_CONTROL_SVC_WMAC1, 52 WMI_CONTROL_SVC_WMAC2}; 53 #else 54 static const uint32_t svc_id[] = {WMI_CONTROL_SVC}; 55 #endif 56 57 extern unsigned int htc_credit_flow; 58 59 static void reset_endpoint_states(HTC_TARGET *target); 60 61 static void destroy_htc_tx_ctrl_packet(HTC_PACKET *pPacket) 62 { 63 qdf_nbuf_t netbuf; 64 65 netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 66 if (netbuf) 67 qdf_nbuf_free(netbuf); 68 qdf_mem_free(pPacket); 69 } 70 71 static HTC_PACKET *build_htc_tx_ctrl_packet(qdf_device_t osdev) 72 { 73 HTC_PACKET *pPacket = NULL; 74 qdf_nbuf_t netbuf; 75 76 do { 77 pPacket = (HTC_PACKET *) qdf_mem_malloc(sizeof(HTC_PACKET)); 78 if (!pPacket) 79 break; 80 netbuf = qdf_nbuf_alloc(osdev, HTC_CONTROL_BUFFER_SIZE, 81 20, 4, true); 82 if (!netbuf) { 83 qdf_mem_free(pPacket); 84 pPacket = NULL; 85 break; 86 } 87 SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); 88 } while (false); 89 90 return pPacket; 91 } 92 93 void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) 94 { 95 96 #ifdef TODO_FIXME 97 LOCK_HTC(target); 98 HTC_PACKET_ENQUEUE(&target->ControlBufferTXFreeList, pPacket); 99 UNLOCK_HTC(target); 100 /* TODO_FIXME netbufs cannot be RESET! */ 101 #else 102 destroy_htc_tx_ctrl_packet(pPacket); 103 #endif 104 105 } 106 107 HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target) 108 { 109 #ifdef TODO_FIXME 110 HTC_PACKET *pPacket; 111 112 LOCK_HTC(target); 113 pPacket = htc_packet_dequeue(&target->ControlBufferTXFreeList); 114 UNLOCK_HTC(target); 115 116 return pPacket; 117 #else 118 return build_htc_tx_ctrl_packet(target->osdev); 119 #endif 120 } 121 122 /* Set the target failure handling callback */ 123 void htc_set_target_failure_callback(HTC_HANDLE HTCHandle, 124 HTC_TARGET_FAILURE Callback) 125 { 126 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 127 128 target->HTCInitInfo.TargetFailure = Callback; 129 } 130 131 void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start) 132 { 133 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 134 135 hif_dump(target->hif_dev, CmdId, start); 136 } 137 138 void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle) 139 { 140 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 141 142 if (!target->hif_dev) 143 return; 144 145 hif_display_stats(target->hif_dev); 146 } 147 148 #ifdef FEATURE_RUNTIME_PM 149 /** 150 * htc_dec_return_wmi_runtime_cnt: Decrement htc wmi runtime count 151 * @target: HTC target 152 * 153 * Return: value of runtime count after decrement 154 */ 155 static inline 156 int32_t htc_dec_return_wmi_runtime_cnt(HTC_TARGET *target) 157 { 158 return qdf_atomic_dec_return(&target->htc_wmi_runtime_cnt); 159 } 160 161 /** 162 * htc_init_wmi_runtime_cnt: Initialize htc wmi runtime count 163 * @target: HTC target 164 * 165 * Return: None 166 */ 167 static inline 168 void htc_init_wmi_runtime_cnt(HTC_TARGET *target) 169 { 170 qdf_atomic_init(&target->htc_wmi_runtime_cnt); 171 } 172 #else 173 static inline 174 int32_t htc_dec_return_wmi_runtime_cnt(HTC_TARGET *target) 175 { 176 return -1; 177 } 178 179 static inline 180 void htc_init_wmi_runtime_cnt(HTC_TARGET *target) 181 { 182 } 183 #endif 184 /* cleanup the HTC instance */ 185 static void htc_cleanup(HTC_TARGET *target) 186 { 187 HTC_PACKET *pPacket; 188 int i; 189 HTC_ENDPOINT *endpoint; 190 HTC_PACKET_QUEUE *pkt_queue; 191 qdf_nbuf_t netbuf; 192 193 while (htc_dec_return_htt_runtime_cnt((void *)target) >= 0) 194 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT); 195 196 while (htc_dec_return_wmi_runtime_cnt((void *)target) >= 0) 197 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_WMI); 198 199 if (target->hif_dev) { 200 hif_detach_htc(target->hif_dev); 201 hif_mask_interrupt_call(target->hif_dev); 202 target->hif_dev = NULL; 203 } 204 205 while (true) { 206 pPacket = allocate_htc_packet_container(target); 207 if (!pPacket) 208 break; 209 qdf_mem_free(pPacket); 210 } 211 212 LOCK_HTC_TX(target); 213 pPacket = target->pBundleFreeList; 214 target->pBundleFreeList = NULL; 215 UNLOCK_HTC_TX(target); 216 while (pPacket) { 217 HTC_PACKET *pPacketTmp = (HTC_PACKET *) pPacket->ListLink.pNext; 218 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 219 if (netbuf) 220 qdf_nbuf_free(netbuf); 221 pkt_queue = pPacket->pContext; 222 if (pkt_queue) 223 qdf_mem_free(pkt_queue); 224 qdf_mem_free(pPacket); 225 pPacket = pPacketTmp; 226 } 227 228 #ifdef TODO_FIXME 229 while (true) { 230 pPacket = htc_alloc_control_tx_packet(target); 231 if (!pPacket) 232 break; 233 netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 234 if (netbuf) 235 qdf_nbuf_free(netbuf); 236 qdf_mem_free(pPacket); 237 } 238 #endif 239 HTC_INFO("%s: Non flow ctrl enabled endpoints nbuf map: %d, unamp: %d", 240 __func__, target->nbuf_nfc_map_count, 241 target->nbuf_nfc_unmap_count); 242 243 htc_flush_endpoint_txlookupQ(target, ENDPOINT_0, true); 244 245 qdf_spinlock_destroy(&target->HTCLock); 246 qdf_spinlock_destroy(&target->HTCRxLock); 247 qdf_spinlock_destroy(&target->HTCTxLock); 248 for (i = 0; i < ENDPOINT_MAX; i++) { 249 endpoint = &target->endpoint[i]; 250 qdf_spinlock_destroy(&endpoint->lookup_queue_lock); 251 } 252 253 /* free our instance */ 254 qdf_mem_free(target); 255 } 256 257 #ifdef FEATURE_RUNTIME_PM 258 /** 259 * htc_runtime_pm_init(): runtime pm related initialization 260 * 261 * need to initialize a work item. 262 */ 263 static void htc_runtime_pm_init(HTC_TARGET *target) 264 { 265 qdf_create_work(0, &target->queue_kicker, htc_kick_queues, target); 266 } 267 268 /** 269 * htc_runtime_suspend() - runtime suspend HTC 270 * 271 * @htc_ctx: HTC context pointer 272 * 273 * This is a dummy function for symmetry. 274 * 275 * Return: 0 for success 276 */ 277 int htc_runtime_suspend(HTC_HANDLE htc_ctx) 278 { 279 return 0; 280 } 281 282 /** 283 * htc_runtime_resume(): resume htc 284 * 285 * The htc message queue needs to be kicked off after 286 * a runtime resume. Otherwise messages would get stuck. 287 * 288 * @htc_ctx: HTC context pointer 289 * 290 * Return: 0 for success; 291 */ 292 int htc_runtime_resume(HTC_HANDLE htc_ctx) 293 { 294 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_ctx); 295 296 if (!target) 297 return 0; 298 299 qdf_sched_work(0, &target->queue_kicker); 300 return 0; 301 } 302 303 /** 304 * htc_runtime_pm_deinit(): runtime pm related de-intialization 305 * 306 * need to de-initialize the work item. 307 * 308 * @target: HTC target pointer 309 * 310 */ 311 static void htc_runtime_pm_deinit(HTC_TARGET *target) 312 { 313 if (!target) 314 return; 315 316 qdf_destroy_work(0, &target->queue_kicker); 317 } 318 319 int32_t htc_dec_return_htt_runtime_cnt(HTC_HANDLE htc) 320 { 321 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc); 322 323 return qdf_atomic_dec_return(&target->htc_htt_runtime_cnt); 324 } 325 326 /** 327 * htc_init_htt_runtime_cnt: Initialize htc htt runtime count 328 * @target: HTC target 329 * 330 * Return: None 331 */ 332 static inline 333 void htc_init_htt_runtime_cnt(HTC_TARGET *target) 334 { 335 qdf_atomic_init(&target->htc_htt_runtime_cnt); 336 } 337 #else 338 static inline void htc_runtime_pm_init(HTC_TARGET *target) { } 339 static inline void htc_runtime_pm_deinit(HTC_TARGET *target) { } 340 341 static inline 342 void htc_init_htt_runtime_cnt(HTC_TARGET *target) 343 { 344 } 345 #endif 346 347 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) 348 static 349 void htc_update_rx_bundle_stats(void *ctx, uint8_t no_of_pkt_in_bundle) 350 { 351 HTC_TARGET *target = (HTC_TARGET *)ctx; 352 353 no_of_pkt_in_bundle--; 354 if (target && (no_of_pkt_in_bundle < HTC_MAX_MSG_PER_BUNDLE_RX)) 355 target->rx_bundle_stats[no_of_pkt_in_bundle]++; 356 } 357 #else 358 static 359 void htc_update_rx_bundle_stats(void *ctx, uint8_t no_of_pkt_in_bundle) 360 { 361 } 362 #endif 363 364 #ifdef WLAN_DEBUG_LINK_VOTE 365 static qdf_atomic_t htc_link_vote_ids[HTC_LINK_VOTE_INVALID_MAX_USER_ID]; 366 367 static void htc_init_link_vote_ids(void) 368 { 369 uint32_t i; 370 371 for (i = HTC_LINK_VOTE_INVALID_MIN_USER_ID; 372 i < HTC_LINK_VOTE_INVALID_MAX_USER_ID; i++) 373 qdf_atomic_init(&htc_link_vote_ids[i]); 374 } 375 376 void htc_log_link_user_votes(void) 377 { 378 uint32_t i; 379 uint32_t link_vote; 380 381 for (i = HTC_LINK_VOTE_INVALID_MIN_USER_ID + 1; 382 i < HTC_LINK_VOTE_INVALID_MAX_USER_ID; i++) { 383 link_vote = qdf_atomic_read(&htc_link_vote_ids[i]); 384 if (link_vote) 385 HTC_NOFL_INFO("Link vote %d user id: %d", 386 link_vote, i); 387 } 388 } 389 390 void htc_vote_link_down(HTC_HANDLE htc_handle, enum htc_link_vote_user_id id) 391 { 392 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 393 394 if (!target->hif_dev) 395 return; 396 if (id >= HTC_LINK_VOTE_INVALID_MAX_USER_ID || 397 id <= HTC_LINK_VOTE_INVALID_MIN_USER_ID) { 398 HTC_ERROR("invalid id: %d", id); 399 return; 400 } 401 402 hif_vote_link_down(target->hif_dev); 403 qdf_atomic_dec(&htc_link_vote_ids[id]); 404 } 405 406 void htc_vote_link_up(HTC_HANDLE htc_handle, enum htc_link_vote_user_id id) 407 { 408 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 409 410 if (!target->hif_dev) 411 return; 412 if (id >= HTC_LINK_VOTE_INVALID_MAX_USER_ID || 413 id <= HTC_LINK_VOTE_INVALID_MIN_USER_ID) { 414 HTC_ERROR("invalid link vote user id: %d", id); 415 return; 416 } 417 418 hif_vote_link_up(target->hif_dev); 419 qdf_atomic_inc(&htc_link_vote_ids[id]); 420 } 421 #else 422 static inline 423 void htc_init_link_vote_ids(void) 424 { 425 } 426 #endif 427 428 /* registered target arrival callback from the HIF layer */ 429 HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo, 430 qdf_device_t osdev, uint32_t con_mode) 431 { 432 struct hif_msg_callbacks htcCallbacks; 433 HTC_ENDPOINT *pEndpoint = NULL; 434 HTC_TARGET *target = NULL; 435 int i; 436 437 if (!ol_sc) { 438 HTC_ERROR("%s: ol_sc = NULL", __func__); 439 return NULL; 440 } 441 HTC_TRACE("+htc_create .. HIF :%pK", ol_sc); 442 443 A_REGISTER_MODULE_DEBUG_INFO(htc); 444 445 target = (HTC_TARGET *) qdf_mem_malloc(sizeof(HTC_TARGET)); 446 if (!target) 447 return NULL; 448 449 htc_runtime_pm_init(target); 450 htc_credit_history_init(); 451 qdf_spinlock_create(&target->HTCLock); 452 qdf_spinlock_create(&target->HTCRxLock); 453 qdf_spinlock_create(&target->HTCTxLock); 454 for (i = 0; i < ENDPOINT_MAX; i++) { 455 pEndpoint = &target->endpoint[i]; 456 qdf_spinlock_create(&pEndpoint->lookup_queue_lock); 457 } 458 target->is_nodrop_pkt = false; 459 target->htc_hdr_length_check = false; 460 target->wmi_ep_count = 1; 461 462 do { 463 qdf_mem_copy(&target->HTCInitInfo, pInfo, 464 sizeof(struct htc_init_info)); 465 target->host_handle = pInfo->pContext; 466 target->osdev = osdev; 467 target->con_mode = con_mode; 468 469 /* If htc_ready_timeout_ms is not configured from CFG, 470 * assign the default timeout value here. 471 */ 472 473 if (!target->HTCInitInfo.htc_ready_timeout_ms) 474 target->HTCInitInfo.htc_ready_timeout_ms = 475 HTC_CONTROL_RX_TIMEOUT; 476 477 reset_endpoint_states(target); 478 479 INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); 480 481 for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { 482 HTC_PACKET *pPacket = (HTC_PACKET *) 483 qdf_mem_malloc(sizeof(HTC_PACKET)); 484 if (pPacket) 485 free_htc_packet_container(target, pPacket); 486 } 487 488 #ifdef TODO_FIXME 489 for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) { 490 pPacket = build_htc_tx_ctrl_packet(); 491 if (!pPacket) 492 break; 493 htc_free_control_tx_packet(target, pPacket); 494 } 495 #endif 496 497 /* setup HIF layer callbacks */ 498 qdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks)); 499 htcCallbacks.Context = target; 500 htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; 501 htcCallbacks.txCompletionHandler = htc_tx_completion_handler; 502 htcCallbacks.txResourceAvailHandler = 503 htc_tx_resource_avail_handler; 504 htcCallbacks.fwEventHandler = htc_fw_event_handler; 505 htcCallbacks.update_bundle_stats = htc_update_rx_bundle_stats; 506 target->hif_dev = ol_sc; 507 508 /* Get HIF default pipe for HTC message exchange */ 509 pEndpoint = &target->endpoint[ENDPOINT_0]; 510 511 hif_post_init(target->hif_dev, target, &htcCallbacks); 512 hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID, 513 &pEndpoint->DL_PipeID); 514 hif_set_initial_wakeup_cb(target->hif_dev, 515 pInfo->target_initial_wakeup_cb, 516 pInfo->target_psoc); 517 518 } while (false); 519 520 htc_recv_init(target); 521 htc_init_htt_runtime_cnt(target); 522 htc_init_wmi_runtime_cnt(target); 523 524 HTC_TRACE("-htc_create: (0x%pK)", target); 525 526 htc_hang_event_notifier_register(target); 527 528 htc_init_link_vote_ids(); 529 530 hif_rtpm_register(HIF_RTPM_ID_WMI, NULL); 531 hif_rtpm_register(HIF_RTPM_ID_HTT, NULL); 532 533 return (HTC_HANDLE) target; 534 } 535 536 void htc_destroy(HTC_HANDLE HTCHandle) 537 { 538 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 539 540 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 541 ("+htc_destroy .. Destroying :0x%pK\n", target)); 542 543 htc_hang_event_notifier_unregister(); 544 545 if (target) { 546 hif_stop(htc_get_hif_device(HTCHandle)); 547 htc_cleanup(target); 548 hif_rtpm_deregister(HIF_RTPM_ID_HTT); 549 hif_rtpm_deregister(HIF_RTPM_ID_WMI); 550 } 551 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n")); 552 htc_credit_history_deinit(); 553 } 554 555 /* get the low level HIF device for the caller , the caller may wish to do low 556 * level HIF requests 557 */ 558 void *htc_get_hif_device(HTC_HANDLE HTCHandle) 559 { 560 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 561 562 return target->hif_dev; 563 } 564 565 static void htc_control_tx_complete(void *Context, HTC_PACKET *pPacket) 566 { 567 HTC_TARGET *target = (HTC_TARGET *) Context; 568 569 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 570 ("+-htc_control_tx_complete 0x%pK (l:%d)\n", pPacket, 571 pPacket->ActualLength)); 572 htc_free_control_tx_packet(target, pPacket); 573 } 574 575 /* TODO, this is just a temporary max packet size */ 576 #define MAX_MESSAGE_SIZE 1536 577 578 /** 579 * htc_setup_epping_credit_allocation() - allocate credits/HTC buffers to WMI 580 * @scn: pointer to hif_opaque_softc 581 * @pEntry: pointer to tx credit allocation entry 582 * @credits: number of credits 583 * 584 * Return: None 585 */ 586 static void 587 htc_setup_epping_credit_allocation(struct hif_opaque_softc *scn, 588 struct htc_service_tx_credit_allocation *pEntry, 589 int credits) 590 { 591 switch (hif_get_bus_type(scn)) { 592 case QDF_BUS_TYPE_PCI: 593 case QDF_BUS_TYPE_USB: 594 pEntry++; 595 pEntry->service_id = WMI_DATA_BE_SVC; 596 pEntry->CreditAllocation = (credits >> 1); 597 598 pEntry++; 599 pEntry->service_id = WMI_DATA_BK_SVC; 600 pEntry->CreditAllocation = (credits >> 1); 601 break; 602 case QDF_BUS_TYPE_SDIO: 603 pEntry++; 604 pEntry->service_id = WMI_DATA_BE_SVC; 605 pEntry->CreditAllocation = credits; 606 break; 607 default: 608 break; 609 } 610 } 611 612 /** 613 * htc_setup_target_buffer_assignments() - setup target buffer assignments 614 * @target: HTC Target Pointer 615 * 616 * Return: A_STATUS 617 */ 618 static 619 A_STATUS htc_setup_target_buffer_assignments(HTC_TARGET *target) 620 { 621 struct htc_service_tx_credit_allocation *pEntry; 622 A_STATUS status; 623 int credits; 624 int creditsPerMaxMsg; 625 626 creditsPerMaxMsg = MAX_MESSAGE_SIZE / target->TargetCreditSize; 627 if (MAX_MESSAGE_SIZE % target->TargetCreditSize) 628 creditsPerMaxMsg++; 629 630 /* TODO, this should be configured by the caller! */ 631 632 credits = target->TotalTransmitCredits; 633 pEntry = &target->ServiceTxAllocTable[0]; 634 635 status = A_OK; 636 /* 637 * Allocate all credits/HTC buffers to WMI. 638 * no buffers are used/required for data. data always 639 * remains on host. 640 */ 641 if (HTC_IS_EPPING_ENABLED(target->con_mode)) { 642 pEntry++; 643 pEntry->service_id = WMI_CONTROL_SVC; 644 pEntry->CreditAllocation = credits; 645 /* endpoint ping is a testing tool directly on top of HTC in 646 * both target and host sides. 647 * In target side, the endppint ping fw has no wlan stack and 648 * FW mboxping app directly sits on HTC and it simply drops 649 * or loops back TX packets. For rx perf, FW mboxping app 650 * generates packets and passes packets to HTC to send to host. 651 * There is no WMI message exchanges between host and target 652 * in endpoint ping case. 653 * In host side, the endpoint ping driver is a Ethernet driver 654 * and it directly sits on HTC. Only HIF, HTC, QDF, ADF are 655 * used by the endpoint ping driver. There is no wifi stack 656 * at all in host side also. For tx perf use case, 657 * the user space mboxping app sends the raw packets to endpoint 658 * ping driver and it directly forwards to HTC for transmission 659 * to stress the bus. For the rx perf, HTC passes the received 660 * packets to endpoint ping driver and it is passed to the user 661 * space through the Ethernet interface. 662 * For credit allocation, in SDIO bus case, only BE service is 663 * used for tx/rx perf testing so that all credits are given 664 * to BE service. In PCIe and USB bus case, endpoint ping uses 665 * both BE and BK services to stress the bus so that the total 666 * credits are equally distributed to BE and BK services. 667 */ 668 669 htc_setup_epping_credit_allocation(target->hif_dev, 670 pEntry, credits); 671 } else { 672 int i; 673 uint32_t max_wmi_svc = (sizeof(svc_id) / sizeof(uint32_t)); 674 675 if ((target->wmi_ep_count == 0) || 676 (target->wmi_ep_count > max_wmi_svc)) 677 return A_ERROR; 678 679 /* 680 * Divide credit among number of endpoints for WMI 681 */ 682 credits = credits / target->wmi_ep_count; 683 for (i = 0; i < target->wmi_ep_count; i++) { 684 status = A_OK; 685 pEntry++; 686 pEntry->service_id = svc_id[i]; 687 pEntry->CreditAllocation = credits; 688 } 689 } 690 691 if (A_SUCCESS(status)) { 692 int i; 693 694 for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { 695 if (target->ServiceTxAllocTable[i].service_id != 0) { 696 AR_DEBUG_PRINTF(ATH_DEBUG_INIT, 697 ("SVS Index : %d TX : 0x%2.2X : alloc:%d", 698 i, 699 target->ServiceTxAllocTable[i]. 700 service_id, 701 target->ServiceTxAllocTable[i]. 702 CreditAllocation)); 703 } 704 } 705 } 706 707 return status; 708 } 709 710 uint8_t htc_get_credit_allocation(HTC_TARGET *target, uint16_t service_id) 711 { 712 uint8_t allocation = 0; 713 int i; 714 715 for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { 716 if (target->ServiceTxAllocTable[i].service_id == service_id) { 717 allocation = 718 target->ServiceTxAllocTable[i].CreditAllocation; 719 } 720 } 721 722 if (0 == allocation) { 723 AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, 724 ("HTC Service TX : 0x%2.2X : allocation is zero!\n", 725 service_id)); 726 } 727 728 return allocation; 729 } 730 731 QDF_STATUS htc_wait_target(HTC_HANDLE HTCHandle) 732 { 733 QDF_STATUS status = QDF_STATUS_SUCCESS; 734 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 735 HTC_READY_EX_MSG *pReadyMsg; 736 struct htc_service_connect_req connect; 737 struct htc_service_connect_resp resp; 738 HTC_READY_MSG *rdy_msg; 739 uint16_t htc_rdy_msg_id; 740 uint8_t i = 0; 741 HTC_PACKET *rx_bundle_packet, *temp_bundle_packet; 742 743 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 744 ("htc_wait_target - Enter (target:0x%pK)\n", HTCHandle)); 745 AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, ("+HWT\n")); 746 747 do { 748 749 status = hif_start(target->hif_dev); 750 if (QDF_IS_STATUS_ERROR(status)) { 751 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, 752 ("hif_start failed\n")); 753 break; 754 } 755 756 status = htc_wait_recv_ctrl_message(target); 757 758 if (QDF_IS_STATUS_ERROR(status)) 759 break; 760 761 if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) { 762 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 763 ("Invalid HTC Ready Msg Len:%d!\n", 764 target->CtrlResponseLength)); 765 status = QDF_STATUS_E_BADMSG; 766 break; 767 } 768 769 pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer; 770 771 rdy_msg = &pReadyMsg->Version2_0_Info; 772 htc_rdy_msg_id = 773 HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID); 774 if (htc_rdy_msg_id != HTC_MSG_READY_ID) { 775 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 776 ("Invalid HTC Ready Msg : 0x%X!\n", 777 htc_rdy_msg_id)); 778 status = QDF_STATUS_E_BADMSG; 779 break; 780 } 781 782 target->TotalTransmitCredits = HTC_GET_FIELD(rdy_msg, 783 HTC_READY_MSG, CREDITCOUNT); 784 if (target->HTCInitInfo.cfg_wmi_credit_cnt && 785 (target->HTCInitInfo.cfg_wmi_credit_cnt < 786 target->TotalTransmitCredits)) 787 /* 788 * If INI configured value is less than FW advertised, 789 * then use INI configured value, otherwise use FW 790 * advertised. 791 */ 792 target->TotalTransmitCredits = 793 target->HTCInitInfo.cfg_wmi_credit_cnt; 794 795 target->TargetCreditSize = 796 (int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE); 797 target->MaxMsgsPerHTCBundle = 798 (uint8_t) pReadyMsg->MaxMsgsPerHTCBundle; 799 UPDATE_ALT_CREDIT(target, pReadyMsg->AltDataCreditSize); 800 /* for old fw this value is set to 0. But the minimum value 801 * should be 1, i.e., no bundling 802 */ 803 if (target->MaxMsgsPerHTCBundle < 1) 804 target->MaxMsgsPerHTCBundle = 1; 805 806 AR_DEBUG_PRINTF(ATH_DEBUG_INIT, 807 ("Target Ready! TX resource : %d size:%d, MaxMsgsPerHTCBundle = %d", 808 target->TotalTransmitCredits, 809 target->TargetCreditSize, 810 target->MaxMsgsPerHTCBundle)); 811 812 if ((0 == target->TotalTransmitCredits) 813 || (0 == target->TargetCreditSize)) { 814 status = QDF_STATUS_E_ABORTED; 815 break; 816 } 817 818 /* Allocate expected number of RX bundle buffer allocation */ 819 if (HTC_RX_BUNDLE_ENABLED(target)) { 820 temp_bundle_packet = NULL; 821 for (i = 0; i < MAX_HTC_RX_BUNDLE; i++) { 822 rx_bundle_packet = 823 allocate_htc_bundle_packet(target); 824 if (rx_bundle_packet) 825 rx_bundle_packet->ListLink.pNext = 826 (DL_LIST *)temp_bundle_packet; 827 else 828 break; 829 830 temp_bundle_packet = rx_bundle_packet; 831 } 832 LOCK_HTC_TX(target); 833 target->pBundleFreeList = temp_bundle_packet; 834 UNLOCK_HTC_TX(target); 835 } 836 837 /* done processing */ 838 target->CtrlResponseProcessing = false; 839 840 htc_setup_target_buffer_assignments(target); 841 842 /* setup our pseudo HTC control endpoint connection */ 843 qdf_mem_zero(&connect, sizeof(connect)); 844 qdf_mem_zero(&resp, sizeof(resp)); 845 connect.EpCallbacks.pContext = target; 846 connect.EpCallbacks.EpTxComplete = htc_control_tx_complete; 847 connect.EpCallbacks.EpRecv = htc_control_rx_complete; 848 connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS; 849 connect.service_id = HTC_CTRL_RSVD_SVC; 850 851 /* connect fake service */ 852 status = htc_connect_service((HTC_HANDLE) target, 853 &connect, &resp); 854 855 } while (false); 856 857 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n", 858 status)); 859 AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, ("-HWT\n")); 860 return status; 861 } 862 863 /* start HTC, this is called after all services are connected */ 864 static A_STATUS htc_config_target_hif_pipe(HTC_TARGET *target) 865 { 866 867 return A_OK; 868 } 869 870 static void reset_endpoint_states(HTC_TARGET *target) 871 { 872 HTC_ENDPOINT *pEndpoint; 873 int i; 874 875 for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { 876 pEndpoint = &target->endpoint[i]; 877 pEndpoint->service_id = 0; 878 pEndpoint->MaxMsgLength = 0; 879 pEndpoint->MaxTxQueueDepth = 0; 880 pEndpoint->Id = i; 881 INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); 882 INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue); 883 INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue); 884 pEndpoint->target = target; 885 pEndpoint->TxCreditFlowEnabled = (bool)htc_credit_flow; 886 pEndpoint->num_requeues_warn = 0; 887 pEndpoint->total_num_requeues = 0; 888 qdf_atomic_init(&pEndpoint->TxProcessCount); 889 } 890 } 891 892 /** 893 * htc_start() - Main HTC function to trigger HTC start 894 * @HTCHandle: pointer to HTC handle 895 * 896 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 897 */ 898 QDF_STATUS htc_start(HTC_HANDLE HTCHandle) 899 { 900 qdf_nbuf_t netbuf; 901 QDF_STATUS status = QDF_STATUS_SUCCESS; 902 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 903 HTC_SETUP_COMPLETE_EX_MSG *pSetupComp; 904 HTC_PACKET *pSendPacket; 905 906 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n")); 907 908 do { 909 910 htc_config_target_hif_pipe(target); 911 912 /* allocate a buffer to send */ 913 pSendPacket = htc_alloc_control_tx_packet(target); 914 if (!pSendPacket) { 915 AR_DEBUG_ASSERT(false); 916 qdf_print("%s: allocControlTxPacket failed", 917 __func__); 918 status = QDF_STATUS_E_NOMEM; 919 break; 920 } 921 922 netbuf = 923 (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); 924 /* assemble setup complete message */ 925 qdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); 926 pSetupComp = 927 (HTC_SETUP_COMPLETE_EX_MSG *) qdf_nbuf_data(netbuf); 928 qdf_mem_zero(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); 929 930 HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG, 931 MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID); 932 933 if (!htc_credit_flow) { 934 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 935 ("HTC will not use TX credit flow control")); 936 pSetupComp->SetupFlags |= 937 HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW; 938 } else { 939 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 940 ("HTC using TX credit flow control")); 941 } 942 943 if ((hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO) || 944 (hif_get_bus_type(target->hif_dev) == 945 QDF_BUS_TYPE_USB)) { 946 if (HTC_RX_BUNDLE_ENABLED(target)) 947 pSetupComp->SetupFlags |= 948 HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; 949 hif_set_bundle_mode(target->hif_dev, true, 950 HTC_MAX_MSG_PER_BUNDLE_RX); 951 pSetupComp->MaxMsgsPerBundledRecv = HTC_MAX_MSG_PER_BUNDLE_RX; 952 } 953 954 SET_HTC_PACKET_INFO_TX(pSendPacket, 955 NULL, 956 (uint8_t *) pSetupComp, 957 sizeof(HTC_SETUP_COMPLETE_EX_MSG), 958 ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); 959 960 status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); 961 if (QDF_IS_STATUS_ERROR(status)) 962 break; 963 } while (false); 964 965 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n")); 966 return status; 967 } 968 969 /*flush all queued buffers for surpriseremove case*/ 970 void htc_flush_surprise_remove(HTC_HANDLE HTCHandle) 971 { 972 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 973 int i; 974 HTC_ENDPOINT *pEndpoint; 975 #ifdef RX_SG_SUPPORT 976 qdf_nbuf_t netbuf; 977 qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; 978 #endif 979 980 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove\n")); 981 982 /* cleanup endpoints */ 983 for (i = 0; i < ENDPOINT_MAX; i++) { 984 pEndpoint = &target->endpoint[i]; 985 htc_flush_rx_hold_queue(target, pEndpoint); 986 htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); 987 } 988 989 hif_flush_surprise_remove(target->hif_dev); 990 991 #ifdef RX_SG_SUPPORT 992 LOCK_HTC_RX(target); 993 while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) 994 qdf_nbuf_free(netbuf); 995 RESET_RX_SG_CONFIG(target); 996 UNLOCK_HTC_RX(target); 997 #endif 998 999 reset_endpoint_states(target); 1000 1001 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove\n")); 1002 } 1003 1004 /* stop HTC communications, i.e. stop interrupt reception, and flush all queued 1005 * buffers 1006 */ 1007 void htc_stop(HTC_HANDLE HTCHandle) 1008 { 1009 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1010 int i; 1011 HTC_ENDPOINT *endpoint; 1012 #ifdef RX_SG_SUPPORT 1013 qdf_nbuf_t netbuf; 1014 qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; 1015 #endif 1016 1017 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop\n")); 1018 1019 htc_runtime_pm_deinit(target); 1020 1021 HTC_INFO("%s: endpoints cleanup\n", __func__); 1022 /* cleanup endpoints */ 1023 for (i = 0; i < ENDPOINT_MAX; i++) { 1024 endpoint = &target->endpoint[i]; 1025 htc_flush_rx_hold_queue(target, endpoint); 1026 htc_flush_endpoint_tx(target, endpoint, HTC_TX_PACKET_TAG_ALL); 1027 if (endpoint->ul_is_polled) { 1028 qdf_timer_stop(&endpoint->ul_poll_timer); 1029 qdf_timer_free(&endpoint->ul_poll_timer); 1030 } 1031 } 1032 1033 /* Note: htc_flush_endpoint_tx for all endpoints should be called before 1034 * hif_stop - otherwise htc_tx_completion_handler called from 1035 * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer, 1036 * might queue the packet again to HIF Layer - which could cause tx 1037 * buffer leak 1038 */ 1039 1040 HTC_INFO("%s: stopping hif layer\n", __func__); 1041 hif_stop(target->hif_dev); 1042 1043 #ifdef RX_SG_SUPPORT 1044 LOCK_HTC_RX(target); 1045 while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) 1046 qdf_nbuf_free(netbuf); 1047 RESET_RX_SG_CONFIG(target); 1048 UNLOCK_HTC_RX(target); 1049 #endif 1050 1051 /** 1052 * In SSR case, HTC tx completion callback for wmi will be blocked 1053 * by TARGET_STATUS_RESET and HTC packets will be left unfreed on 1054 * lookup queue. 1055 * 1056 * In case of target failing to send wmi_ready_event, the htc connect 1057 * msg buffer will be left unmapped and not freed. So calling the 1058 * completion handler for this buffer will handle this scenario. 1059 */ 1060 HTC_INFO("%s: flush endpoints Tx lookup queue\n", __func__); 1061 for (i = 0; i < ENDPOINT_MAX; i++) { 1062 endpoint = &target->endpoint[i]; 1063 if (endpoint->service_id == WMI_CONTROL_SVC) 1064 htc_flush_endpoint_txlookupQ(target, i, false); 1065 else if (endpoint->service_id == HTC_CTRL_RSVD_SVC || 1066 (endpoint->service_id == HTT_DATA_MSG_SVC && 1067 !endpoint->ul_is_polled)) 1068 htc_flush_endpoint_txlookupQ(target, i, true); 1069 } 1070 HTC_INFO("%s: resetting endpoints state\n", __func__); 1071 1072 reset_endpoint_states(target); 1073 1074 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop\n")); 1075 } 1076 1077 void htc_dump_credit_states(HTC_HANDLE HTCHandle) 1078 { 1079 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1080 HTC_ENDPOINT *pEndpoint; 1081 int i; 1082 1083 for (i = 0; i < ENDPOINT_MAX; i++) { 1084 pEndpoint = &target->endpoint[i]; 1085 if (0 == pEndpoint->service_id) 1086 continue; 1087 1088 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1089 ("--- EP : %d service_id: 0x%X --------------\n", 1090 pEndpoint->Id, pEndpoint->service_id)); 1091 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1092 (" TxCredits : %d\n", 1093 pEndpoint->TxCredits)); 1094 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1095 (" TxCreditSize : %d\n", 1096 pEndpoint->TxCreditSize)); 1097 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1098 (" TxCreditsPerMaxMsg : %d\n", 1099 pEndpoint->TxCreditsPerMaxMsg)); 1100 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1101 (" TxQueueDepth : %d\n", 1102 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); 1103 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1104 ("----------------------------------------\n")); 1105 } 1106 } 1107 1108 bool htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, 1109 HTC_ENDPOINT_ID Endpoint, 1110 enum htc_endpoint_stat_action Action, 1111 struct htc_endpoint_stats *pStats) 1112 { 1113 #ifdef HTC_EP_STAT_PROFILING 1114 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1115 bool clearStats = false; 1116 bool sample = false; 1117 1118 switch (Action) { 1119 case HTC_EP_STAT_SAMPLE: 1120 sample = true; 1121 break; 1122 case HTC_EP_STAT_SAMPLE_AND_CLEAR: 1123 sample = true; 1124 clearStats = true; 1125 break; 1126 case HTC_EP_STAT_CLEAR: 1127 clearStats = true; 1128 break; 1129 default: 1130 break; 1131 } 1132 1133 A_ASSERT(Endpoint < ENDPOINT_MAX); 1134 1135 /* lock out TX and RX while we sample and/or clear */ 1136 LOCK_HTC_TX(target); 1137 LOCK_HTC_RX(target); 1138 1139 if (sample) { 1140 A_ASSERT(pStats); 1141 /* return the stats to the caller */ 1142 qdf_mem_copy(pStats, &target->endpoint[Endpoint].endpoint_stats, 1143 sizeof(struct htc_endpoint_stats)); 1144 } 1145 1146 if (clearStats) { 1147 /* reset stats */ 1148 qdf_mem_zero(&target->endpoint[Endpoint].endpoint_stats, 1149 sizeof(struct htc_endpoint_stats)); 1150 } 1151 1152 UNLOCK_HTC_RX(target); 1153 UNLOCK_HTC_TX(target); 1154 1155 return true; 1156 #else 1157 return false; 1158 #endif 1159 } 1160 1161 void *htc_get_targetdef(HTC_HANDLE htc_handle) 1162 { 1163 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 1164 1165 return hif_get_targetdef(target->hif_dev); 1166 } 1167 1168 #ifdef IPA_OFFLOAD 1169 /** 1170 * htc_ipa_get_ce_resource() - get uc resource on lower layer 1171 * @htc_handle: htc context 1172 * @ce_sr_base_paddr: copyengine source ring base physical address 1173 * @ce_sr_ring_size: copyengine source ring size 1174 * @ce_reg_paddr: copyengine register physical address 1175 * 1176 * Return: None 1177 */ 1178 void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle, 1179 qdf_shared_mem_t **ce_sr, 1180 uint32_t *ce_sr_ring_size, 1181 qdf_dma_addr_t *ce_reg_paddr) 1182 { 1183 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 1184 1185 if (target->hif_dev) 1186 hif_ipa_get_ce_resource(target->hif_dev, 1187 ce_sr, ce_sr_ring_size, ce_reg_paddr); 1188 } 1189 #endif /* IPA_OFFLOAD */ 1190 1191 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) 1192 1193 void htc_dump_bundle_stats(HTC_HANDLE HTCHandle) 1194 { 1195 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1196 int total, i; 1197 1198 total = 0; 1199 for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++) 1200 total += target->rx_bundle_stats[i]; 1201 1202 if (total) { 1203 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("RX Bundle stats:\n")); 1204 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total RX packets: %d\n", 1205 total)); 1206 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ( 1207 "Number of bundle: Number of packets\n")); 1208 for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++) 1209 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1210 ("%10d:%10d(%2d%s)\n", (i+1), 1211 target->rx_bundle_stats[i], 1212 ((target->rx_bundle_stats[i]*100)/ 1213 total), "%")); 1214 } 1215 1216 1217 total = 0; 1218 for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++) 1219 total += target->tx_bundle_stats[i]; 1220 1221 if (total) { 1222 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("TX Bundle stats:\n")); 1223 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total TX packets: %d\n", 1224 total)); 1225 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1226 ("Number of bundle: Number of packets\n")); 1227 for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++) 1228 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 1229 ("%10d:%10d(%2d%s)\n", (i+1), 1230 target->tx_bundle_stats[i], 1231 ((target->tx_bundle_stats[i]*100)/ 1232 total), "%")); 1233 } 1234 } 1235 1236 void htc_clear_bundle_stats(HTC_HANDLE HTCHandle) 1237 { 1238 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1239 1240 qdf_mem_zero(&target->rx_bundle_stats, sizeof(target->rx_bundle_stats)); 1241 qdf_mem_zero(&target->tx_bundle_stats, sizeof(target->tx_bundle_stats)); 1242 } 1243 #endif 1244 1245 /** 1246 * htc_can_suspend_link - API to query HIF for link status 1247 * @htc_handle: HTC Handle 1248 * 1249 * API for upper layers to call HIF to query if the link can suspend 1250 * 1251 * Return: void 1252 */ 1253 bool htc_can_suspend_link(HTC_HANDLE htc_handle) 1254 { 1255 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 1256 1257 if (!target->hif_dev) 1258 return false; 1259 1260 return hif_can_suspend_link(target->hif_dev); 1261 } 1262 1263 #ifdef FEATURE_RUNTIME_PM 1264 int htc_pm_runtime_get(HTC_HANDLE htc_handle) 1265 { 1266 return hif_rtpm_get(HIF_RTPM_GET_ASYNC, HIF_RTPM_ID_HTT); 1267 } 1268 1269 int htc_pm_runtime_put(HTC_HANDLE htc_handle) 1270 { 1271 return hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT); 1272 } 1273 #endif 1274 1275 /** 1276 * htc_set_wmi_endpoint_count: Set number of WMI endpoint 1277 * @htc_handle: HTC handle 1278 * @wmi_ep_count: WMI endpoint count 1279 * 1280 * return: None 1281 */ 1282 void htc_set_wmi_endpoint_count(HTC_HANDLE htc_handle, uint8_t wmi_ep_count) 1283 { 1284 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 1285 1286 target->wmi_ep_count = wmi_ep_count; 1287 } 1288 1289 /** 1290 * htc_get_wmi_endpoint_count: Get number of WMI endpoint 1291 * @htc_handle: HTC handle 1292 * 1293 * return: WMI endpoint count 1294 */ 1295 uint8_t htc_get_wmi_endpoint_count(HTC_HANDLE htc_handle) 1296 { 1297 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 1298 1299 return target->wmi_ep_count; 1300 } 1301