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