1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include "htc_debug.h" 21 #include "htc_internal.h" 22 #include "htc_credit_history.h" 23 #include <qdf_mem.h> /* qdf_mem_malloc */ 24 #include <qdf_nbuf.h> /* qdf_nbuf_t */ 25 #include "qdf_module.h" 26 27 /* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */ 28 /* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */ 29 #define DATA_EP_SIZE 4 30 /* #endif */ 31 #define HTC_DATA_RESOURCE_THRS 256 32 #define HTC_DATA_MINDESC_PERPACKET 2 33 34 /* maximum number of requeue attempts before print */ 35 #define MAX_REQUEUE_WARN 5 36 37 enum HTC_SEND_QUEUE_RESULT { 38 HTC_SEND_QUEUE_OK = 0, /* packet was queued */ 39 HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */ 40 }; 41 42 #ifndef DEBUG_CREDIT 43 #define DEBUG_CREDIT 0 44 #endif 45 46 #if DEBUG_CREDIT 47 /* bit mask to enable debug certain endpoint */ 48 static unsigned int ep_debug_mask = 49 (1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2); 50 #endif 51 52 #ifdef QCA_WIFI_EMULATION 53 #define HTC_EMULATION_DELAY_IN_MS 20 54 /** 55 * htc_add_delay(): Adds a delay in before proceeding, only for emulation 56 * 57 * Return: None 58 */ 59 static inline void htc_add_emulation_delay(void) 60 { 61 qdf_mdelay(HTC_EMULATION_DELAY_IN_MS); 62 } 63 #else 64 static inline void htc_add_emulation_delay(void) 65 { 66 } 67 #endif 68 69 void htc_dump_counter_info(HTC_HANDLE HTCHandle) 70 { 71 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 72 73 if (!target) 74 return; 75 76 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 77 ("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n", 78 __func__, target->ce_send_cnt, target->TX_comp_cnt)); 79 } 80 81 int htc_get_tx_queue_depth(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id) 82 { 83 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); 84 HTC_ENDPOINT *endpoint = &target->endpoint[endpoint_id]; 85 86 return HTC_PACKET_QUEUE_DEPTH(&endpoint->TxQueue); 87 } 88 qdf_export_symbol(htc_get_tx_queue_depth); 89 90 void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, 91 int *credits) 92 { 93 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 94 HTC_ENDPOINT *pEndpoint; 95 int i; 96 97 if (!credits || !target) { 98 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__)); 99 return; 100 } 101 102 *credits = 0; 103 LOCK_HTC_TX(target); 104 for (i = 0; i < ENDPOINT_MAX; i++) { 105 pEndpoint = &target->endpoint[i]; 106 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 107 *credits = pEndpoint->TxCredits; 108 break; 109 } 110 } 111 UNLOCK_HTC_TX(target); 112 } 113 114 static inline void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) 115 { 116 qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 117 118 if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) { 119 qdf_nbuf_unmap(target->osdev, netbuf, QDF_DMA_TO_DEVICE); 120 pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 121 } 122 if (pPacket->PktInfo.AsTx.Flags & 123 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA) { 124 qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR)); 125 pPacket->PktInfo.AsTx.Flags &= 126 ~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 127 } 128 } 129 130 static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket) 131 { 132 HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint]; 133 HTC_EP_SEND_PKT_COMPLETE EpTxComplete; 134 135 if ((pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) && 136 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))) 137 target->nbuf_nfc_unmap_count++; 138 139 restore_tx_packet(target, pPacket); 140 141 /* 142 * In case of SSR, we cannot call the upper layer completion 143 * callbacks, hence just free the nbuf and HTC packet here. 144 */ 145 if (target->hif_dev && hif_get_target_status(target->hif_dev)) { 146 htc_free_control_tx_packet(target, pPacket); 147 return; 148 } 149 150 /* do completion */ 151 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 152 ("HTC calling ep %d send complete callback on packet %pK\n", 153 pEndpoint->Id, pPacket)); 154 155 EpTxComplete = pEndpoint->EpCallBacks.EpTxComplete; 156 if (EpTxComplete) 157 EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket); 158 else 159 qdf_nbuf_free(pPacket->pPktContext); 160 161 162 } 163 164 #ifdef FEATURE_RUNTIME_PM 165 /** 166 * log_packet_info() - Log HTC packet information 167 * 168 * @target: handle of HTC context 169 * @pPacket: handle of HTC packet 170 * 171 * Return: None 172 */ 173 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket) 174 { 175 HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint]; 176 HTC_EP_LOG_PKT ep_log_pkt; 177 qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 178 179 ep_log_pkt = pEndpoint->EpCallBacks.ep_log_pkt; 180 if (ep_log_pkt) { 181 qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR)); 182 ep_log_pkt(pEndpoint->EpCallBacks.pContext, pPacket); 183 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); 184 } 185 } 186 187 /** 188 * htc_inc_htt_runtime_cnt: Increment htc htt runtime count 189 * @target: handle of HTC context 190 * 191 * Return: None 192 */ 193 static inline 194 void htc_inc_htt_runtime_cnt(HTC_TARGET *target) 195 { 196 qdf_atomic_inc(&target->htc_htt_runtime_cnt); 197 } 198 #else 199 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket) 200 { 201 } 202 203 static inline 204 void htc_inc_htt_runtime_cnt(HTC_TARGET *target) 205 { 206 } 207 #endif 208 209 void htc_send_complete_check_cleanup(void *context) 210 { 211 HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context; 212 213 htc_send_complete_check(pEndpoint, 1); 214 } 215 216 HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target) 217 { 218 HTC_PACKET *pPacket; 219 HTC_PACKET_QUEUE *pQueueSave; 220 qdf_nbuf_t netbuf; 221 222 LOCK_HTC_TX(target); 223 if (!target->pBundleFreeList) { 224 UNLOCK_HTC_TX(target); 225 netbuf = qdf_nbuf_alloc(NULL, 226 target->MaxMsgsPerHTCBundle * 227 target->TargetCreditSize, 0, 4, false); 228 AR_DEBUG_ASSERT(netbuf); 229 if (!netbuf) 230 return NULL; 231 pPacket = qdf_mem_malloc(sizeof(HTC_PACKET)); 232 AR_DEBUG_ASSERT(pPacket); 233 if (!pPacket) { 234 qdf_nbuf_free(netbuf); 235 return NULL; 236 } 237 pQueueSave = qdf_mem_malloc(sizeof(HTC_PACKET_QUEUE)); 238 AR_DEBUG_ASSERT(pQueueSave); 239 if (!pQueueSave) { 240 qdf_nbuf_free(netbuf); 241 qdf_mem_free(pPacket); 242 return NULL; 243 } 244 INIT_HTC_PACKET_QUEUE(pQueueSave); 245 pPacket->pContext = pQueueSave; 246 SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); 247 pPacket->pBuffer = qdf_nbuf_data(netbuf); 248 pPacket->BufferLength = qdf_nbuf_len(netbuf); 249 250 /* store the original head room so that we can restore this 251 * when we "free" the packet. 252 * free packet puts the packet back on the free list 253 */ 254 pPacket->netbufOrigHeadRoom = qdf_nbuf_headroom(netbuf); 255 return pPacket; 256 } 257 /* already done malloc - restore from free list */ 258 pPacket = target->pBundleFreeList; 259 AR_DEBUG_ASSERT(pPacket); 260 if (!pPacket) { 261 UNLOCK_HTC_TX(target); 262 return NULL; 263 } 264 target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext; 265 UNLOCK_HTC_TX(target); 266 pPacket->ListLink.pNext = NULL; 267 268 return pPacket; 269 } 270 271 void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket) 272 { 273 uint32_t curentHeadRoom; 274 qdf_nbuf_t netbuf; 275 HTC_PACKET_QUEUE *pQueueSave; 276 277 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 278 AR_DEBUG_ASSERT(netbuf); 279 if (!netbuf) { 280 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 281 ("\n%s: Invalid netbuf in HTC Packet\n", 282 __func__)); 283 return; 284 } 285 /* HIF adds data to the headroom section of the nbuf, restore their 286 * original size. If this is not done, headroom keeps shrinking with 287 * every HIF send and eventually HIF ends up doing another malloc big 288 * enough to store the data + its header 289 */ 290 291 curentHeadRoom = qdf_nbuf_headroom(netbuf); 292 qdf_nbuf_pull_head(netbuf, 293 pPacket->netbufOrigHeadRoom - curentHeadRoom); 294 qdf_nbuf_trim_tail(netbuf, qdf_nbuf_len(netbuf)); 295 296 /* restore the pBuffer pointer. HIF changes this */ 297 pPacket->pBuffer = qdf_nbuf_data(netbuf); 298 pPacket->BufferLength = qdf_nbuf_len(netbuf); 299 300 /* restore queue */ 301 pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext; 302 if (qdf_unlikely(!pQueueSave)) { 303 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 304 ("\n%s: Invalid pQueueSave in HTC Packet\n", 305 __func__)); 306 AR_DEBUG_ASSERT(pQueueSave); 307 } else 308 INIT_HTC_PACKET_QUEUE(pQueueSave); 309 310 LOCK_HTC_TX(target); 311 if (!target->pBundleFreeList) { 312 target->pBundleFreeList = pPacket; 313 pPacket->ListLink.pNext = NULL; 314 } else { 315 pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList; 316 target->pBundleFreeList = pPacket; 317 } 318 UNLOCK_HTC_TX(target); 319 } 320 321 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) 322 323 /** 324 * htc_send_update_tx_bundle_stats() - update tx bundle stats depends 325 * on max bundle size 326 * @target: hif context 327 * @data_len: tx data len 328 * @TxCreditSize: endpoint tx credit size 329 * 330 * Return: None 331 */ 332 static inline void 333 htc_send_update_tx_bundle_stats(HTC_TARGET *target, 334 qdf_size_t data_len, 335 int TxCreditSize) 336 { 337 int index = ((data_len + TxCreditSize - 1) / TxCreditSize) - 1; 338 339 if (index < HTC_MAX_MSG_PER_BUNDLE_TX) 340 target->tx_bundle_stats[index]++; 341 } 342 343 /** 344 * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats 345 * on max bundle size 346 * @target: hif context 347 * 348 * Return: None 349 */ 350 static inline void 351 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) 352 { 353 target->tx_bundle_stats[0]++; 354 } 355 #else 356 357 static inline void 358 htc_send_update_tx_bundle_stats(HTC_TARGET *target, 359 qdf_size_t data_len, 360 int TxCreditSize) 361 { 362 } 363 364 static inline void 365 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) 366 { 367 } 368 #endif 369 370 #if defined(HIF_USB) || defined(HIF_SDIO) 371 #ifdef ENABLE_BUNDLE_TX 372 static QDF_STATUS htc_send_bundled_netbuf(HTC_TARGET *target, 373 HTC_ENDPOINT *pEndpoint, 374 unsigned char *pBundleBuffer, 375 HTC_PACKET *pPacketTx) 376 { 377 qdf_size_t data_len; 378 QDF_STATUS status; 379 qdf_nbuf_t bundleBuf; 380 uint32_t data_attr = 0; 381 382 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 383 data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf); 384 qdf_nbuf_put_tail(bundleBuf, data_len); 385 SET_HTC_PACKET_INFO_TX(pPacketTx, 386 target, 387 pBundleBuffer, 388 data_len, 389 pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED); 390 LOCK_HTC_TX(target); 391 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx); 392 pEndpoint->ul_outstanding_cnt++; 393 UNLOCK_HTC_TX(target); 394 #if DEBUG_BUNDLE 395 qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.", 396 pEndpoint->Id, 397 pEndpoint->TxCreditSize, 398 data_len, data_len / pEndpoint->TxCreditSize); 399 #endif 400 401 htc_send_update_tx_bundle_stats(target, data_len, 402 pEndpoint->TxCreditSize); 403 404 status = hif_send_head(target->hif_dev, 405 pEndpoint->UL_PipeID, 406 pEndpoint->Id, data_len, 407 bundleBuf, data_attr); 408 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 409 HTC_PACKET_QUEUE requeue; 410 411 qdf_print("hif_send_head failed(len=%zu).", data_len); 412 INIT_HTC_PACKET_QUEUE(&requeue); 413 LOCK_HTC_TX(target); 414 pEndpoint->ul_outstanding_cnt--; 415 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacketTx); 416 417 if (pPacketTx->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) { 418 HTC_PACKET *temp_packet; 419 HTC_PACKET_QUEUE *packet_queue = 420 (HTC_PACKET_QUEUE *)pPacketTx->pContext; 421 422 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(packet_queue, 423 temp_packet) { 424 HTC_PACKET_ENQUEUE(&requeue, temp_packet); 425 } HTC_PACKET_QUEUE_ITERATE_END; 426 427 UNLOCK_HTC_TX(target); 428 free_htc_bundle_packet(target, pPacketTx); 429 LOCK_HTC_TX(target); 430 431 } else { 432 HTC_PACKET_ENQUEUE(&requeue, pPacketTx); 433 } 434 435 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 436 &requeue); 437 UNLOCK_HTC_TX(target); 438 } 439 return status; 440 } 441 442 #ifdef QCA_TX_PADDING_CREDIT_SUPPORT 443 #define SDIO_BLOCK_SIZE 512 444 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep) 445 { 446 int ret = 0; 447 448 if (!ep || !ep->EpCallBacks.pContext || 449 !ep->EpCallBacks.ep_padding_credit_update) 450 return 1; 451 452 ret = ep->EpCallBacks.ep_padding_credit_update(ep->EpCallBacks.pContext, 453 0); 454 455 if (ret < 2) 456 AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s ret %d\n", __func__, ret)); 457 458 return ret; 459 } 460 461 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep, 462 HTC_PACKET *p_last_htc_pkt, 463 unsigned char *p_last_pkt_bundle_buffer, 464 unsigned char **p_bundle_buffer, 465 int tot_data_len) 466 { 467 bool extra_tx_credit = FALSE; 468 HTC_FRAME_HDR *p_htc_hdr; 469 int first_buf_bundled_len = 0, last_buf_len = 0; 470 int sdio_pad = 0, free_space = 0; 471 int (*update_ep_padding_credit)(void *, int); 472 473 update_ep_padding_credit = ep->EpCallBacks.ep_padding_credit_update; 474 475 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 476 ("%s Tot data_len = %d\n", __func__, tot_data_len)); 477 478 if (!p_last_htc_pkt) 479 return extra_tx_credit; 480 481 last_buf_len = (p_last_htc_pkt->ActualLength + HTC_HDR_LENGTH); 482 if (tot_data_len != last_buf_len) { 483 first_buf_bundled_len = tot_data_len - ep->TxCreditSize; 484 free_space = tot_data_len - 485 (first_buf_bundled_len + last_buf_len); 486 } else { 487 free_space = ep->TxCreditSize - tot_data_len; 488 } 489 490 sdio_pad = SDIO_BLOCK_SIZE - ((first_buf_bundled_len + last_buf_len) % 491 SDIO_BLOCK_SIZE); 492 493 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 494 ("%s first_buf_bundled_len = %d last_buf_len = %d\n", 495 __func__, first_buf_bundled_len, last_buf_len)); 496 497 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 498 ("%s sdio_pad = %d free_space = %d\n", __func__, 499 sdio_pad, free_space)); 500 501 if (sdio_pad <= free_space) { 502 if (p_bundle_buffer && *p_bundle_buffer) { 503 /* Align Tx bundled buf to avoid a extra Padding buf */ 504 *p_bundle_buffer -= (free_space - sdio_pad); 505 } 506 } else { 507 /* Extra Padding Buffer needed, consume extra tx credit */ 508 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 509 ("%s Used a Tx credit for Padding Buffer\n", 510 __func__)); 511 p_htc_hdr = (HTC_FRAME_HDR *)(p_last_pkt_bundle_buffer); 512 p_htc_hdr->Flags |= HTC_FLAGS_PADDING_CHECK; 513 extra_tx_credit = TRUE; 514 if (ep->EpCallBacks.ep_padding_credit_update) { 515 /* Decrement 1 credit at host, 516 * due to extra tx credit consumed by padding buffer 517 */ 518 update_ep_padding_credit(ep->EpCallBacks.pContext, -1); 519 } 520 } 521 return extra_tx_credit; 522 } 523 #else 524 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep) 525 { 526 return 1; 527 } 528 529 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep, 530 HTC_PACKET *p_last_htc_pkt, 531 unsigned char *p_last_pkt_bundle_buffer, 532 unsigned char **p_bundle_buffer, 533 int tot_data_len) 534 { 535 return FALSE; 536 } 537 #endif 538 539 /** 540 * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue 541 * @target: HTC target on which packets need to be sent 542 * @pEndpoint: logical endpoint on which packets needs to be sent 543 * @pPktQueue: HTC packet queue containing the list of packets to be sent 544 * 545 * Return: void 546 */ 547 static void htc_issue_packets_bundle(HTC_TARGET *target, 548 HTC_ENDPOINT *pEndpoint, 549 HTC_PACKET_QUEUE *pPktQueue) 550 { 551 int i, frag_count, nbytes; 552 qdf_nbuf_t netbuf, bundleBuf; 553 unsigned char *pBundleBuffer = NULL; 554 HTC_PACKET *pPacket = NULL, *pPacketTx = NULL; 555 HTC_FRAME_HDR *pHtcHdr; 556 int last_credit_pad = 0; 557 int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining = 558 0; 559 HTC_PACKET_QUEUE *pQueueSave = NULL; 560 HTC_PACKET *p_last_htc_pkt = NULL; 561 unsigned char *p_last_pkt_bundle_buffer = NULL; 562 563 bundlesSpaceRemaining = 564 target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize; 565 pPacketTx = allocate_htc_bundle_packet(target); 566 if (!pPacketTx) { 567 /* good time to panic */ 568 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 569 ("allocate_htc_bundle_packet failed\n")); 570 AR_DEBUG_ASSERT(false); 571 return; 572 } 573 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 574 pBundleBuffer = qdf_nbuf_data(bundleBuf); 575 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; 576 while (1) { 577 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 578 if (htc_tx_pad_credit_avail(pEndpoint) < 1) 579 break; 580 } 581 pPacket = htc_packet_dequeue(pPktQueue); 582 if (!pPacket) 583 break; 584 creditPad = 0; 585 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; 586 creditRemainder = transferLength % pEndpoint->TxCreditSize; 587 if (creditRemainder != 0) { 588 if (transferLength < pEndpoint->TxCreditSize) { 589 creditPad = pEndpoint->TxCreditSize - 590 transferLength; 591 } else { 592 creditPad = creditRemainder; 593 } 594 transferLength += creditPad; 595 } 596 597 if (bundlesSpaceRemaining < transferLength) { 598 htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt, 599 p_last_pkt_bundle_buffer, 600 &pBundleBuffer, 601 pBundleBuffer - 602 qdf_nbuf_data(bundleBuf)); 603 604 /* send out previous buffer */ 605 htc_send_bundled_netbuf(target, pEndpoint, 606 pBundleBuffer - last_credit_pad, 607 pPacketTx); 608 /* One packet has been dequeued from sending queue when enter 609 * this loop, so need to add 1 back for this checking. 610 */ 611 if ((HTC_PACKET_QUEUE_DEPTH(pPktQueue) + 1) < 612 HTC_MIN_MSG_PER_BUNDLE) { 613 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 614 return; 615 } 616 bundlesSpaceRemaining = 617 target->MaxMsgsPerHTCBundle * 618 pEndpoint->TxCreditSize; 619 pPacketTx = allocate_htc_bundle_packet(target); 620 if (!pPacketTx) { 621 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 622 /* good time to panic */ 623 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 624 ("allocate_htc_bundle_packet failed\n")); 625 AR_DEBUG_ASSERT(false); 626 return; 627 } 628 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 629 pBundleBuffer = qdf_nbuf_data(bundleBuf); 630 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; 631 } 632 633 p_last_htc_pkt = pPacket; 634 p_last_pkt_bundle_buffer = pBundleBuffer; 635 636 bundlesSpaceRemaining -= transferLength; 637 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 638 639 if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) { 640 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr( 641 netbuf, 0); 642 HTC_WRITE32(pHtcHdr, 643 SM(pPacket->ActualLength, 644 HTC_FRAME_HDR_PAYLOADLEN) | 645 SM(pPacket->PktInfo.AsTx.SendFlags | 646 HTC_FLAGS_SEND_BUNDLE, 647 HTC_FRAME_HDR_FLAGS) | 648 SM(pPacket->Endpoint, 649 HTC_FRAME_HDR_ENDPOINTID)); 650 HTC_WRITE32((uint32_t *) pHtcHdr + 1, 651 SM(pPacket->PktInfo.AsTx.SeqNo, 652 HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad, 653 HTC_FRAME_HDR_RESERVED)); 654 pHtcHdr->reserved = creditPad; 655 } 656 frag_count = qdf_nbuf_get_num_frags(netbuf); 657 nbytes = pPacket->ActualLength + HTC_HDR_LENGTH; 658 for (i = 0; i < frag_count && nbytes > 0; i++) { 659 int frag_len = qdf_nbuf_get_frag_len(netbuf, i); 660 unsigned char *frag_addr = 661 qdf_nbuf_get_frag_vaddr(netbuf, i); 662 if (frag_len > nbytes) 663 frag_len = nbytes; 664 qdf_mem_copy(pBundleBuffer, frag_addr, frag_len); 665 nbytes -= frag_len; 666 pBundleBuffer += frag_len; 667 } 668 HTC_PACKET_ENQUEUE(pQueueSave, pPacket); 669 pBundleBuffer += creditPad; 670 671 /* last one can't be packed. */ 672 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) 673 last_credit_pad = creditPad; 674 } 675 /* send out remaining buffer */ 676 if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) { 677 htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt, 678 p_last_pkt_bundle_buffer, 679 &pBundleBuffer, 680 pBundleBuffer - 681 qdf_nbuf_data(bundleBuf)); 682 683 htc_send_bundled_netbuf(target, pEndpoint, 684 pBundleBuffer - last_credit_pad, 685 pPacketTx); 686 } else { 687 free_htc_bundle_packet(target, pPacketTx); 688 } 689 } 690 #endif /* ENABLE_BUNDLE_TX */ 691 #else 692 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep) 693 { 694 return 1; 695 } 696 697 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep, 698 HTC_PACKET *p_last_htc_pkt, 699 unsigned char *p_last_pkt_bundle_buffer, 700 unsigned char **p_bundle_buffer, 701 int tot_data_len); 702 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep, 703 HTC_PACKET *p_last_htc_pkt, 704 unsigned char *p_last_pkt_bundle_buffer, 705 unsigned char **p_bundle_buffer, 706 int tot_data_len) 707 { 708 return FALSE; 709 } 710 711 static void htc_issue_packets_bundle(HTC_TARGET *target, 712 HTC_ENDPOINT *pEndpoint, 713 HTC_PACKET_QUEUE *pPktQueue) 714 { 715 } 716 #endif 717 718 /** 719 * htc_issue_packets() - HTC function to send packets from a queue 720 * @target: HTC target on which packets need to be sent 721 * @pEndpoint: logical endpoint on which packets needs to be sent 722 * @pPktQueue: HTC packet queue containing the list of packets to be sent 723 * 724 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure 725 */ 726 static QDF_STATUS htc_issue_packets(HTC_TARGET *target, 727 HTC_ENDPOINT *pEndpoint, 728 HTC_PACKET_QUEUE *pPktQueue) 729 { 730 QDF_STATUS status = QDF_STATUS_SUCCESS; 731 qdf_nbuf_t netbuf; 732 HTC_PACKET *pPacket = NULL; 733 uint16_t payloadLen; 734 HTC_FRAME_HDR *pHtcHdr; 735 uint32_t data_attr = 0; 736 enum qdf_bus_type bus_type; 737 QDF_STATUS ret; 738 bool rt_put = false; 739 bool used_extra_tx_credit = false; 740 uint8_t *buf = NULL; 741 int (*update_ep_padding_credit)(void *, int); 742 void *ctx = NULL; 743 bool rt_put_in_resp; 744 int32_t sys_state = HIF_SYSTEM_PM_STATE_ON; 745 746 update_ep_padding_credit = 747 pEndpoint->EpCallBacks.ep_padding_credit_update; 748 749 bus_type = hif_get_bus_type(target->hif_dev); 750 751 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 752 ("+htc_issue_packets: Queue: %pK, Pkts %d\n", pPktQueue, 753 HTC_PACKET_QUEUE_DEPTH(pPktQueue))); 754 while (true) { 755 rt_put_in_resp = false; 756 if (HTC_TX_BUNDLE_ENABLED(target) && 757 HTC_PACKET_QUEUE_DEPTH(pPktQueue) >= 758 HTC_MIN_MSG_PER_BUNDLE) { 759 switch (bus_type) { 760 case QDF_BUS_TYPE_SDIO: 761 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) 762 break; 763 if (update_ep_padding_credit) { 764 if (htc_tx_pad_credit_avail 765 (pEndpoint) < 1) 766 break; 767 } 768 fallthrough; 769 case QDF_BUS_TYPE_USB: 770 htc_issue_packets_bundle(target, 771 pEndpoint, 772 pPktQueue); 773 break; 774 default: 775 break; 776 } 777 } 778 /* if not bundling or there was a packet that could not be 779 * placed in a bundle, and send it by normal way 780 */ 781 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 782 if (htc_tx_pad_credit_avail(pEndpoint) < 1) { 783 status = QDF_STATUS_E_FAILURE; 784 break; 785 } 786 } 787 788 pPacket = htc_packet_dequeue(pPktQueue); 789 if (!pPacket) { 790 /* local queue is fully drained */ 791 break; 792 } 793 794 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 795 AR_DEBUG_ASSERT(netbuf); 796 /* Non-credit enabled endpoints have been mapped and setup by 797 * now, so no need to revisit the HTC headers 798 */ 799 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 800 801 payloadLen = pPacket->ActualLength; 802 /* setup HTC frame header */ 803 804 pHtcHdr = (HTC_FRAME_HDR *) 805 qdf_nbuf_get_frag_vaddr(netbuf, 0); 806 if (qdf_unlikely(!pHtcHdr)) { 807 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 808 ("%s Invalid pHtcHdr\n", 809 __func__)); 810 AR_DEBUG_ASSERT(pHtcHdr); 811 status = QDF_STATUS_E_FAILURE; 812 break; 813 } 814 815 HTC_WRITE32(pHtcHdr, 816 SM(payloadLen, 817 HTC_FRAME_HDR_PAYLOADLEN) | 818 SM(pPacket->PktInfo.AsTx.SendFlags, 819 HTC_FRAME_HDR_FLAGS) | 820 SM(pPacket->Endpoint, 821 HTC_FRAME_HDR_ENDPOINTID)); 822 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, 823 SM(pPacket->PktInfo.AsTx.SeqNo, 824 HTC_FRAME_HDR_CONTROLBYTES1)); 825 826 /* 827 * Now that the HTC frame header has been added, the 828 * netbuf can be mapped. This only applies to non-data 829 * frames, since data frames were already mapped as they 830 * entered into the driver. 831 */ 832 ret = qdf_nbuf_map(target->osdev, 833 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 834 QDF_DMA_TO_DEVICE); 835 if (ret != QDF_STATUS_SUCCESS) { 836 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 837 ("%s nbuf Map Fail Endpnt %pK\n", 838 __func__, pEndpoint)); 839 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 840 status = QDF_STATUS_E_FAILURE; 841 break; 842 } 843 pPacket->PktInfo.AsTx.Flags |= 844 HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 845 } 846 847 if (!pEndpoint->async_update) { 848 LOCK_HTC_TX(target); 849 } 850 /* store in look up queue to match completions */ 851 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); 852 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); 853 pEndpoint->ul_outstanding_cnt++; 854 if (!pEndpoint->async_update) { 855 UNLOCK_HTC_TX(target); 856 hif_send_complete_check(target->hif_dev, 857 pEndpoint->UL_PipeID, false); 858 } 859 860 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_SUSPEND) { 861 sys_state = hif_system_pm_get_state(target->hif_dev); 862 hif_system_pm_set_state_suspending(target->hif_dev); 863 } 864 865 htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE); 866 /* 867 * For HTT messages without a response from fw, 868 * do the runtime put here. 869 * otherwise runtime put will be done when the fw response comes 870 */ 871 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT) { 872 rt_put = true; 873 } else if (pPacket->PktInfo.AsTx.Tag == 874 HTC_TX_PACKET_TAG_RTPM_PUT_RC) { 875 rt_put_in_resp = true; 876 htc_inc_htt_runtime_cnt(target); 877 } 878 879 #if DEBUG_BUNDLE 880 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.", 881 pEndpoint->Id, 882 pEndpoint->TxCreditSize, 883 HTC_HDR_LENGTH + pPacket->ActualLength); 884 #endif 885 buf = (uint8_t *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 886 used_extra_tx_credit = 887 htc_handle_extra_tx_credit(pEndpoint, pPacket, buf, 888 NULL, pPacket->ActualLength + 889 HTC_HDR_LENGTH); 890 891 status = hif_send_head(target->hif_dev, 892 pEndpoint->UL_PipeID, pEndpoint->Id, 893 HTC_HDR_LENGTH + pPacket->ActualLength, 894 netbuf, data_attr); 895 896 if (status != QDF_STATUS_SUCCESS) { 897 if (rt_put_in_resp) 898 htc_dec_return_htt_runtime_cnt((void *)target); 899 900 if (pPacket->PktInfo.AsTx.Tag == 901 HTC_TX_PACKET_SYSTEM_SUSPEND) 902 __hif_system_pm_set_state(target->hif_dev, 903 sys_state); 904 905 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 906 if (used_extra_tx_credit) { 907 ctx = pEndpoint->EpCallBacks.pContext; 908 update_ep_padding_credit(ctx, 1); 909 } 910 } 911 } 912 913 htc_issue_tx_bundle_stats_inc(target); 914 915 target->ce_send_cnt++; 916 pEndpoint->htc_send_cnt++; 917 918 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 919 if (status != QDF_STATUS_E_RESOURCES) { 920 /* TODO : if more than 1 endpoint maps to the 921 * same PipeID it is possible to run out of 922 * resources in the HIF layer. Don't emit the 923 * error 924 */ 925 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 926 ("hif_send Failed status:%d\n", 927 status)); 928 } else { 929 if (target->htc_pkt_dbg) { 930 if (pEndpoint->num_requeues_warn > 931 MAX_REQUEUE_WARN) { 932 hif_print_napi_stats(target->hif_dev); 933 } 934 } 935 } 936 937 /* only unmap if we mapped in this function */ 938 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 939 qdf_nbuf_unmap(target->osdev, 940 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 941 QDF_DMA_TO_DEVICE); 942 pPacket->PktInfo.AsTx.Flags &= 943 ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 944 } 945 946 if (!pEndpoint->async_update) { 947 LOCK_HTC_TX(target); 948 } 949 target->ce_send_cnt--; 950 pEndpoint->htc_send_cnt--; 951 pEndpoint->ul_outstanding_cnt--; 952 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); 953 htc_packet_set_magic_cookie(pPacket, 0); 954 /* put it back into the callers queue */ 955 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 956 /* reclaim credits */ 957 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, 958 pPacket) { 959 pEndpoint->TxCredits += 960 pPacket->PktInfo.AsTx.CreditsUsed; 961 } HTC_PACKET_QUEUE_ITERATE_END; 962 if (!pEndpoint->async_update) { 963 UNLOCK_HTC_TX(target); 964 } 965 break; 966 } 967 if (rt_put) { 968 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT); 969 rt_put = false; 970 } 971 } 972 973 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 974 if (((status == QDF_STATUS_E_RESOURCES) && 975 (pEndpoint->num_requeues_warn > MAX_REQUEUE_WARN)) || 976 (status != QDF_STATUS_E_RESOURCES)) { 977 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, 978 "failed pkt:0x%pK status:%d endpoint:%d", 979 pPacket, status, pEndpoint->Id); 980 } 981 982 } 983 984 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets\n")); 985 986 return status; 987 } 988 989 #ifdef FEATURE_RUNTIME_PM 990 /** 991 * extract_htc_pm_packets(): move pm packets from endpoint into queue 992 * @endpoint: which endpoint to extract packets from 993 * @queue: a queue to store extracted packets in. 994 * 995 * remove pm packets from the endpoint's tx queue. 996 * queue them into a queue 997 */ 998 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, 999 HTC_PACKET_QUEUE *queue) 1000 { 1001 HTC_PACKET *packet; 1002 1003 /* only WMI endpoint has power management packets */ 1004 if (endpoint->service_id != WMI_CONTROL_SVC) 1005 return; 1006 1007 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, 1008 HTC_PACKET, ListLink) { 1009 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) { 1010 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); 1011 HTC_PACKET_ENQUEUE(queue, packet); 1012 } 1013 } ITERATE_END 1014 } 1015 1016 /** 1017 * queue_htc_pm_packets(): queue pm packets with priority 1018 * @endpoint: endpoint to queue packets to 1019 * @queue: queue of pm packets to enqueue 1020 * 1021 * suspend resume packets get special treatment & priority. 1022 * need to queue them at the front of the queue. 1023 */ 1024 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, 1025 HTC_PACKET_QUEUE *queue) 1026 { 1027 if (endpoint->service_id != WMI_CONTROL_SVC) 1028 return; 1029 1030 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue); 1031 } 1032 1033 /** 1034 * htc_dec_wmi_runtime_cnt: Decrement htc wmi runtime count 1035 * @target: HTC target 1036 * @rtpm_code: RTPM code 1037 * 1038 * Return: None 1039 */ 1040 static inline 1041 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code) 1042 { 1043 if (rtpm_code == HIF_RTPM_ID_WMI) 1044 qdf_atomic_dec(&target->htc_wmi_runtime_cnt); 1045 } 1046 1047 /** 1048 * htc_inc_wmi_runtime_cnt: Increment htc wmi runtime count 1049 * @target: HTC target 1050 * @rtpm_code: RTPM code 1051 * 1052 * Return: None 1053 */ 1054 static inline 1055 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code) 1056 { 1057 if (rtpm_code == HIF_RTPM_ID_WMI) 1058 qdf_atomic_inc(&target->htc_wmi_runtime_cnt); 1059 } 1060 #else 1061 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, 1062 HTC_PACKET_QUEUE *queue) 1063 {} 1064 1065 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, 1066 HTC_PACKET_QUEUE *queue) 1067 {} 1068 1069 static inline 1070 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code) 1071 { 1072 } 1073 1074 static inline 1075 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code) 1076 { 1077 } 1078 #endif 1079 1080 /** 1081 * htc_send_pkts_get_rtpm_id() - get runtime pm dbgid by service_id 1082 * @service_id: service for endpoint 1083 * 1084 * For service_id HTT_DATA_MSG_SVC, HTT message donot have a tx complete 1085 * from CE level, so they need runtime put which only can happen in fw 1086 * response. runtime put will happens at 2 ways. 1087 * 1 if packet tag HTC_TX_PACKET_TAG_RUNTIME_PUT, runtime put 1088 * will be just in htc_issue_packets. as such pkt doesn't have 1089 * a response from fw. 1090 * 2 other pkt must have a response from fw, it will be handled 1091 * by fw response using htc_pm_runtime_put. 1092 * 1093 * For other service_id, they have tx_completion from CE, so they will be 1094 * handled in htc_tx_completion_handler, except packet tag as 1095 * HTC_TX_PACKET_TAG_AUTO_PM, pm related wmi cmd don't need a runtime 1096 * put/get. 1097 * 1098 * 1099 * Return: rtpm id to trace who used it 1100 */ 1101 static unsigned int 1102 htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id) 1103 { 1104 if (service_id == HTT_DATA_MSG_SVC) 1105 return HIF_RTPM_ID_HTT; 1106 else 1107 return HIF_RTPM_ID_WMI; 1108 } 1109 1110 #ifdef SYSTEM_PM_CHECK 1111 /** 1112 * extract_htc_system_resume_pkts(): Move system pm resume packets from endpoint 1113 * into queue 1114 * @endpoint: which endpoint to extract packets from 1115 * @queue: a queue to store extracted packets in. 1116 * 1117 * Remove pm packets from the endpoint's tx queue and enqueue 1118 * them into a queue 1119 */ 1120 static void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, 1121 HTC_PACKET_QUEUE *queue) 1122 { 1123 HTC_PACKET *packet; 1124 1125 /* only WMI endpoint has power management packets */ 1126 if (endpoint->service_id != WMI_CONTROL_SVC) 1127 return; 1128 1129 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, 1130 HTC_PACKET, ListLink) { 1131 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_RESUME) { 1132 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); 1133 HTC_PACKET_ENQUEUE(queue, packet); 1134 } 1135 } ITERATE_END 1136 } 1137 #else 1138 static inline 1139 void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, 1140 HTC_PACKET_QUEUE *queue) 1141 { 1142 } 1143 #endif 1144 1145 /** 1146 * get_htc_send_packets_credit_based() - get packets based on available credits 1147 * @target: HTC target on which packets need to be sent 1148 * @pEndpoint: logical endpoint on which packets needs to be sent 1149 * @pQueue: HTC packet queue containing the list of packets to be sent 1150 * 1151 * Get HTC send packets from TX queue on an endpoint based on available credits. 1152 * The function moves the packets from TX queue of the endpoint to pQueue. 1153 * 1154 * Return: None 1155 */ 1156 static void get_htc_send_packets_credit_based(HTC_TARGET *target, 1157 HTC_ENDPOINT *pEndpoint, 1158 HTC_PACKET_QUEUE *pQueue) 1159 { 1160 int creditsRequired; 1161 int remainder; 1162 uint8_t sendFlags; 1163 HTC_PACKET *pPacket; 1164 unsigned int transferLength; 1165 HTC_PACKET_QUEUE *tx_queue; 1166 HTC_PACKET_QUEUE pm_queue; 1167 bool do_pm_get = false; 1168 unsigned int rtpm_code = 0; 1169 int ret; 1170 HTC_PACKET_QUEUE sys_pm_queue; 1171 bool sys_pm_check = false; 1172 1173 /*** NOTE : the TX lock is held when this function is called ***/ 1174 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1175 ("+get_htc_send_packets_credit_based\n")); 1176 1177 INIT_HTC_PACKET_QUEUE(&pm_queue); 1178 extract_htc_pm_packets(pEndpoint, &pm_queue); 1179 if (HTC_QUEUE_EMPTY(&pm_queue)) { 1180 do_pm_get = true; 1181 1182 INIT_HTC_PACKET_QUEUE(&sys_pm_queue); 1183 extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue); 1184 if (HTC_QUEUE_EMPTY(&sys_pm_queue)) { 1185 tx_queue = &pEndpoint->TxQueue; 1186 sys_pm_check = true; 1187 } else { 1188 tx_queue = &sys_pm_queue; 1189 } 1190 } else { 1191 tx_queue = &pm_queue; 1192 } 1193 1194 /* loop until we can grab as many packets out of the queue as we can */ 1195 while (true) { 1196 if (do_pm_get) { 1197 rtpm_code = htc_send_pkts_get_rtpm_id( 1198 pEndpoint->service_id); 1199 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code); 1200 if (ret) { 1201 /* bus suspended, runtime resume issued */ 1202 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 1203 pPacket = htc_get_pkt_at_head(tx_queue); 1204 if (!pPacket) 1205 break; 1206 log_packet_info(target, pPacket); 1207 break; 1208 } 1209 htc_inc_wmi_runtime_cnt(target, rtpm_code); 1210 } 1211 1212 sendFlags = 0; 1213 /* get packet at head, but don't remove it */ 1214 pPacket = htc_get_pkt_at_head(tx_queue); 1215 if (!pPacket) { 1216 if (do_pm_get) { 1217 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1218 htc_dec_wmi_runtime_cnt(target, rtpm_code); 1219 } 1220 break; 1221 } 1222 1223 if (sys_pm_check && 1224 hif_system_pm_state_check(target->hif_dev)) { 1225 if (do_pm_get) { 1226 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1227 htc_dec_wmi_runtime_cnt(target, rtpm_code); 1228 } 1229 break; 1230 } 1231 1232 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1233 (" Got head packet:%pK , Queue Depth: %d\n", 1234 pPacket, 1235 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 1236 1237 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; 1238 1239 if (transferLength <= pEndpoint->TxCreditSize) { 1240 creditsRequired = 1; 1241 } else { 1242 /* figure out how many credits this message requires */ 1243 creditsRequired = 1244 transferLength / pEndpoint->TxCreditSize; 1245 remainder = transferLength % pEndpoint->TxCreditSize; 1246 1247 if (remainder) 1248 creditsRequired++; 1249 } 1250 1251 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1252 (" Credits Required:%d Got:%d\n", 1253 creditsRequired, pEndpoint->TxCredits)); 1254 1255 if (pEndpoint->Id == ENDPOINT_0) { 1256 /* 1257 * endpoint 0 is special, it always has a credit and 1258 * does not require credit based flow control 1259 */ 1260 creditsRequired = 0; 1261 } else { 1262 1263 if (pEndpoint->TxCredits < creditsRequired) { 1264 #if DEBUG_CREDIT 1265 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1266 ("EP%d,No Credit now.%d < %d\n", 1267 pEndpoint->Id, 1268 pEndpoint->TxCredits, 1269 creditsRequired)); 1270 #endif 1271 if (do_pm_get) { 1272 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, 1273 rtpm_code); 1274 htc_dec_wmi_runtime_cnt(target, 1275 rtpm_code); 1276 } 1277 1278 break; 1279 } 1280 1281 pEndpoint->TxCredits -= creditsRequired; 1282 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, 1283 creditsRequired); 1284 1285 /* check if we need credits back from the target */ 1286 if (pEndpoint->TxCredits <= 1287 pEndpoint->TxCreditsPerMaxMsg) { 1288 /* tell the target we need credits ASAP! */ 1289 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; 1290 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 1291 htc_credit_record(HTC_REQUEST_CREDIT, 1292 pEndpoint->TxCredits, 1293 HTC_PACKET_QUEUE_DEPTH 1294 (tx_queue)); 1295 hif_latency_detect_credit_record_time( 1296 HIF_REQUEST_CREDIT, 1297 target->hif_dev); 1298 } 1299 INC_HTC_EP_STAT(pEndpoint, 1300 TxCreditLowIndications, 1); 1301 #if DEBUG_CREDIT 1302 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1303 (" EP%d Needs Credits\n", 1304 pEndpoint->Id)); 1305 #endif 1306 } 1307 } 1308 1309 /* now we can fully dequeue */ 1310 pPacket = htc_packet_dequeue(tx_queue); 1311 if (pPacket) { 1312 /* save the number of credits this packet consumed */ 1313 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; 1314 /* save send flags */ 1315 pPacket->PktInfo.AsTx.SendFlags = sendFlags; 1316 1317 /* queue this packet into the caller's queue */ 1318 HTC_PACKET_ENQUEUE(pQueue, pPacket); 1319 } 1320 } 1321 1322 if (!HTC_QUEUE_EMPTY(&pm_queue)) 1323 queue_htc_pm_packets(pEndpoint, &pm_queue); 1324 1325 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1326 ("-get_htc_send_packets_credit_based\n")); 1327 1328 } 1329 1330 static void get_htc_send_packets(HTC_TARGET *target, 1331 HTC_ENDPOINT *pEndpoint, 1332 HTC_PACKET_QUEUE *pQueue, int Resources) 1333 { 1334 1335 HTC_PACKET *pPacket; 1336 HTC_PACKET_QUEUE *tx_queue; 1337 HTC_PACKET_QUEUE pm_queue; 1338 bool do_pm_get = false; 1339 unsigned int rtpm_code = 0; 1340 int ret; 1341 1342 /*** NOTE : the TX lock is held when this function is called ***/ 1343 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1344 ("+get_htc_send_packets %d resources\n", Resources)); 1345 1346 INIT_HTC_PACKET_QUEUE(&pm_queue); 1347 extract_htc_pm_packets(pEndpoint, &pm_queue); 1348 if (HTC_QUEUE_EMPTY(&pm_queue)) { 1349 tx_queue = &pEndpoint->TxQueue; 1350 do_pm_get = true; 1351 } else { 1352 tx_queue = &pm_queue; 1353 } 1354 1355 /* loop until we can grab as many packets out of the queue as we can */ 1356 while (Resources > 0) { 1357 int num_frags; 1358 1359 if (do_pm_get) { 1360 rtpm_code = 1361 htc_send_pkts_get_rtpm_id( 1362 pEndpoint->service_id); 1363 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code); 1364 if (ret) { 1365 /* bus suspended, runtime resume issued */ 1366 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 1367 pPacket = htc_get_pkt_at_head(tx_queue); 1368 if (!pPacket) 1369 break; 1370 log_packet_info(target, pPacket); 1371 break; 1372 } 1373 htc_inc_wmi_runtime_cnt(target, rtpm_code); 1374 1375 } 1376 1377 ret = hif_system_pm_state_check(target->hif_dev); 1378 if (ret) { 1379 if (do_pm_get) { 1380 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1381 htc_dec_wmi_runtime_cnt(target, rtpm_code); 1382 } 1383 break; 1384 } 1385 1386 pPacket = htc_packet_dequeue(tx_queue); 1387 if (!pPacket) { 1388 if (do_pm_get) { 1389 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1390 htc_dec_wmi_runtime_cnt(target, rtpm_code); 1391 } 1392 break; 1393 } 1394 1395 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1396 (" Got packet:%pK , New Queue Depth: %d\n", 1397 pPacket, 1398 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 1399 /* For non-credit path the sequence number is already embedded 1400 * in the constructed HTC header 1401 */ 1402 pPacket->PktInfo.AsTx.SendFlags = 0; 1403 pPacket->PktInfo.AsTx.CreditsUsed = 0; 1404 /* queue this packet into the caller's queue */ 1405 HTC_PACKET_ENQUEUE(pQueue, pPacket); 1406 1407 /* 1408 * FIX THIS: 1409 * For now, avoid calling qdf_nbuf_get_num_frags before calling 1410 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't 1411 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has 1412 * been done. 1413 * Assume that the non-data netbufs, i.e. WMI message netbufs, 1414 * consist of a single fragment. 1415 */ 1416 /* WMI messages are in a single-fragment network buf */ 1417 num_frags = 1418 (pPacket->PktInfo.AsTx. 1419 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 : 1420 qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT 1421 (pPacket)); 1422 Resources -= num_frags; 1423 } 1424 1425 if (!HTC_QUEUE_EMPTY(&pm_queue)) 1426 queue_htc_pm_packets(pEndpoint, &pm_queue); 1427 1428 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n")); 1429 1430 } 1431 1432 /** 1433 * htc_try_send() - Send packets in a queue on an endpoint 1434 * @target: HTC target on which packets need to be sent 1435 * @pEndpoint: logical endpoint on which packets needs to be sent 1436 * @pCallersSendQueue: packet queue containing the list of packets to be sent 1437 * 1438 * Return: enum HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to 1439 * be sent or the packet should be dropped by the upper layer 1440 */ 1441 static enum HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target, 1442 HTC_ENDPOINT *pEndpoint, 1443 HTC_PACKET_QUEUE *pCallersSendQueue) 1444 { 1445 /* temp queue to hold packets at various stages */ 1446 HTC_PACKET_QUEUE sendQueue; 1447 HTC_PACKET *pPacket; 1448 int tx_resources; 1449 int overflow; 1450 enum HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; 1451 QDF_STATUS status; 1452 1453 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%pK Depth:%d)\n", 1454 pCallersSendQueue, 1455 (pCallersSendQueue == 1456 NULL) ? 0 : 1457 HTC_PACKET_QUEUE_DEPTH 1458 (pCallersSendQueue))); 1459 1460 /* init the local send queue */ 1461 INIT_HTC_PACKET_QUEUE(&sendQueue); 1462 1463 do { 1464 1465 /* caller didn't provide a queue, just wants us to check 1466 * queues and send 1467 */ 1468 if (!pCallersSendQueue) 1469 break; 1470 1471 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { 1472 /* empty queue */ 1473 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 1474 HTC_PKT_Q_EMPTY); 1475 result = HTC_SEND_QUEUE_DROP; 1476 break; 1477 } 1478 1479 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= 1480 pEndpoint->MaxTxQueueDepth) { 1481 /* we've already overflowed */ 1482 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 1483 } else { 1484 /* figure out how much we will overflow by */ 1485 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 1486 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 1487 /* get how much we will overflow the TX queue by */ 1488 overflow -= pEndpoint->MaxTxQueueDepth; 1489 } 1490 1491 /* if overflow is negative or zero, we are okay */ 1492 if (overflow > 0) { 1493 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1494 ("Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d\n", 1495 pEndpoint->Id, overflow, 1496 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 1497 TxQueue), 1498 pEndpoint->MaxTxQueueDepth)); 1499 } 1500 if ((overflow <= 0) 1501 || (!pEndpoint->EpCallBacks.EpSendFull)) { 1502 /* all packets will fit or caller did not provide send 1503 * full indication handler 1504 * just move all of them to local sendQueue object 1505 */ 1506 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, 1507 pCallersSendQueue); 1508 } else { 1509 int i; 1510 int goodPkts = 1511 HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - 1512 overflow; 1513 1514 A_ASSERT(goodPkts >= 0); 1515 /* we have overflowed and callback is provided. Dequeue 1516 * all non-overflow packets into the sendqueue 1517 */ 1518 for (i = 0; i < goodPkts; i++) { 1519 /* pop off caller's queue */ 1520 pPacket = htc_packet_dequeue(pCallersSendQueue); 1521 A_ASSERT(pPacket); 1522 if (pPacket) 1523 /* insert into local queue */ 1524 HTC_PACKET_ENQUEUE(&sendQueue, 1525 pPacket); 1526 } 1527 1528 /* the caller's queue has all the packets that won't fit 1529 * walk through the caller's queue and indicate each one 1530 * to the send full handler 1531 */ 1532 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue-> 1533 QueueHead, pPacket, 1534 HTC_PACKET, ListLink) { 1535 1536 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1537 ("Indicating overflowed TX packet: %pK\n", 1538 pPacket)); 1539 /* 1540 * Remove headroom reserved for HTC_FRAME_HDR 1541 * before giving the packet back to the user via 1542 * the EpSendFull callback. 1543 */ 1544 qdf_nbuf_pull_head 1545 (GET_HTC_PACKET_NET_BUF_CONTEXT 1546 (pPacket), 1547 sizeof(HTC_FRAME_HDR)); 1548 pPacket->PktInfo.AsTx.Flags &= 1549 ~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1550 1551 if (pEndpoint->EpCallBacks. 1552 EpSendFull(pEndpoint->EpCallBacks.pContext, 1553 pPacket) == HTC_SEND_FULL_DROP) { 1554 /* callback wants the packet dropped */ 1555 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1556 1); 1557 /* leave this one in the caller's queue 1558 * for cleanup 1559 */ 1560 } else { 1561 /* callback wants to keep this packet, 1562 * remove from caller's queue 1563 */ 1564 HTC_PACKET_REMOVE(pCallersSendQueue, 1565 pPacket); 1566 /* put it in the send queue 1567 * add HTC_FRAME_HDR space reservation 1568 * again 1569 */ 1570 qdf_nbuf_push_head 1571 (GET_HTC_PACKET_NET_BUF_CONTEXT 1572 (pPacket), 1573 sizeof(HTC_FRAME_HDR)); 1574 pPacket->PktInfo.AsTx.Flags |= 1575 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1576 1577 HTC_PACKET_ENQUEUE(&sendQueue, pPacket); 1578 } 1579 1580 } 1581 ITERATE_END; 1582 1583 if (HTC_QUEUE_EMPTY(&sendQueue)) { 1584 /* no packets made it in, caller will cleanup */ 1585 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 1586 HTC_SEND_Q_EMPTY); 1587 result = HTC_SEND_QUEUE_DROP; 1588 break; 1589 } 1590 } 1591 1592 } while (false); 1593 1594 if (result != HTC_SEND_QUEUE_OK) { 1595 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n", 1596 result)); 1597 return result; 1598 } 1599 1600 LOCK_HTC_TX(target); 1601 1602 if (!HTC_QUEUE_EMPTY(&sendQueue)) { 1603 if (target->is_nodrop_pkt) { 1604 /* 1605 * nodrop pkts have higher priority than normal pkts, 1606 * insert nodrop pkt to head for proper 1607 * start/termination of test. 1608 */ 1609 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1610 &sendQueue); 1611 target->is_nodrop_pkt = false; 1612 } else { 1613 /* transfer packets to tail */ 1614 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue, 1615 &sendQueue); 1616 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); 1617 INIT_HTC_PACKET_QUEUE(&sendQueue); 1618 } 1619 } 1620 1621 /* increment tx processing count on entry */ 1622 if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) { 1623 /* another thread or task is draining the TX queues on this 1624 * endpoint that thread will reset the tx processing count when 1625 * the queue is drained 1626 */ 1627 qdf_atomic_dec(&pEndpoint->TxProcessCount); 1628 UNLOCK_HTC_TX(target); 1629 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy)\n")); 1630 return HTC_SEND_QUEUE_OK; 1631 } 1632 1633 /***** beyond this point only 1 thread may enter ******/ 1634 1635 /* now drain the endpoint TX queue for transmission as long as we have 1636 * enough transmit resources 1637 */ 1638 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1639 tx_resources = 1640 hif_get_free_queue_number(target->hif_dev, 1641 pEndpoint->UL_PipeID); 1642 } else { 1643 tx_resources = 0; 1644 } 1645 1646 while (true) { 1647 1648 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) 1649 break; 1650 1651 if (pEndpoint->async_update && 1652 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) && 1653 (!tx_resources)) { 1654 hif_schedule_ce_tasklet(target->hif_dev, 1655 pEndpoint->UL_PipeID); 1656 break; 1657 } 1658 1659 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1660 #if DEBUG_CREDIT 1661 int cred = pEndpoint->TxCredits; 1662 #endif 1663 /* credit based mechanism provides flow control based on 1664 * target transmit resource availability, we assume that 1665 * the HIF layer will always have bus resources greater 1666 * than target transmit resources 1667 */ 1668 get_htc_send_packets_credit_based(target, pEndpoint, 1669 &sendQueue); 1670 #if DEBUG_CREDIT 1671 if (ep_debug_mask & (1 << pEndpoint->Id)) { 1672 if (cred - pEndpoint->TxCredits > 0) { 1673 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1674 (" <HTC> Decrease EP%d %d - %d = %d credits.\n", 1675 pEndpoint->Id, cred, 1676 cred - 1677 pEndpoint->TxCredits, 1678 pEndpoint->TxCredits)); 1679 } 1680 } 1681 #endif 1682 } else { 1683 1684 /* 1685 * Header and payload belongs to the different fragments and 1686 * consume 2 resource for one HTC package but USB combine into 1687 * one transfer.And one WMI message only consumes one single 1688 * resource. 1689 */ 1690 if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources && 1691 hif_get_bus_type(target->hif_dev) == 1692 QDF_BUS_TYPE_USB) { 1693 if (pEndpoint->service_id == 1694 WMI_CONTROL_SVC) 1695 tx_resources = 1696 HTC_MAX_MSG_PER_BUNDLE_TX; 1697 else 1698 tx_resources = 1699 (HTC_MAX_MSG_PER_BUNDLE_TX * 2); 1700 } 1701 /* get all the packets for this endpoint that we can for 1702 * this pass 1703 */ 1704 get_htc_send_packets(target, pEndpoint, &sendQueue, 1705 tx_resources); 1706 } 1707 1708 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { 1709 /* didn't get any packets due to a lack of resources or 1710 * TX queue was drained 1711 */ 1712 break; 1713 } 1714 1715 if (!pEndpoint->async_update) 1716 UNLOCK_HTC_TX(target); 1717 1718 /* send what we can */ 1719 status = htc_issue_packets(target, pEndpoint, &sendQueue); 1720 if (status) { 1721 int i; 1722 unsigned int rtpm_code; 1723 1724 result = HTC_SEND_QUEUE_DROP; 1725 1726 switch (status) { 1727 case QDF_STATUS_E_RESOURCES: 1728 if (pEndpoint->num_requeues_warn <= MAX_REQUEUE_WARN) { 1729 pEndpoint->num_requeues_warn++; 1730 pEndpoint->total_num_requeues++; 1731 break; 1732 } else { 1733 pEndpoint->total_num_requeues++; 1734 pEndpoint->num_requeues_warn = 0; 1735 } 1736 fallthrough; 1737 default: 1738 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, 1739 "htc_issue_packets, failed status:%d" 1740 "endpoint:%d, put it back to head of" 1741 "callersSendQueue", result, pEndpoint->Id); 1742 break; 1743 } 1744 1745 rtpm_code = htc_send_pkts_get_rtpm_id( 1746 pEndpoint->service_id); 1747 for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) { 1748 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1749 htc_dec_wmi_runtime_cnt(target, rtpm_code); 1750 } 1751 1752 if (!pEndpoint->async_update) { 1753 LOCK_HTC_TX(target); 1754 } 1755 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1756 &sendQueue); 1757 break; 1758 } else { 1759 if (pEndpoint->num_requeues_warn) 1760 pEndpoint->num_requeues_warn = 0; 1761 } 1762 1763 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1764 tx_resources = 1765 hif_get_free_queue_number(target->hif_dev, 1766 pEndpoint->UL_PipeID); 1767 } 1768 1769 if (!pEndpoint->async_update) { 1770 LOCK_HTC_TX(target); 1771 } 1772 1773 } 1774 1775 /* done with this endpoint, we can clear the count */ 1776 qdf_atomic_init(&pEndpoint->TxProcessCount); 1777 1778 UNLOCK_HTC_TX(target); 1779 1780 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send:\n")); 1781 1782 return HTC_SEND_QUEUE_OK; 1783 } 1784 1785 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1786 static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, 1787 HTC_ENDPOINT_ID id) 1788 { 1789 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1790 HTC_ENDPOINT *pEndpoint; 1791 HTC_ENDPOINT_ID eid; 1792 HTC_PACKET_QUEUE *pTxQueue; 1793 uint16_t resources; 1794 uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 }; 1795 1796 if (id < ENDPOINT_2 || id > ENDPOINT_5) 1797 return 1; 1798 1799 for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) { 1800 pEndpoint = &target->endpoint[eid]; 1801 pTxQueue = &pEndpoint->TxQueue; 1802 1803 if (HTC_QUEUE_EMPTY(pTxQueue)) 1804 acQueueStatus[eid - 2] = 1; 1805 } 1806 1807 switch (id) { 1808 case ENDPOINT_2: /* BE */ 1809 return acQueueStatus[0] && acQueueStatus[2] 1810 && acQueueStatus[3]; 1811 case ENDPOINT_3: /* BK */ 1812 return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2] 1813 && acQueueStatus[3]; 1814 case ENDPOINT_4: /* VI */ 1815 return acQueueStatus[2] && acQueueStatus[3]; 1816 case ENDPOINT_5: /* VO */ 1817 return acQueueStatus[3]; 1818 default: 1819 return 0; 1820 } 1821 1822 } 1823 1824 static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target, 1825 HTC_PACKET_QUEUE *pPktQueue, 1826 HTC_ENDPOINT_ID eid) 1827 { 1828 HTC_ENDPOINT *pEndpoint; 1829 HTC_PACKET_QUEUE *pTxQueue; 1830 HTC_PACKET *pPacket; 1831 int goodPkts; 1832 1833 pEndpoint = &target->endpoint[eid]; 1834 pTxQueue = &pEndpoint->TxQueue; 1835 1836 LOCK_HTC_TX(target); 1837 1838 goodPkts = 1839 pEndpoint->MaxTxQueueDepth - 1840 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 1841 1842 if (goodPkts > 0) { 1843 while (!HTC_QUEUE_EMPTY(pPktQueue)) { 1844 pPacket = htc_packet_dequeue(pPktQueue); 1845 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1846 goodPkts--; 1847 1848 if (goodPkts <= 0) 1849 break; 1850 } 1851 } 1852 1853 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) { 1854 ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket, 1855 HTC_PACKET, ListLink) { 1856 1857 if (pEndpoint->EpCallBacks. 1858 EpSendFull(pEndpoint->EpCallBacks.pContext, 1859 pPacket) == HTC_SEND_FULL_DROP) { 1860 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); 1861 } else { 1862 HTC_PACKET_REMOVE(pPktQueue, pPacket); 1863 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1864 } 1865 } 1866 ITERATE_END; 1867 } 1868 1869 UNLOCK_HTC_TX(target); 1870 1871 return A_OK; 1872 } 1873 1874 #endif 1875 1876 static inline QDF_STATUS __htc_send_pkt(HTC_HANDLE HTCHandle, 1877 HTC_PACKET *pPacket) 1878 { 1879 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1880 HTC_ENDPOINT *pEndpoint; 1881 HTC_PACKET_QUEUE pPktQueue; 1882 qdf_nbuf_t netbuf; 1883 HTC_FRAME_HDR *htc_hdr; 1884 QDF_STATUS status; 1885 1886 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1887 ("+__htc_send_pkt\n")); 1888 1889 /* get packet at head to figure out which endpoint these packets will 1890 * go into 1891 */ 1892 if (!pPacket) { 1893 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL); 1894 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1895 return QDF_STATUS_E_INVAL; 1896 } 1897 1898 if ((pPacket->Endpoint >= ENDPOINT_MAX) || 1899 (pPacket->Endpoint <= ENDPOINT_UNUSED)) { 1900 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1901 ("%s endpoint is invalid\n", __func__)); 1902 AR_DEBUG_ASSERT(0); 1903 return QDF_STATUS_E_INVAL; 1904 } 1905 pEndpoint = &target->endpoint[pPacket->Endpoint]; 1906 1907 if (!pEndpoint->service_id) { 1908 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n", 1909 __func__)); 1910 return QDF_STATUS_E_INVAL; 1911 } 1912 1913 #ifdef HTC_EP_STAT_PROFILING 1914 LOCK_HTC_TX(target); 1915 INC_HTC_EP_STAT(pEndpoint, TxPosted, 1); 1916 UNLOCK_HTC_TX(target); 1917 #endif 1918 1919 /* provide room in each packet's netbuf for the HTC frame header */ 1920 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 1921 AR_DEBUG_ASSERT(netbuf); 1922 if (!netbuf) 1923 return QDF_STATUS_E_INVAL; 1924 1925 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); 1926 pPacket->PktInfo.AsTx.Flags |= 1927 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1928 /* setup HTC frame header */ 1929 htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 1930 AR_DEBUG_ASSERT(htc_hdr); 1931 if (!htc_hdr) 1932 return QDF_STATUS_E_INVAL; 1933 1934 HTC_WRITE32(htc_hdr, 1935 SM(pPacket->ActualLength, 1936 HTC_FRAME_HDR_PAYLOADLEN) | 1937 SM(pPacket->Endpoint, 1938 HTC_FRAME_HDR_ENDPOINTID)); 1939 LOCK_HTC_TX(target); 1940 1941 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; 1942 pEndpoint->SeqNo++; 1943 1944 HTC_WRITE32(((uint32_t *)htc_hdr) + 1, 1945 SM(pPacket->PktInfo.AsTx.SeqNo, 1946 HTC_FRAME_HDR_CONTROLBYTES1)); 1947 1948 UNLOCK_HTC_TX(target); 1949 1950 /* 1951 * For flow control enabled endpoints mapping is done in 1952 * htc_issue_packets and for non flow control enabled endpoints 1953 * its done here. 1954 */ 1955 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1956 pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 1957 status = qdf_nbuf_map(target->osdev, 1958 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 1959 QDF_DMA_TO_DEVICE); 1960 if (status == QDF_STATUS_SUCCESS) { 1961 target->nbuf_nfc_map_count++; 1962 } else { 1963 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1964 ("%s: nbuf map failed, endpoint %pK, seq_no. %d\n", 1965 __func__, pEndpoint, pEndpoint->SeqNo)); 1966 return status; 1967 } 1968 } 1969 1970 INIT_HTC_PACKET_QUEUE_AND_ADD(&pPktQueue, pPacket); 1971 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1972 if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) 1973 htc_send_pkts_sched_queue(HTCHandle, &pPktQueue, pEndpoint->Id); 1974 else 1975 htc_try_send(target, pEndpoint, &pPktQueue); 1976 #else 1977 htc_try_send(target, pEndpoint, &pPktQueue); 1978 #endif 1979 1980 /* do completion on any packets that couldn't get in */ 1981 while (!HTC_QUEUE_EMPTY(&pPktQueue)) { 1982 pPacket = htc_packet_dequeue(&pPktQueue); 1983 1984 if (HTC_STOPPING(target)) 1985 pPacket->Status = QDF_STATUS_E_CANCELED; 1986 else 1987 pPacket->Status = QDF_STATUS_E_RESOURCES; 1988 1989 send_packet_completion(target, pPacket); 1990 } 1991 1992 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1993 1994 return QDF_STATUS_SUCCESS; 1995 } 1996 1997 /* HTC API - htc_send_pkt */ 1998 QDF_STATUS htc_send_pkt(HTC_HANDLE htc_handle, HTC_PACKET *htc_packet) 1999 { 2000 if (!htc_handle) { 2001 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2002 ("%s: HTCHandle is NULL \n", __func__)); 2003 return QDF_STATUS_E_FAILURE; 2004 } 2005 2006 if (!htc_packet) { 2007 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2008 ("%s: pPacket is NULL \n", __func__)); 2009 return QDF_STATUS_E_FAILURE; 2010 } 2011 2012 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2013 ("+-htc_send_pkt: Enter endPointId: %d, buffer: %pK, length: %d\n", 2014 htc_packet->Endpoint, htc_packet->pBuffer, 2015 htc_packet->ActualLength)); 2016 return __htc_send_pkt(htc_handle, htc_packet); 2017 } 2018 qdf_export_symbol(htc_send_pkt); 2019 2020 #ifdef ATH_11AC_TXCOMPACT 2021 /** 2022 * htc_send_data_pkt() - send single data packet on an endpoint 2023 * @HTCHandle: pointer to HTC handle 2024 * @netbuf: network buffer containing the data to be sent 2025 * @ActualLength: length of data that needs to be transmitted 2026 * 2027 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 2028 */ 2029 QDF_STATUS htc_send_data_pkt(HTC_HANDLE htc_hdl, qdf_nbuf_t netbuf, int ep_id, 2030 int actual_length) 2031 { 2032 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl); 2033 HTC_ENDPOINT *pEndpoint; 2034 HTC_FRAME_HDR *p_htc_hdr; 2035 QDF_STATUS status = QDF_STATUS_SUCCESS; 2036 int tx_resources; 2037 uint32_t data_attr = 0; 2038 int htc_payload_len = actual_length; 2039 unsigned int rtpm_code; 2040 2041 pEndpoint = &target->endpoint[ep_id]; 2042 2043 tx_resources = hif_get_free_queue_number(target->hif_dev, 2044 pEndpoint->UL_PipeID); 2045 2046 if (tx_resources < HTC_DATA_RESOURCE_THRS) { 2047 if (pEndpoint->ul_is_polled) { 2048 hif_send_complete_check(pEndpoint->target->hif_dev, 2049 pEndpoint->UL_PipeID, 1); 2050 tx_resources = 2051 hif_get_free_queue_number(target->hif_dev, 2052 pEndpoint->UL_PipeID); 2053 } 2054 if (tx_resources < HTC_DATA_MINDESC_PERPACKET) 2055 return QDF_STATUS_E_FAILURE; 2056 } 2057 2058 rtpm_code = htc_send_pkts_get_rtpm_id( 2059 pEndpoint->service_id); 2060 if (hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code)) 2061 return QDF_STATUS_E_FAILURE; 2062 2063 p_htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 2064 AR_DEBUG_ASSERT(p_htc_hdr); 2065 2066 data_attr = qdf_nbuf_data_attr_get(netbuf); 2067 2068 if (target->htc_hdr_length_check) 2069 htc_payload_len = actual_length - HTC_HEADER_LEN; 2070 2071 HTC_WRITE32(p_htc_hdr, SM(htc_payload_len, HTC_FRAME_HDR_PAYLOADLEN) 2072 | SM(ep_id, HTC_FRAME_HDR_ENDPOINTID)); 2073 /* 2074 * If the HIF pipe for the data endpoint is polled rather than 2075 * interrupt-driven, this is a good point to check whether any 2076 * data previously sent through the HIF pipe have finished being 2077 * sent. 2078 * Since this may result in callbacks to htc_tx_completion_handler, 2079 * which can take the HTC tx lock, make the hif_send_complete_check 2080 * call before acquiring the HTC tx lock. 2081 * Call hif_send_complete_check directly, rather than calling 2082 * htc_send_complete_check, and call the PollTimerStart separately 2083 * after calling hif_send_head, so the timer will be started to 2084 * check for completion of the new outstanding download (in the 2085 * unexpected event that other polling calls don't catch it). 2086 */ 2087 2088 LOCK_HTC_TX(target); 2089 2090 HTC_WRITE32(((uint32_t *)p_htc_hdr) + 1, 2091 SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1)); 2092 2093 pEndpoint->SeqNo++; 2094 2095 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); 2096 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 2097 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf), 2098 sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); 2099 status = hif_send_head(target->hif_dev, 2100 pEndpoint->UL_PipeID, 2101 pEndpoint->Id, actual_length, netbuf, data_attr); 2102 2103 UNLOCK_HTC_TX(target); 2104 return status; 2105 } 2106 #else /*ATH_11AC_TXCOMPACT */ 2107 2108 /** 2109 * htc_send_data_pkt() - htc_send_data_pkt 2110 * @HTCHandle: pointer to HTC handle 2111 * @pPacket: pointer to HTC_PACKET 2112 * @more_data: indicates whether more data is to follow 2113 * 2114 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 2115 */ 2116 QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, 2117 uint8_t more_data) 2118 { 2119 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2120 HTC_ENDPOINT *pEndpoint; 2121 HTC_FRAME_HDR *pHtcHdr; 2122 HTC_PACKET_QUEUE sendQueue; 2123 qdf_nbuf_t netbuf = NULL; 2124 int tx_resources; 2125 QDF_STATUS status = QDF_STATUS_SUCCESS; 2126 uint32_t data_attr = 0; 2127 bool used_extra_tx_credit = false; 2128 2129 if (pPacket) { 2130 if ((pPacket->Endpoint >= ENDPOINT_MAX) || 2131 (pPacket->Endpoint <= ENDPOINT_UNUSED)) { 2132 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2133 ("%s endpoint is invalid\n", __func__)); 2134 AR_DEBUG_ASSERT(0); 2135 return QDF_STATUS_E_INVAL; 2136 } 2137 pEndpoint = &target->endpoint[pPacket->Endpoint]; 2138 2139 /* add HTC_FRAME_HDR in the initial fragment */ 2140 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 2141 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); 2142 AR_DEBUG_ASSERT(pHtcHdr); 2143 2144 HTC_WRITE32(pHtcHdr, 2145 SM(pPacket->ActualLength, 2146 HTC_FRAME_HDR_PAYLOADLEN) | 2147 SM(pPacket->PktInfo.AsTx.SendFlags, 2148 HTC_FRAME_HDR_FLAGS) | 2149 SM(pPacket->Endpoint, 2150 HTC_FRAME_HDR_ENDPOINTID)); 2151 /* 2152 * If the HIF pipe for the data endpoint is polled rather than 2153 * interrupt-driven, this is a good point to check whether any 2154 * data previously sent through the HIF pipe have finished being 2155 * sent. Since this may result in callbacks to 2156 * htc_tx_completion_handler, which can take the HTC tx lock, 2157 * make the hif_send_complete_check call before acquiring the 2158 * HTC tx lock. 2159 * Call hif_send_complete_check directly, rather than calling 2160 * htc_send_complete_check, and call the PollTimerStart 2161 * separately after calling hif_send_head, so the timer will be 2162 * started to check for completion of the new outstanding 2163 * download (in the unexpected event that other polling calls 2164 * don't catch it). 2165 */ 2166 if (pEndpoint->ul_is_polled) { 2167 htc_send_complete_poll_timer_stop(pEndpoint); 2168 hif_send_complete_check(pEndpoint->target->hif_dev, 2169 pEndpoint->UL_PipeID, 0); 2170 } 2171 2172 LOCK_HTC_TX(target); 2173 2174 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; 2175 pEndpoint->SeqNo++; 2176 2177 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, 2178 SM(pPacket->PktInfo.AsTx.SeqNo, 2179 HTC_FRAME_HDR_CONTROLBYTES1)); 2180 2181 /* append new packet to pEndpoint->TxQueue */ 2182 HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket); 2183 if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) { 2184 UNLOCK_HTC_TX(target); 2185 return QDF_STATUS_SUCCESS; 2186 } 2187 2188 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); 2189 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 2190 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf), 2191 sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); 2192 } else { 2193 LOCK_HTC_TX(target); 2194 pEndpoint = &target->endpoint[1]; 2195 } 2196 2197 /* increment tx processing count on entry */ 2198 qdf_atomic_inc(&pEndpoint->TxProcessCount); 2199 if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) { 2200 /* 2201 * Another thread or task is draining the TX queues on this 2202 * endpoint. That thread will reset the tx processing count when 2203 * the queue is drained. 2204 */ 2205 qdf_atomic_dec(&pEndpoint->TxProcessCount); 2206 UNLOCK_HTC_TX(target); 2207 return QDF_STATUS_SUCCESS; 2208 } 2209 2210 /***** beyond this point only 1 thread may enter ******/ 2211 2212 INIT_HTC_PACKET_QUEUE(&sendQueue); 2213 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 2214 #if DEBUG_CREDIT 2215 int cred = pEndpoint->TxCredits; 2216 #endif 2217 get_htc_send_packets_credit_based(target, pEndpoint, 2218 &sendQueue); 2219 #if DEBUG_CREDIT 2220 if (ep_debug_mask & (1 << pEndpoint->Id)) { 2221 if (cred - pEndpoint->TxCredits > 0) { 2222 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2223 (" <HTC> Decrease EP%d %d - %d = %d credits.\n", 2224 pEndpoint->Id, cred, 2225 cred - pEndpoint->TxCredits, 2226 pEndpoint->TxCredits)); 2227 } 2228 } 2229 #endif 2230 UNLOCK_HTC_TX(target); 2231 } 2232 2233 else if (HTC_TX_BUNDLE_ENABLED(target)) { 2234 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) { 2235 if (hif_get_free_queue_number(target->hif_dev, 2236 pEndpoint->UL_PipeID)) 2237 /* 2238 * Header and payload belongs to the different 2239 * fragments and consume 2 resource for one HTC 2240 * package but USB combine into one transfer. 2241 */ 2242 get_htc_send_packets(target, pEndpoint, 2243 &sendQueue, 2244 HTC_MAX_MSG_PER_BUNDLE_TX 2245 * 2); 2246 } else { 2247 /* Dequeue max packets from endpoint tx queue */ 2248 get_htc_send_packets(target, pEndpoint, &sendQueue, 2249 HTC_MAX_TX_BUNDLE_SEND_LIMIT); 2250 } 2251 UNLOCK_HTC_TX(target); 2252 } else { 2253 /* 2254 * Now drain the endpoint TX queue for transmission as long as 2255 * we have enough transmit resources 2256 */ 2257 tx_resources = 2258 hif_get_free_queue_number(target->hif_dev, 2259 pEndpoint->UL_PipeID); 2260 get_htc_send_packets(target, pEndpoint, &sendQueue, 2261 tx_resources); 2262 UNLOCK_HTC_TX(target); 2263 } 2264 2265 /* send what we can */ 2266 while (true) { 2267 if (HTC_TX_BUNDLE_ENABLED(target) && 2268 (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= 2269 HTC_MIN_MSG_PER_BUNDLE) && 2270 (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO || 2271 hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) { 2272 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2273 if (htc_tx_pad_credit_avail(pEndpoint) < 1) { 2274 status = QDF_STATUS_E_RESOURCES; 2275 /* put the sendQueue back at the front 2276 * of pEndpoint->TxQueue 2277 */ 2278 LOCK_HTC_TX(target); 2279 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD( 2280 &pEndpoint->TxQueue, 2281 &sendQueue); 2282 UNLOCK_HTC_TX(target); 2283 break; 2284 } 2285 } 2286 htc_issue_packets_bundle(target, pEndpoint, &sendQueue); 2287 } 2288 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2289 if (htc_tx_pad_credit_avail(pEndpoint) < 1) { 2290 status = QDF_STATUS_E_RESOURCES; 2291 /* put the sendQueue back at the front 2292 * of pEndpoint->TxQueue 2293 */ 2294 LOCK_HTC_TX(target); 2295 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD( 2296 &pEndpoint->TxQueue, 2297 &sendQueue); 2298 UNLOCK_HTC_TX(target); 2299 break; 2300 } 2301 } 2302 pPacket = htc_packet_dequeue(&sendQueue); 2303 if (!pPacket) 2304 break; 2305 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 2306 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 2307 2308 LOCK_HTC_TX(target); 2309 /* store in look up queue to match completions */ 2310 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); 2311 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); 2312 pEndpoint->ul_outstanding_cnt++; 2313 UNLOCK_HTC_TX(target); 2314 2315 used_extra_tx_credit = 2316 htc_handle_extra_tx_credit(pEndpoint, pPacket, 2317 (uint8_t *)pHtcHdr, 2318 NULL, 2319 pPacket->ActualLength 2320 + HTC_HDR_LENGTH); 2321 2322 status = hif_send_head(target->hif_dev, 2323 pEndpoint->UL_PipeID, 2324 pEndpoint->Id, 2325 HTC_HDR_LENGTH + pPacket->ActualLength, 2326 netbuf, data_attr); 2327 if (status != QDF_STATUS_SUCCESS) { 2328 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2329 if (used_extra_tx_credit) { 2330 pEndpoint->EpCallBacks. 2331 ep_padding_credit_update 2332 (pEndpoint->EpCallBacks.pContext, 1); 2333 } 2334 } 2335 } 2336 #if DEBUG_BUNDLE 2337 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.", 2338 pEndpoint->Id, 2339 pEndpoint->TxCreditSize, 2340 HTC_HDR_LENGTH + pPacket->ActualLength); 2341 #endif 2342 2343 htc_issue_tx_bundle_stats_inc(target); 2344 2345 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 2346 LOCK_HTC_TX(target); 2347 pEndpoint->ul_outstanding_cnt--; 2348 /* remove this packet from the tx completion queue */ 2349 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); 2350 2351 /* 2352 * Don't bother reclaiming credits - HTC flow control 2353 * is not applicable to tx data. 2354 * In LL systems, there is no download flow control, 2355 * since there's virtually no download delay. 2356 * In HL systems, the txrx SW explicitly performs the 2357 * tx flow control. 2358 */ 2359 /* pEndpoint->TxCredits += 2360 * pPacket->PktInfo.AsTx.CreditsUsed; 2361 */ 2362 2363 /* put this frame back at the front of the sendQueue */ 2364 HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket); 2365 2366 /* put the sendQueue back at the front of 2367 * pEndpoint->TxQueue 2368 */ 2369 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 2370 &sendQueue); 2371 UNLOCK_HTC_TX(target); 2372 break; /* still need to reset TxProcessCount */ 2373 } 2374 } 2375 /* done with this endpoint, we can clear the count */ 2376 qdf_atomic_init(&pEndpoint->TxProcessCount); 2377 2378 if (pEndpoint->ul_is_polled) { 2379 /* 2380 * Start a cleanup timer to poll for download completion. 2381 * The download completion should be noticed promptly from 2382 * other polling calls, but the timer provides a safety net 2383 * in case other polling calls don't occur as expected. 2384 */ 2385 htc_send_complete_poll_timer_start(pEndpoint); 2386 } 2387 2388 return status; 2389 } 2390 #endif /*ATH_11AC_TXCOMPACT */ 2391 qdf_export_symbol(htc_send_data_pkt); 2392 2393 /* 2394 * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC, 2395 * since upper layers expects HTC_PACKET containers we use the completed netbuf 2396 * and lookup its corresponding HTC packet buffer from a lookup list. 2397 * This is extra overhead that can be fixed by re-aligning HIF interfaces 2398 * with HTC. 2399 * 2400 */ 2401 static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, 2402 HTC_ENDPOINT *pEndpoint, 2403 qdf_nbuf_t netbuf) 2404 { 2405 HTC_PACKET *pPacket = NULL; 2406 HTC_PACKET *pFoundPacket = NULL; 2407 HTC_PACKET_QUEUE lookupQueue; 2408 2409 INIT_HTC_PACKET_QUEUE(&lookupQueue); 2410 LOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2411 2412 LOCK_HTC_TX(target); 2413 /* mark that HIF has indicated the send complete for another packet */ 2414 pEndpoint->ul_outstanding_cnt--; 2415 2416 /* Dequeue first packet directly because of in-order completion */ 2417 pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue); 2418 if (qdf_unlikely(!pPacket)) { 2419 UNLOCK_HTC_TX(target); 2420 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2421 return NULL; 2422 } 2423 if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { 2424 UNLOCK_HTC_TX(target); 2425 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2426 return pPacket; 2427 } 2428 HTC_PACKET_ENQUEUE(&lookupQueue, pPacket); 2429 2430 /* 2431 * Move TX lookup queue to temp queue because most of packets that are 2432 * not index 0 are not top 10 packets. 2433 */ 2434 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue, 2435 &pEndpoint->TxLookupQueue); 2436 2437 ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket, 2438 HTC_PACKET, ListLink) { 2439 2440 if (!pPacket) { 2441 pFoundPacket = pPacket; 2442 break; 2443 } 2444 /* check for removal */ 2445 if (netbuf == 2446 (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { 2447 /* found it */ 2448 HTC_PACKET_REMOVE(&lookupQueue, pPacket); 2449 pFoundPacket = pPacket; 2450 break; 2451 } 2452 2453 } 2454 ITERATE_END; 2455 2456 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue, 2457 &lookupQueue); 2458 UNLOCK_HTC_TX(target); 2459 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2460 2461 return pFoundPacket; 2462 } 2463 2464 /** 2465 * htc_tx_completion_handler() - htc tx completion handler 2466 * @Context: pointer to HTC_TARGET structure 2467 * @netbuf: pointer to netbuf for which completion handler is being called 2468 * @EpID: end point Id on which the packet was sent 2469 * @toeplitz_hash_result: toeplitz hash result 2470 * 2471 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 2472 */ 2473 QDF_STATUS htc_tx_completion_handler(void *Context, 2474 qdf_nbuf_t netbuf, unsigned int EpID, 2475 uint32_t toeplitz_hash_result) 2476 { 2477 HTC_TARGET *target = (HTC_TARGET *) Context; 2478 HTC_ENDPOINT *pEndpoint; 2479 HTC_PACKET *pPacket; 2480 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 2481 HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4, 2482 ENDPOINT_2, ENDPOINT_3 }; 2483 int epidIdx; 2484 uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */ 2485 uint16_t resources; 2486 uint16_t resourcesMax; 2487 #endif 2488 2489 pEndpoint = &target->endpoint[EpID]; 2490 target->TX_comp_cnt++; 2491 pEndpoint->htc_comp_cnt++; 2492 2493 do { 2494 pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf); 2495 if (!pPacket) { 2496 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2497 ("HTC TX lookup failed!\n")); 2498 /* may have already been flushed and freed */ 2499 netbuf = NULL; 2500 break; 2501 } 2502 if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM && 2503 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RUNTIME_PUT && 2504 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RTPM_PUT_RC) { 2505 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_WMI); 2506 htc_dec_wmi_runtime_cnt(target, HIF_RTPM_ID_WMI); 2507 } 2508 2509 2510 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) { 2511 HTC_PACKET *pPacketTemp; 2512 HTC_PACKET_QUEUE *pQueueSave = 2513 (HTC_PACKET_QUEUE *) pPacket->pContext; 2514 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave, 2515 pPacketTemp) { 2516 pPacket->Status = QDF_STATUS_SUCCESS; 2517 send_packet_completion(target, pPacketTemp); 2518 } 2519 HTC_PACKET_QUEUE_ITERATE_END; 2520 free_htc_bundle_packet(target, pPacket); 2521 2522 if (hif_get_bus_type(target->hif_dev) == 2523 QDF_BUS_TYPE_USB) { 2524 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) 2525 htc_try_send(target, pEndpoint, NULL); 2526 } 2527 2528 return QDF_STATUS_SUCCESS; 2529 } 2530 /* will be giving this buffer back to upper layers */ 2531 netbuf = NULL; 2532 pPacket->Status = QDF_STATUS_SUCCESS; 2533 send_packet_completion(target, pPacket); 2534 2535 } while (false); 2536 2537 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 2538 /* note: when using TX credit flow, the re-checking of queues 2539 * happens when credits flow back from the target. In the non-TX 2540 * credit case, we recheck after the packet completes 2541 */ 2542 if ((qdf_atomic_read(&pEndpoint->TxProcessCount) == 0) || 2543 (!pEndpoint->async_update)) { 2544 htc_try_send(target, pEndpoint, NULL); 2545 } 2546 } 2547 2548 return QDF_STATUS_SUCCESS; 2549 } 2550 2551 #ifdef WLAN_FEATURE_FASTPATH 2552 /** 2553 * htc_ctrl_msg_cmpl(): checks for tx completion for the endpoint specified 2554 * @HTC_HANDLE : pointer to the htc target context 2555 * @htc_ep_id : end point id 2556 * 2557 * checks HTC tx completion 2558 * 2559 * Return: none 2560 */ 2561 void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id) 2562 { 2563 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev); 2564 HTC_ENDPOINT *pendpoint = &target->endpoint[htc_ep_id]; 2565 2566 htc_send_complete_check(pendpoint, 1); 2567 } 2568 qdf_export_symbol(htc_ctrl_msg_cmpl); 2569 #endif 2570 2571 /* callback when TX resources become available */ 2572 void htc_tx_resource_avail_handler(void *context, uint8_t pipeID) 2573 { 2574 int i; 2575 HTC_TARGET *target = (HTC_TARGET *) context; 2576 HTC_ENDPOINT *pEndpoint = NULL; 2577 2578 for (i = 0; i < ENDPOINT_MAX; i++) { 2579 pEndpoint = &target->endpoint[i]; 2580 if (pEndpoint->service_id != 0) { 2581 if (pEndpoint->UL_PipeID == pipeID) 2582 break; 2583 } 2584 } 2585 2586 if (i >= ENDPOINT_MAX) { 2587 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2588 ("Invalid pipe indicated for TX resource avail : %d!\n", 2589 pipeID)); 2590 return; 2591 } 2592 2593 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2594 ("HIF indicated more resources for pipe:%d\n", 2595 pipeID)); 2596 2597 htc_try_send(target, pEndpoint, NULL); 2598 } 2599 2600 #ifdef FEATURE_RUNTIME_PM 2601 /** 2602 * htc_kick_queues(): resumes tx transactions of suspended endpoints 2603 * @context: pointer to the htc target context 2604 * 2605 * Iterates through the endpoints and provides a context to empty queues 2606 * int the hif layer when they are stalled due to runtime suspend. 2607 * 2608 * Return: none 2609 */ 2610 void htc_kick_queues(void *context) 2611 { 2612 int i; 2613 HTC_TARGET *target = (HTC_TARGET *)context; 2614 HTC_ENDPOINT *endpoint = NULL; 2615 2616 if (hif_rtpm_get(HIF_RTPM_GET_SYNC, HIF_RTPM_ID_HTT)) 2617 return; 2618 2619 for (i = 0; i < ENDPOINT_MAX; i++) { 2620 endpoint = &target->endpoint[i]; 2621 2622 if (endpoint->service_id == 0) 2623 continue; 2624 2625 if (endpoint->EpCallBacks.ep_resume_tx_queue) 2626 endpoint->EpCallBacks.ep_resume_tx_queue( 2627 endpoint->EpCallBacks.pContext); 2628 2629 htc_try_send(target, endpoint, NULL); 2630 } 2631 2632 hif_fastpath_resume(target->hif_dev); 2633 2634 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT); 2635 } 2636 #endif 2637 2638 /* flush endpoint TX queue */ 2639 void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, 2640 HTC_TX_TAG Tag) 2641 { 2642 HTC_PACKET *pPacket; 2643 2644 LOCK_HTC_TX(target); 2645 while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { 2646 pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); 2647 2648 if (pPacket) { 2649 /* let the sender know the packet was not delivered */ 2650 pPacket->Status = QDF_STATUS_E_CANCELED; 2651 send_packet_completion(target, pPacket); 2652 } 2653 } 2654 UNLOCK_HTC_TX(target); 2655 } 2656 2657 /* flush pending entries in endpoint TX Lookup queue */ 2658 void htc_flush_endpoint_txlookupQ(HTC_TARGET *target, 2659 HTC_ENDPOINT_ID endpoint_id, 2660 bool call_ep_callback) 2661 { 2662 HTC_PACKET *packet; 2663 HTC_ENDPOINT *endpoint; 2664 2665 endpoint = &target->endpoint[endpoint_id]; 2666 2667 if (!endpoint && endpoint->service_id == 0) 2668 return; 2669 2670 LOCK_HTC_TX(target); 2671 while (HTC_PACKET_QUEUE_DEPTH(&endpoint->TxLookupQueue)) { 2672 packet = htc_packet_dequeue(&endpoint->TxLookupQueue); 2673 2674 if (packet) { 2675 if (call_ep_callback == true) { 2676 packet->Status = QDF_STATUS_E_CANCELED; 2677 send_packet_completion(target, packet); 2678 } else { 2679 qdf_mem_free(packet); 2680 } 2681 } 2682 } 2683 UNLOCK_HTC_TX(target); 2684 } 2685 2686 /* HTC API to flush an endpoint's TX queue*/ 2687 void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, 2688 HTC_TX_TAG Tag) 2689 { 2690 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2691 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; 2692 2693 if (pEndpoint->service_id == 0) { 2694 AR_DEBUG_ASSERT(false); 2695 /* not in use.. */ 2696 return; 2697 } 2698 2699 htc_flush_endpoint_tx(target, pEndpoint, Tag); 2700 } 2701 2702 /* HTC API to indicate activity to the credit distribution function */ 2703 void htc_indicate_activity_change(HTC_HANDLE HTCHandle, 2704 HTC_ENDPOINT_ID Endpoint, bool Active) 2705 { 2706 /* TODO */ 2707 } 2708 2709 bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) 2710 { 2711 return true; 2712 } 2713 2714 void htc_set_pkt_dbg(HTC_HANDLE handle, A_BOOL dbg_flag) 2715 { 2716 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(handle); 2717 2718 target->htc_pkt_dbg = dbg_flag; 2719 } 2720 2721 void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt) 2722 { 2723 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2724 2725 target->is_nodrop_pkt = isNodropPkt; 2726 } 2727 2728 void htc_enable_hdr_length_check(HTC_HANDLE htc_hdl, bool htc_hdr_length_check) 2729 { 2730 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl); 2731 2732 target->htc_hdr_length_check = htc_hdr_length_check; 2733 } 2734 2735 /** 2736 * htc_process_credit_rpt() - process credit report, call distribution function 2737 * @target: pointer to HTC_TARGET 2738 * @pRpt: pointer to HTC_CREDIT_REPORT 2739 * @NumEntries: number of entries in credit report 2740 * @FromEndpoint: endpoint for which credit report is received 2741 * 2742 * Return: A_OK for success or an appropriate A_STATUS error 2743 */ 2744 void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, 2745 int NumEntries, HTC_ENDPOINT_ID FromEndpoint) 2746 { 2747 int i; 2748 HTC_ENDPOINT *pEndpoint; 2749 int totalCredits = 0; 2750 uint8_t rpt_credits, rpt_ep_id; 2751 2752 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2753 ("+htc_process_credit_rpt, Credit Report Entries:%d\n", 2754 NumEntries)); 2755 2756 /* lock out TX while we update credits */ 2757 LOCK_HTC_TX(target); 2758 2759 for (i = 0; i < NumEntries; i++, pRpt++) { 2760 2761 rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID); 2762 2763 if (rpt_ep_id >= ENDPOINT_MAX) { 2764 AR_DEBUG_ASSERT(false); 2765 break; 2766 } 2767 2768 rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS); 2769 2770 pEndpoint = &target->endpoint[rpt_ep_id]; 2771 #if DEBUG_CREDIT 2772 if (ep_debug_mask & (1 << pEndpoint->Id)) { 2773 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2774 (" <HTC> Increase EP%d %d + %d = %d credits\n", 2775 rpt_ep_id, pEndpoint->TxCredits, 2776 rpt_credits, 2777 pEndpoint->TxCredits + rpt_credits)); 2778 } 2779 #endif 2780 2781 #ifdef HTC_EP_STAT_PROFILING 2782 2783 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1); 2784 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits); 2785 2786 if (FromEndpoint == rpt_ep_id) { 2787 /* this credit report arrived on the same endpoint 2788 * indicating it arrived in an RX packet 2789 */ 2790 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, 2791 rpt_credits); 2792 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1); 2793 } else if (FromEndpoint == ENDPOINT_0) { 2794 /* this credit arrived on endpoint 0 as a NULL msg */ 2795 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, 2796 rpt_credits); 2797 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1); 2798 } else { 2799 /* arrived on another endpoint */ 2800 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, 2801 rpt_credits); 2802 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1); 2803 } 2804 2805 #endif 2806 2807 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 2808 htc_credit_record(HTC_PROCESS_CREDIT_REPORT, 2809 pEndpoint->TxCredits + rpt_credits, 2810 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 2811 TxQueue)); 2812 hif_latency_detect_credit_record_time( 2813 HIF_PROCESS_CREDIT_REPORT, 2814 target->hif_dev); 2815 } 2816 2817 pEndpoint->TxCredits += rpt_credits; 2818 2819 if (pEndpoint->TxCredits 2820 && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { 2821 UNLOCK_HTC_TX(target); 2822 #ifdef ATH_11AC_TXCOMPACT 2823 htc_try_send(target, pEndpoint, NULL); 2824 #else 2825 if (pEndpoint->service_id == HTT_DATA_MSG_SVC) 2826 htc_send_data_pkt((HTC_HANDLE)target, NULL, 0); 2827 else 2828 htc_try_send(target, pEndpoint, NULL); 2829 #endif 2830 LOCK_HTC_TX(target); 2831 } 2832 totalCredits += rpt_credits; 2833 } 2834 2835 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2836 (" Report indicated %d credits to distribute\n", 2837 totalCredits)); 2838 2839 UNLOCK_HTC_TX(target); 2840 2841 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt\n")); 2842 } 2843 2844 /* function to fetch stats from htc layer*/ 2845 struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) 2846 { 2847 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2848 2849 return &(target->htc_pkt_stats); 2850 } 2851 2852 #ifdef SYSTEM_PM_CHECK 2853 void htc_system_resume(HTC_HANDLE htc) 2854 { 2855 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc); 2856 HTC_ENDPOINT *endpoint = NULL; 2857 int i; 2858 2859 if (!target) 2860 return; 2861 2862 for (i = 0; i < ENDPOINT_MAX; i++) { 2863 endpoint = &target->endpoint[i]; 2864 2865 if (endpoint->service_id == 0) 2866 continue; 2867 2868 htc_try_send(target, endpoint, NULL); 2869 } 2870 } 2871 #endif 2872