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