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