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