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