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