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