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