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