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