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_runtime_cnt: Increment htc runtime count 189 * @target: handle of HTC context 190 * 191 * Return: None 192 */ 193 static inline 194 void htc_inc_runtime_cnt(HTC_TARGET *target) 195 { 196 qdf_atomic_inc(&target->htc_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_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_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_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 #else 1033 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, 1034 HTC_PACKET_QUEUE *queue) 1035 {} 1036 1037 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, 1038 HTC_PACKET_QUEUE *queue) 1039 {} 1040 #endif 1041 1042 /** 1043 * htc_send_pkts_get_rtpm_id() - get runtime pm dbgid by service_id 1044 * @service_id: service for endpoint 1045 * 1046 * For service_id HTT_DATA_MSG_SVC, HTT message donot have a tx complete 1047 * from CE level, so they need runtime put which only can happen in fw 1048 * response. runtime put will happens at 2 ways. 1049 * 1 if packet tag HTC_TX_PACKET_TAG_RUNTIME_PUT, runtime put 1050 * will be just in htc_issue_packets. as such pkt doesn't have 1051 * a response from fw. 1052 * 2 other pkt must have a response from fw, it will be handled 1053 * by fw response using htc_pm_runtime_put. 1054 * 1055 * For other service_id, they have tx_completion from CE, so they will be 1056 * handled in htc_tx_completion_handler, except packet tag as 1057 * HTC_TX_PACKET_TAG_AUTO_PM, pm related wmi cmd don't need a runtime 1058 * put/get. 1059 * 1060 * 1061 * Return: rtpm id to trace who used it 1062 */ 1063 static unsigned int 1064 htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id) 1065 { 1066 if (service_id == HTT_DATA_MSG_SVC) 1067 return HIF_RTPM_ID_HTT; 1068 else 1069 return HIF_RTPM_ID_WMI; 1070 } 1071 1072 #ifdef SYSTEM_PM_CHECK 1073 /** 1074 * extract_htc_system_resume_pkts(): Move system pm resume packets from endpoint 1075 * into queue 1076 * @endpoint: which endpoint to extract packets from 1077 * @queue: a queue to store extracted packets in. 1078 * 1079 * Remove pm packets from the endpoint's tx queue and enqueue 1080 * them into a queue 1081 */ 1082 static void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, 1083 HTC_PACKET_QUEUE *queue) 1084 { 1085 HTC_PACKET *packet; 1086 1087 /* only WMI endpoint has power management packets */ 1088 if (endpoint->service_id != WMI_CONTROL_SVC) 1089 return; 1090 1091 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, 1092 HTC_PACKET, ListLink) { 1093 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_RESUME) { 1094 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); 1095 HTC_PACKET_ENQUEUE(queue, packet); 1096 } 1097 } ITERATE_END 1098 } 1099 #else 1100 static inline 1101 void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint, 1102 HTC_PACKET_QUEUE *queue) 1103 { 1104 } 1105 #endif 1106 1107 /** 1108 * get_htc_send_packets_credit_based() - get packets based on available credits 1109 * @target: HTC target on which packets need to be sent 1110 * @pEndpoint: logical endpoint on which packets needs to be sent 1111 * @pQueue: HTC packet queue containing the list of packets to be sent 1112 * 1113 * Get HTC send packets from TX queue on an endpoint based on available credits. 1114 * The function moves the packets from TX queue of the endpoint to pQueue. 1115 * 1116 * Return: None 1117 */ 1118 static void get_htc_send_packets_credit_based(HTC_TARGET *target, 1119 HTC_ENDPOINT *pEndpoint, 1120 HTC_PACKET_QUEUE *pQueue) 1121 { 1122 int creditsRequired; 1123 int remainder; 1124 uint8_t sendFlags; 1125 HTC_PACKET *pPacket; 1126 unsigned int transferLength; 1127 HTC_PACKET_QUEUE *tx_queue; 1128 HTC_PACKET_QUEUE pm_queue; 1129 bool do_pm_get = false; 1130 unsigned int rtpm_code = 0; 1131 int ret; 1132 HTC_PACKET_QUEUE sys_pm_queue; 1133 bool sys_pm_check = false; 1134 1135 /*** NOTE : the TX lock is held when this function is called ***/ 1136 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1137 ("+get_htc_send_packets_credit_based\n")); 1138 1139 INIT_HTC_PACKET_QUEUE(&pm_queue); 1140 extract_htc_pm_packets(pEndpoint, &pm_queue); 1141 if (HTC_QUEUE_EMPTY(&pm_queue)) { 1142 do_pm_get = true; 1143 1144 INIT_HTC_PACKET_QUEUE(&sys_pm_queue); 1145 extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue); 1146 if (HTC_QUEUE_EMPTY(&sys_pm_queue)) { 1147 tx_queue = &pEndpoint->TxQueue; 1148 sys_pm_check = true; 1149 } else { 1150 tx_queue = &sys_pm_queue; 1151 } 1152 } else { 1153 tx_queue = &pm_queue; 1154 } 1155 1156 /* loop until we can grab as many packets out of the queue as we can */ 1157 while (true) { 1158 if (do_pm_get) { 1159 rtpm_code = htc_send_pkts_get_rtpm_id( 1160 pEndpoint->service_id); 1161 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code); 1162 if (ret) { 1163 /* bus suspended, runtime resume issued */ 1164 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 1165 pPacket = htc_get_pkt_at_head(tx_queue); 1166 if (!pPacket) 1167 break; 1168 log_packet_info(target, pPacket); 1169 break; 1170 } 1171 } 1172 1173 sendFlags = 0; 1174 /* get packet at head, but don't remove it */ 1175 pPacket = htc_get_pkt_at_head(tx_queue); 1176 if (!pPacket) { 1177 if (do_pm_get) 1178 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1179 break; 1180 } 1181 1182 if (sys_pm_check && 1183 hif_system_pm_state_check(target->hif_dev)) { 1184 if (do_pm_get) 1185 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1186 break; 1187 } 1188 1189 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1190 (" Got head packet:%pK , Queue Depth: %d\n", 1191 pPacket, 1192 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 1193 1194 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; 1195 1196 if (transferLength <= pEndpoint->TxCreditSize) { 1197 creditsRequired = 1; 1198 } else { 1199 /* figure out how many credits this message requires */ 1200 creditsRequired = 1201 transferLength / pEndpoint->TxCreditSize; 1202 remainder = transferLength % pEndpoint->TxCreditSize; 1203 1204 if (remainder) 1205 creditsRequired++; 1206 } 1207 1208 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1209 (" Credits Required:%d Got:%d\n", 1210 creditsRequired, pEndpoint->TxCredits)); 1211 1212 if (pEndpoint->Id == ENDPOINT_0) { 1213 /* 1214 * endpoint 0 is special, it always has a credit and 1215 * does not require credit based flow control 1216 */ 1217 creditsRequired = 0; 1218 } else { 1219 1220 if (pEndpoint->TxCredits < creditsRequired) { 1221 #if DEBUG_CREDIT 1222 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1223 ("EP%d,No Credit now.%d < %d\n", 1224 pEndpoint->Id, 1225 pEndpoint->TxCredits, 1226 creditsRequired)); 1227 #endif 1228 if (do_pm_get) 1229 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, 1230 rtpm_code); 1231 1232 break; 1233 } 1234 1235 pEndpoint->TxCredits -= creditsRequired; 1236 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, 1237 creditsRequired); 1238 1239 /* check if we need credits back from the target */ 1240 if (pEndpoint->TxCredits <= 1241 pEndpoint->TxCreditsPerMaxMsg) { 1242 /* tell the target we need credits ASAP! */ 1243 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; 1244 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 1245 htc_credit_record(HTC_REQUEST_CREDIT, 1246 pEndpoint->TxCredits, 1247 HTC_PACKET_QUEUE_DEPTH 1248 (tx_queue)); 1249 hif_latency_detect_credit_record_time( 1250 HIF_REQUEST_CREDIT, 1251 target->hif_dev); 1252 } 1253 INC_HTC_EP_STAT(pEndpoint, 1254 TxCreditLowIndications, 1); 1255 #if DEBUG_CREDIT 1256 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1257 (" EP%d Needs Credits\n", 1258 pEndpoint->Id)); 1259 #endif 1260 } 1261 } 1262 1263 /* now we can fully dequeue */ 1264 pPacket = htc_packet_dequeue(tx_queue); 1265 if (pPacket) { 1266 /* save the number of credits this packet consumed */ 1267 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; 1268 /* save send flags */ 1269 pPacket->PktInfo.AsTx.SendFlags = sendFlags; 1270 1271 /* queue this packet into the caller's queue */ 1272 HTC_PACKET_ENQUEUE(pQueue, pPacket); 1273 } 1274 } 1275 1276 if (!HTC_QUEUE_EMPTY(&pm_queue)) 1277 queue_htc_pm_packets(pEndpoint, &pm_queue); 1278 1279 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1280 ("-get_htc_send_packets_credit_based\n")); 1281 1282 } 1283 1284 static void get_htc_send_packets(HTC_TARGET *target, 1285 HTC_ENDPOINT *pEndpoint, 1286 HTC_PACKET_QUEUE *pQueue, int Resources) 1287 { 1288 1289 HTC_PACKET *pPacket; 1290 HTC_PACKET_QUEUE *tx_queue; 1291 HTC_PACKET_QUEUE pm_queue; 1292 bool do_pm_get = false; 1293 unsigned int rtpm_code = 0; 1294 int ret; 1295 1296 /*** NOTE : the TX lock is held when this function is called ***/ 1297 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1298 ("+get_htc_send_packets %d resources\n", Resources)); 1299 1300 INIT_HTC_PACKET_QUEUE(&pm_queue); 1301 extract_htc_pm_packets(pEndpoint, &pm_queue); 1302 if (HTC_QUEUE_EMPTY(&pm_queue)) { 1303 tx_queue = &pEndpoint->TxQueue; 1304 do_pm_get = true; 1305 } else { 1306 tx_queue = &pm_queue; 1307 } 1308 1309 /* loop until we can grab as many packets out of the queue as we can */ 1310 while (Resources > 0) { 1311 int num_frags; 1312 1313 if (do_pm_get) { 1314 rtpm_code = 1315 htc_send_pkts_get_rtpm_id( 1316 pEndpoint->service_id); 1317 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code); 1318 if (ret) { 1319 /* bus suspended, runtime resume issued */ 1320 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 1321 pPacket = htc_get_pkt_at_head(tx_queue); 1322 if (!pPacket) 1323 break; 1324 log_packet_info(target, pPacket); 1325 break; 1326 } 1327 1328 } 1329 1330 ret = hif_system_pm_state_check(target->hif_dev); 1331 if (ret) { 1332 if (do_pm_get) { 1333 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1334 } 1335 break; 1336 } 1337 1338 pPacket = htc_packet_dequeue(tx_queue); 1339 if (!pPacket) { 1340 if (do_pm_get) { 1341 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1342 } 1343 break; 1344 } 1345 1346 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1347 (" Got packet:%pK , New Queue Depth: %d\n", 1348 pPacket, 1349 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 1350 /* For non-credit path the sequence number is already embedded 1351 * in the constructed HTC header 1352 */ 1353 pPacket->PktInfo.AsTx.SendFlags = 0; 1354 pPacket->PktInfo.AsTx.CreditsUsed = 0; 1355 /* queue this packet into the caller's queue */ 1356 HTC_PACKET_ENQUEUE(pQueue, pPacket); 1357 1358 /* 1359 * FIX THIS: 1360 * For now, avoid calling qdf_nbuf_get_num_frags before calling 1361 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't 1362 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has 1363 * been done. 1364 * Assume that the non-data netbufs, i.e. WMI message netbufs, 1365 * consist of a single fragment. 1366 */ 1367 /* WMI messages are in a single-fragment network buf */ 1368 num_frags = 1369 (pPacket->PktInfo.AsTx. 1370 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 : 1371 qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT 1372 (pPacket)); 1373 Resources -= num_frags; 1374 } 1375 1376 if (!HTC_QUEUE_EMPTY(&pm_queue)) 1377 queue_htc_pm_packets(pEndpoint, &pm_queue); 1378 1379 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n")); 1380 1381 } 1382 1383 /** 1384 * htc_try_send() - Send packets in a queue on an endpoint 1385 * @target: HTC target on which packets need to be sent 1386 * @pEndpoint: logical endpoint on which packets needs to be sent 1387 * @pCallersSendQueue: packet queue containing the list of packets to be sent 1388 * 1389 * Return: enum HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to 1390 * be sent or the packet should be dropped by the upper layer 1391 */ 1392 static enum HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target, 1393 HTC_ENDPOINT *pEndpoint, 1394 HTC_PACKET_QUEUE *pCallersSendQueue) 1395 { 1396 /* temp queue to hold packets at various stages */ 1397 HTC_PACKET_QUEUE sendQueue; 1398 HTC_PACKET *pPacket; 1399 int tx_resources; 1400 int overflow; 1401 enum HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; 1402 QDF_STATUS status; 1403 1404 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%pK Depth:%d)\n", 1405 pCallersSendQueue, 1406 (pCallersSendQueue == 1407 NULL) ? 0 : 1408 HTC_PACKET_QUEUE_DEPTH 1409 (pCallersSendQueue))); 1410 1411 /* init the local send queue */ 1412 INIT_HTC_PACKET_QUEUE(&sendQueue); 1413 1414 do { 1415 1416 /* caller didn't provide a queue, just wants us to check 1417 * queues and send 1418 */ 1419 if (!pCallersSendQueue) 1420 break; 1421 1422 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { 1423 /* empty queue */ 1424 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 1425 HTC_PKT_Q_EMPTY); 1426 result = HTC_SEND_QUEUE_DROP; 1427 break; 1428 } 1429 1430 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= 1431 pEndpoint->MaxTxQueueDepth) { 1432 /* we've already overflowed */ 1433 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 1434 } else { 1435 /* figure out how much we will overflow by */ 1436 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 1437 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 1438 /* get how much we will overflow the TX queue by */ 1439 overflow -= pEndpoint->MaxTxQueueDepth; 1440 } 1441 1442 /* if overflow is negative or zero, we are okay */ 1443 if (overflow > 0) { 1444 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1445 ("Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d\n", 1446 pEndpoint->Id, overflow, 1447 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 1448 TxQueue), 1449 pEndpoint->MaxTxQueueDepth)); 1450 } 1451 if ((overflow <= 0) 1452 || (!pEndpoint->EpCallBacks.EpSendFull)) { 1453 /* all packets will fit or caller did not provide send 1454 * full indication handler 1455 * just move all of them to local sendQueue object 1456 */ 1457 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, 1458 pCallersSendQueue); 1459 } else { 1460 int i; 1461 int goodPkts = 1462 HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - 1463 overflow; 1464 1465 A_ASSERT(goodPkts >= 0); 1466 /* we have overflowed and callback is provided. Dequeue 1467 * all non-overflow packets into the sendqueue 1468 */ 1469 for (i = 0; i < goodPkts; i++) { 1470 /* pop off caller's queue */ 1471 pPacket = htc_packet_dequeue(pCallersSendQueue); 1472 A_ASSERT(pPacket); 1473 if (pPacket) 1474 /* insert into local queue */ 1475 HTC_PACKET_ENQUEUE(&sendQueue, 1476 pPacket); 1477 } 1478 1479 /* the caller's queue has all the packets that won't fit 1480 * walk through the caller's queue and indicate each one 1481 * to the send full handler 1482 */ 1483 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue-> 1484 QueueHead, pPacket, 1485 HTC_PACKET, ListLink) { 1486 1487 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1488 ("Indicating overflowed TX packet: %pK\n", 1489 pPacket)); 1490 /* 1491 * Remove headroom reserved for HTC_FRAME_HDR 1492 * before giving the packet back to the user via 1493 * the EpSendFull callback. 1494 */ 1495 qdf_nbuf_pull_head 1496 (GET_HTC_PACKET_NET_BUF_CONTEXT 1497 (pPacket), 1498 sizeof(HTC_FRAME_HDR)); 1499 pPacket->PktInfo.AsTx.Flags &= 1500 ~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1501 1502 if (pEndpoint->EpCallBacks. 1503 EpSendFull(pEndpoint->EpCallBacks.pContext, 1504 pPacket) == HTC_SEND_FULL_DROP) { 1505 /* callback wants the packet dropped */ 1506 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1507 1); 1508 /* leave this one in the caller's queue 1509 * for cleanup 1510 */ 1511 } else { 1512 /* callback wants to keep this packet, 1513 * remove from caller's queue 1514 */ 1515 HTC_PACKET_REMOVE(pCallersSendQueue, 1516 pPacket); 1517 /* put it in the send queue 1518 * add HTC_FRAME_HDR space reservation 1519 * again 1520 */ 1521 qdf_nbuf_push_head 1522 (GET_HTC_PACKET_NET_BUF_CONTEXT 1523 (pPacket), 1524 sizeof(HTC_FRAME_HDR)); 1525 pPacket->PktInfo.AsTx.Flags |= 1526 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1527 1528 HTC_PACKET_ENQUEUE(&sendQueue, pPacket); 1529 } 1530 1531 } 1532 ITERATE_END; 1533 1534 if (HTC_QUEUE_EMPTY(&sendQueue)) { 1535 /* no packets made it in, caller will cleanup */ 1536 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 1537 HTC_SEND_Q_EMPTY); 1538 result = HTC_SEND_QUEUE_DROP; 1539 break; 1540 } 1541 } 1542 1543 } while (false); 1544 1545 if (result != HTC_SEND_QUEUE_OK) { 1546 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n", 1547 result)); 1548 return result; 1549 } 1550 1551 LOCK_HTC_TX(target); 1552 1553 if (!HTC_QUEUE_EMPTY(&sendQueue)) { 1554 if (target->is_nodrop_pkt) { 1555 /* 1556 * nodrop pkts have higher priority than normal pkts, 1557 * insert nodrop pkt to head for proper 1558 * start/termination of test. 1559 */ 1560 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1561 &sendQueue); 1562 target->is_nodrop_pkt = false; 1563 } else { 1564 /* transfer packets to tail */ 1565 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue, 1566 &sendQueue); 1567 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); 1568 INIT_HTC_PACKET_QUEUE(&sendQueue); 1569 } 1570 } 1571 1572 /* increment tx processing count on entry */ 1573 if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) { 1574 /* another thread or task is draining the TX queues on this 1575 * endpoint that thread will reset the tx processing count when 1576 * the queue is drained 1577 */ 1578 qdf_atomic_dec(&pEndpoint->TxProcessCount); 1579 UNLOCK_HTC_TX(target); 1580 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy)\n")); 1581 return HTC_SEND_QUEUE_OK; 1582 } 1583 1584 /***** beyond this point only 1 thread may enter ******/ 1585 1586 /* now drain the endpoint TX queue for transmission as long as we have 1587 * enough transmit resources 1588 */ 1589 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1590 tx_resources = 1591 hif_get_free_queue_number(target->hif_dev, 1592 pEndpoint->UL_PipeID); 1593 } else { 1594 tx_resources = 0; 1595 } 1596 1597 while (true) { 1598 1599 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) 1600 break; 1601 1602 if (pEndpoint->async_update && 1603 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) && 1604 (!tx_resources)) { 1605 hif_schedule_ce_tasklet(target->hif_dev, 1606 pEndpoint->UL_PipeID); 1607 break; 1608 } 1609 1610 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1611 #if DEBUG_CREDIT 1612 int cred = pEndpoint->TxCredits; 1613 #endif 1614 /* credit based mechanism provides flow control based on 1615 * target transmit resource availability, we assume that 1616 * the HIF layer will always have bus resources greater 1617 * than target transmit resources 1618 */ 1619 get_htc_send_packets_credit_based(target, pEndpoint, 1620 &sendQueue); 1621 #if DEBUG_CREDIT 1622 if (ep_debug_mask & (1 << pEndpoint->Id)) { 1623 if (cred - pEndpoint->TxCredits > 0) { 1624 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1625 (" <HTC> Decrease EP%d %d - %d = %d credits.\n", 1626 pEndpoint->Id, cred, 1627 cred - 1628 pEndpoint->TxCredits, 1629 pEndpoint->TxCredits)); 1630 } 1631 } 1632 #endif 1633 } else { 1634 1635 /* 1636 * Header and payload belongs to the different fragments and 1637 * consume 2 resource for one HTC package but USB combine into 1638 * one transfer.And one WMI message only consumes one single 1639 * resource. 1640 */ 1641 if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources && 1642 hif_get_bus_type(target->hif_dev) == 1643 QDF_BUS_TYPE_USB) { 1644 if (pEndpoint->service_id == 1645 WMI_CONTROL_SVC) 1646 tx_resources = 1647 HTC_MAX_MSG_PER_BUNDLE_TX; 1648 else 1649 tx_resources = 1650 (HTC_MAX_MSG_PER_BUNDLE_TX * 2); 1651 } 1652 /* get all the packets for this endpoint that we can for 1653 * this pass 1654 */ 1655 get_htc_send_packets(target, pEndpoint, &sendQueue, 1656 tx_resources); 1657 } 1658 1659 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { 1660 /* didn't get any packets due to a lack of resources or 1661 * TX queue was drained 1662 */ 1663 break; 1664 } 1665 1666 if (!pEndpoint->async_update) 1667 UNLOCK_HTC_TX(target); 1668 1669 /* send what we can */ 1670 status = htc_issue_packets(target, pEndpoint, &sendQueue); 1671 if (status) { 1672 int i; 1673 unsigned int rtpm_code; 1674 1675 result = HTC_SEND_QUEUE_DROP; 1676 1677 switch (status) { 1678 case QDF_STATUS_E_RESOURCES: 1679 if (pEndpoint->num_requeues_warn <= MAX_REQUEUE_WARN) { 1680 pEndpoint->num_requeues_warn++; 1681 pEndpoint->total_num_requeues++; 1682 break; 1683 } else { 1684 pEndpoint->total_num_requeues++; 1685 pEndpoint->num_requeues_warn = 0; 1686 } 1687 fallthrough; 1688 default: 1689 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, 1690 "htc_issue_packets, failed status:%d" 1691 "endpoint:%d, put it back to head of" 1692 "callersSendQueue", result, pEndpoint->Id); 1693 break; 1694 } 1695 1696 rtpm_code = htc_send_pkts_get_rtpm_id( 1697 pEndpoint->service_id); 1698 for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) { 1699 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code); 1700 } 1701 1702 if (!pEndpoint->async_update) { 1703 LOCK_HTC_TX(target); 1704 } 1705 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1706 &sendQueue); 1707 break; 1708 } else { 1709 if (pEndpoint->num_requeues_warn) 1710 pEndpoint->num_requeues_warn = 0; 1711 } 1712 1713 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1714 tx_resources = 1715 hif_get_free_queue_number(target->hif_dev, 1716 pEndpoint->UL_PipeID); 1717 } 1718 1719 if (!pEndpoint->async_update) { 1720 LOCK_HTC_TX(target); 1721 } 1722 1723 } 1724 1725 /* done with this endpoint, we can clear the count */ 1726 qdf_atomic_init(&pEndpoint->TxProcessCount); 1727 1728 UNLOCK_HTC_TX(target); 1729 1730 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send:\n")); 1731 1732 return HTC_SEND_QUEUE_OK; 1733 } 1734 1735 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1736 static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, 1737 HTC_ENDPOINT_ID id) 1738 { 1739 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1740 HTC_ENDPOINT *pEndpoint; 1741 HTC_ENDPOINT_ID eid; 1742 HTC_PACKET_QUEUE *pTxQueue; 1743 uint16_t resources; 1744 uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 }; 1745 1746 if (id < ENDPOINT_2 || id > ENDPOINT_5) 1747 return 1; 1748 1749 for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) { 1750 pEndpoint = &target->endpoint[eid]; 1751 pTxQueue = &pEndpoint->TxQueue; 1752 1753 if (HTC_QUEUE_EMPTY(pTxQueue)) 1754 acQueueStatus[eid - 2] = 1; 1755 } 1756 1757 switch (id) { 1758 case ENDPOINT_2: /* BE */ 1759 return acQueueStatus[0] && acQueueStatus[2] 1760 && acQueueStatus[3]; 1761 case ENDPOINT_3: /* BK */ 1762 return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2] 1763 && acQueueStatus[3]; 1764 case ENDPOINT_4: /* VI */ 1765 return acQueueStatus[2] && acQueueStatus[3]; 1766 case ENDPOINT_5: /* VO */ 1767 return acQueueStatus[3]; 1768 default: 1769 return 0; 1770 } 1771 1772 } 1773 1774 static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target, 1775 HTC_PACKET_QUEUE *pPktQueue, 1776 HTC_ENDPOINT_ID eid) 1777 { 1778 HTC_ENDPOINT *pEndpoint; 1779 HTC_PACKET_QUEUE *pTxQueue; 1780 HTC_PACKET *pPacket; 1781 int goodPkts; 1782 1783 pEndpoint = &target->endpoint[eid]; 1784 pTxQueue = &pEndpoint->TxQueue; 1785 1786 LOCK_HTC_TX(target); 1787 1788 goodPkts = 1789 pEndpoint->MaxTxQueueDepth - 1790 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 1791 1792 if (goodPkts > 0) { 1793 while (!HTC_QUEUE_EMPTY(pPktQueue)) { 1794 pPacket = htc_packet_dequeue(pPktQueue); 1795 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1796 goodPkts--; 1797 1798 if (goodPkts <= 0) 1799 break; 1800 } 1801 } 1802 1803 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) { 1804 ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket, 1805 HTC_PACKET, ListLink) { 1806 1807 if (pEndpoint->EpCallBacks. 1808 EpSendFull(pEndpoint->EpCallBacks.pContext, 1809 pPacket) == HTC_SEND_FULL_DROP) { 1810 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); 1811 } else { 1812 HTC_PACKET_REMOVE(pPktQueue, pPacket); 1813 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1814 } 1815 } 1816 ITERATE_END; 1817 } 1818 1819 UNLOCK_HTC_TX(target); 1820 1821 return A_OK; 1822 } 1823 1824 #endif 1825 1826 static inline QDF_STATUS __htc_send_pkt(HTC_HANDLE HTCHandle, 1827 HTC_PACKET *pPacket) 1828 { 1829 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1830 HTC_ENDPOINT *pEndpoint; 1831 HTC_PACKET_QUEUE pPktQueue; 1832 qdf_nbuf_t netbuf; 1833 HTC_FRAME_HDR *htc_hdr; 1834 QDF_STATUS status; 1835 1836 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1837 ("+__htc_send_pkt\n")); 1838 1839 /* get packet at head to figure out which endpoint these packets will 1840 * go into 1841 */ 1842 if (!pPacket) { 1843 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL); 1844 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1845 return QDF_STATUS_E_INVAL; 1846 } 1847 1848 if ((pPacket->Endpoint >= ENDPOINT_MAX) || 1849 (pPacket->Endpoint <= ENDPOINT_UNUSED)) { 1850 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1851 ("%s endpoint is invalid\n", __func__)); 1852 AR_DEBUG_ASSERT(0); 1853 return QDF_STATUS_E_INVAL; 1854 } 1855 pEndpoint = &target->endpoint[pPacket->Endpoint]; 1856 1857 if (!pEndpoint->service_id) { 1858 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n", 1859 __func__)); 1860 return QDF_STATUS_E_INVAL; 1861 } 1862 1863 #ifdef HTC_EP_STAT_PROFILING 1864 LOCK_HTC_TX(target); 1865 INC_HTC_EP_STAT(pEndpoint, TxPosted, 1); 1866 UNLOCK_HTC_TX(target); 1867 #endif 1868 1869 /* provide room in each packet's netbuf for the HTC frame header */ 1870 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 1871 AR_DEBUG_ASSERT(netbuf); 1872 if (!netbuf) 1873 return QDF_STATUS_E_INVAL; 1874 1875 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); 1876 pPacket->PktInfo.AsTx.Flags |= 1877 HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA; 1878 /* setup HTC frame header */ 1879 htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 1880 AR_DEBUG_ASSERT(htc_hdr); 1881 if (!htc_hdr) 1882 return QDF_STATUS_E_INVAL; 1883 1884 HTC_WRITE32(htc_hdr, 1885 SM(pPacket->ActualLength, 1886 HTC_FRAME_HDR_PAYLOADLEN) | 1887 SM(pPacket->Endpoint, 1888 HTC_FRAME_HDR_ENDPOINTID)); 1889 LOCK_HTC_TX(target); 1890 1891 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; 1892 pEndpoint->SeqNo++; 1893 1894 HTC_WRITE32(((uint32_t *)htc_hdr) + 1, 1895 SM(pPacket->PktInfo.AsTx.SeqNo, 1896 HTC_FRAME_HDR_CONTROLBYTES1)); 1897 1898 UNLOCK_HTC_TX(target); 1899 1900 /* 1901 * For flow control enabled endpoints mapping is done in 1902 * htc_issue_packets and for non flow control enabled endpoints 1903 * its done here. 1904 */ 1905 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1906 pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 1907 status = qdf_nbuf_map(target->osdev, 1908 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 1909 QDF_DMA_TO_DEVICE); 1910 if (status == QDF_STATUS_SUCCESS) { 1911 target->nbuf_nfc_map_count++; 1912 } else { 1913 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1914 ("%s: nbuf map failed, endpoint %pK, seq_no. %d\n", 1915 __func__, pEndpoint, pEndpoint->SeqNo)); 1916 return status; 1917 } 1918 } 1919 1920 INIT_HTC_PACKET_QUEUE_AND_ADD(&pPktQueue, pPacket); 1921 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1922 if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) 1923 htc_send_pkts_sched_queue(HTCHandle, &pPktQueue, pEndpoint->Id); 1924 else 1925 htc_try_send(target, pEndpoint, &pPktQueue); 1926 #else 1927 htc_try_send(target, pEndpoint, &pPktQueue); 1928 #endif 1929 1930 /* do completion on any packets that couldn't get in */ 1931 while (!HTC_QUEUE_EMPTY(&pPktQueue)) { 1932 pPacket = htc_packet_dequeue(&pPktQueue); 1933 1934 if (HTC_STOPPING(target)) 1935 pPacket->Status = QDF_STATUS_E_CANCELED; 1936 else 1937 pPacket->Status = QDF_STATUS_E_RESOURCES; 1938 1939 send_packet_completion(target, pPacket); 1940 } 1941 1942 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1943 1944 return QDF_STATUS_SUCCESS; 1945 } 1946 1947 /* HTC API - htc_send_pkt */ 1948 QDF_STATUS htc_send_pkt(HTC_HANDLE htc_handle, HTC_PACKET *htc_packet) 1949 { 1950 if (!htc_handle) { 1951 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1952 ("%s: HTCHandle is NULL \n", __func__)); 1953 return QDF_STATUS_E_FAILURE; 1954 } 1955 1956 if (!htc_packet) { 1957 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1958 ("%s: pPacket is NULL \n", __func__)); 1959 return QDF_STATUS_E_FAILURE; 1960 } 1961 1962 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1963 ("+-htc_send_pkt: Enter endPointId: %d, buffer: %pK, length: %d\n", 1964 htc_packet->Endpoint, htc_packet->pBuffer, 1965 htc_packet->ActualLength)); 1966 return __htc_send_pkt(htc_handle, htc_packet); 1967 } 1968 qdf_export_symbol(htc_send_pkt); 1969 1970 #ifdef ATH_11AC_TXCOMPACT 1971 /** 1972 * htc_send_data_pkt() - send single data packet on an endpoint 1973 * @HTCHandle: pointer to HTC handle 1974 * @netbuf: network buffer containing the data to be sent 1975 * @ActualLength: length of data that needs to be transmitted 1976 * 1977 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 1978 */ 1979 QDF_STATUS htc_send_data_pkt(HTC_HANDLE htc_hdl, qdf_nbuf_t netbuf, int ep_id, 1980 int actual_length) 1981 { 1982 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl); 1983 HTC_ENDPOINT *pEndpoint; 1984 HTC_FRAME_HDR *p_htc_hdr; 1985 QDF_STATUS status = QDF_STATUS_SUCCESS; 1986 int tx_resources; 1987 uint32_t data_attr = 0; 1988 int htc_payload_len = actual_length; 1989 unsigned int rtpm_code; 1990 1991 pEndpoint = &target->endpoint[ep_id]; 1992 1993 tx_resources = hif_get_free_queue_number(target->hif_dev, 1994 pEndpoint->UL_PipeID); 1995 1996 if (tx_resources < HTC_DATA_RESOURCE_THRS) { 1997 if (pEndpoint->ul_is_polled) { 1998 hif_send_complete_check(pEndpoint->target->hif_dev, 1999 pEndpoint->UL_PipeID, 1); 2000 tx_resources = 2001 hif_get_free_queue_number(target->hif_dev, 2002 pEndpoint->UL_PipeID); 2003 } 2004 if (tx_resources < HTC_DATA_MINDESC_PERPACKET) 2005 return QDF_STATUS_E_FAILURE; 2006 } 2007 2008 rtpm_code = htc_send_pkts_get_rtpm_id( 2009 pEndpoint->service_id); 2010 if (hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code)) 2011 return QDF_STATUS_E_FAILURE; 2012 2013 p_htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 2014 AR_DEBUG_ASSERT(p_htc_hdr); 2015 2016 data_attr = qdf_nbuf_data_attr_get(netbuf); 2017 2018 if (target->htc_hdr_length_check) 2019 htc_payload_len = actual_length - HTC_HEADER_LEN; 2020 2021 HTC_WRITE32(p_htc_hdr, SM(htc_payload_len, HTC_FRAME_HDR_PAYLOADLEN) 2022 | SM(ep_id, HTC_FRAME_HDR_ENDPOINTID)); 2023 /* 2024 * If the HIF pipe for the data endpoint is polled rather than 2025 * interrupt-driven, this is a good point to check whether any 2026 * data previously sent through the HIF pipe have finished being 2027 * sent. 2028 * Since this may result in callbacks to htc_tx_completion_handler, 2029 * which can take the HTC tx lock, make the hif_send_complete_check 2030 * call before acquiring the HTC tx lock. 2031 * Call hif_send_complete_check directly, rather than calling 2032 * htc_send_complete_check, and call the PollTimerStart separately 2033 * after calling hif_send_head, so the timer will be started to 2034 * check for completion of the new outstanding download (in the 2035 * unexpected event that other polling calls don't catch it). 2036 */ 2037 2038 LOCK_HTC_TX(target); 2039 2040 HTC_WRITE32(((uint32_t *)p_htc_hdr) + 1, 2041 SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1)); 2042 2043 pEndpoint->SeqNo++; 2044 2045 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); 2046 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 2047 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf), 2048 sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); 2049 status = hif_send_head(target->hif_dev, 2050 pEndpoint->UL_PipeID, 2051 pEndpoint->Id, actual_length, netbuf, data_attr); 2052 2053 UNLOCK_HTC_TX(target); 2054 return status; 2055 } 2056 #else /*ATH_11AC_TXCOMPACT */ 2057 2058 /** 2059 * htc_send_data_pkt() - htc_send_data_pkt 2060 * @HTCHandle: pointer to HTC handle 2061 * @pPacket: pointer to HTC_PACKET 2062 * @more_data: indicates whether more data is to follow 2063 * 2064 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 2065 */ 2066 QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, 2067 uint8_t more_data) 2068 { 2069 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2070 HTC_ENDPOINT *pEndpoint; 2071 HTC_FRAME_HDR *pHtcHdr; 2072 HTC_PACKET_QUEUE sendQueue; 2073 qdf_nbuf_t netbuf = NULL; 2074 int tx_resources; 2075 QDF_STATUS status = QDF_STATUS_SUCCESS; 2076 uint32_t data_attr = 0; 2077 bool used_extra_tx_credit = false; 2078 2079 if (pPacket) { 2080 if ((pPacket->Endpoint >= ENDPOINT_MAX) || 2081 (pPacket->Endpoint <= ENDPOINT_UNUSED)) { 2082 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2083 ("%s endpoint is invalid\n", __func__)); 2084 AR_DEBUG_ASSERT(0); 2085 return QDF_STATUS_E_INVAL; 2086 } 2087 pEndpoint = &target->endpoint[pPacket->Endpoint]; 2088 2089 /* add HTC_FRAME_HDR in the initial fragment */ 2090 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 2091 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); 2092 AR_DEBUG_ASSERT(pHtcHdr); 2093 2094 HTC_WRITE32(pHtcHdr, 2095 SM(pPacket->ActualLength, 2096 HTC_FRAME_HDR_PAYLOADLEN) | 2097 SM(pPacket->PktInfo.AsTx.SendFlags, 2098 HTC_FRAME_HDR_FLAGS) | 2099 SM(pPacket->Endpoint, 2100 HTC_FRAME_HDR_ENDPOINTID)); 2101 /* 2102 * If the HIF pipe for the data endpoint is polled rather than 2103 * interrupt-driven, this is a good point to check whether any 2104 * data previously sent through the HIF pipe have finished being 2105 * sent. Since this may result in callbacks to 2106 * htc_tx_completion_handler, which can take the HTC tx lock, 2107 * make the hif_send_complete_check call before acquiring the 2108 * HTC tx lock. 2109 * Call hif_send_complete_check directly, rather than calling 2110 * htc_send_complete_check, and call the PollTimerStart 2111 * separately after calling hif_send_head, so the timer will be 2112 * started to check for completion of the new outstanding 2113 * download (in the unexpected event that other polling calls 2114 * don't catch it). 2115 */ 2116 if (pEndpoint->ul_is_polled) { 2117 htc_send_complete_poll_timer_stop(pEndpoint); 2118 hif_send_complete_check(pEndpoint->target->hif_dev, 2119 pEndpoint->UL_PipeID, 0); 2120 } 2121 2122 LOCK_HTC_TX(target); 2123 2124 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; 2125 pEndpoint->SeqNo++; 2126 2127 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, 2128 SM(pPacket->PktInfo.AsTx.SeqNo, 2129 HTC_FRAME_HDR_CONTROLBYTES1)); 2130 2131 /* append new packet to pEndpoint->TxQueue */ 2132 HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket); 2133 if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) { 2134 UNLOCK_HTC_TX(target); 2135 return QDF_STATUS_SUCCESS; 2136 } 2137 2138 QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); 2139 DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 2140 QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf), 2141 sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); 2142 } else { 2143 LOCK_HTC_TX(target); 2144 pEndpoint = &target->endpoint[1]; 2145 } 2146 2147 /* increment tx processing count on entry */ 2148 qdf_atomic_inc(&pEndpoint->TxProcessCount); 2149 if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) { 2150 /* 2151 * Another thread or task is draining the TX queues on this 2152 * endpoint. That thread will reset the tx processing count when 2153 * the queue is drained. 2154 */ 2155 qdf_atomic_dec(&pEndpoint->TxProcessCount); 2156 UNLOCK_HTC_TX(target); 2157 return QDF_STATUS_SUCCESS; 2158 } 2159 2160 /***** beyond this point only 1 thread may enter ******/ 2161 2162 INIT_HTC_PACKET_QUEUE(&sendQueue); 2163 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 2164 #if DEBUG_CREDIT 2165 int cred = pEndpoint->TxCredits; 2166 #endif 2167 get_htc_send_packets_credit_based(target, pEndpoint, 2168 &sendQueue); 2169 #if DEBUG_CREDIT 2170 if (ep_debug_mask & (1 << pEndpoint->Id)) { 2171 if (cred - pEndpoint->TxCredits > 0) { 2172 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2173 (" <HTC> Decrease EP%d %d - %d = %d credits.\n", 2174 pEndpoint->Id, cred, 2175 cred - pEndpoint->TxCredits, 2176 pEndpoint->TxCredits)); 2177 } 2178 } 2179 #endif 2180 UNLOCK_HTC_TX(target); 2181 } 2182 2183 else if (HTC_TX_BUNDLE_ENABLED(target)) { 2184 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) { 2185 if (hif_get_free_queue_number(target->hif_dev, 2186 pEndpoint->UL_PipeID)) 2187 /* 2188 * Header and payload belongs to the different 2189 * fragments and consume 2 resource for one HTC 2190 * package but USB combine into one transfer. 2191 */ 2192 get_htc_send_packets(target, pEndpoint, 2193 &sendQueue, 2194 HTC_MAX_MSG_PER_BUNDLE_TX 2195 * 2); 2196 } else { 2197 /* Dequeue max packets from endpoint tx queue */ 2198 get_htc_send_packets(target, pEndpoint, &sendQueue, 2199 HTC_MAX_TX_BUNDLE_SEND_LIMIT); 2200 } 2201 UNLOCK_HTC_TX(target); 2202 } else { 2203 /* 2204 * Now drain the endpoint TX queue for transmission as long as 2205 * we have enough transmit resources 2206 */ 2207 tx_resources = 2208 hif_get_free_queue_number(target->hif_dev, 2209 pEndpoint->UL_PipeID); 2210 get_htc_send_packets(target, pEndpoint, &sendQueue, 2211 tx_resources); 2212 UNLOCK_HTC_TX(target); 2213 } 2214 2215 /* send what we can */ 2216 while (true) { 2217 if (HTC_TX_BUNDLE_ENABLED(target) && 2218 (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= 2219 HTC_MIN_MSG_PER_BUNDLE) && 2220 (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO || 2221 hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) { 2222 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2223 if (htc_tx_pad_credit_avail(pEndpoint) < 1) { 2224 status = QDF_STATUS_E_RESOURCES; 2225 /* put the sendQueue back at the front 2226 * of pEndpoint->TxQueue 2227 */ 2228 LOCK_HTC_TX(target); 2229 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD( 2230 &pEndpoint->TxQueue, 2231 &sendQueue); 2232 UNLOCK_HTC_TX(target); 2233 break; 2234 } 2235 } 2236 htc_issue_packets_bundle(target, pEndpoint, &sendQueue); 2237 } 2238 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2239 if (htc_tx_pad_credit_avail(pEndpoint) < 1) { 2240 status = QDF_STATUS_E_RESOURCES; 2241 /* put the sendQueue back at the front 2242 * of pEndpoint->TxQueue 2243 */ 2244 LOCK_HTC_TX(target); 2245 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD( 2246 &pEndpoint->TxQueue, 2247 &sendQueue); 2248 UNLOCK_HTC_TX(target); 2249 break; 2250 } 2251 } 2252 pPacket = htc_packet_dequeue(&sendQueue); 2253 if (!pPacket) 2254 break; 2255 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 2256 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0); 2257 2258 LOCK_HTC_TX(target); 2259 /* store in look up queue to match completions */ 2260 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); 2261 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); 2262 pEndpoint->ul_outstanding_cnt++; 2263 UNLOCK_HTC_TX(target); 2264 2265 used_extra_tx_credit = 2266 htc_handle_extra_tx_credit(pEndpoint, pPacket, 2267 (uint8_t *)pHtcHdr, 2268 NULL, 2269 pPacket->ActualLength 2270 + HTC_HDR_LENGTH); 2271 2272 status = hif_send_head(target->hif_dev, 2273 pEndpoint->UL_PipeID, 2274 pEndpoint->Id, 2275 HTC_HDR_LENGTH + pPacket->ActualLength, 2276 netbuf, data_attr); 2277 if (status != QDF_STATUS_SUCCESS) { 2278 if (pEndpoint->EpCallBacks.ep_padding_credit_update) { 2279 if (used_extra_tx_credit) { 2280 pEndpoint->EpCallBacks. 2281 ep_padding_credit_update 2282 (pEndpoint->EpCallBacks.pContext, 1); 2283 } 2284 } 2285 } 2286 #if DEBUG_BUNDLE 2287 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.", 2288 pEndpoint->Id, 2289 pEndpoint->TxCreditSize, 2290 HTC_HDR_LENGTH + pPacket->ActualLength); 2291 #endif 2292 2293 htc_issue_tx_bundle_stats_inc(target); 2294 2295 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 2296 LOCK_HTC_TX(target); 2297 pEndpoint->ul_outstanding_cnt--; 2298 /* remove this packet from the tx completion queue */ 2299 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); 2300 2301 /* 2302 * Don't bother reclaiming credits - HTC flow control 2303 * is not applicable to tx data. 2304 * In LL systems, there is no download flow control, 2305 * since there's virtually no download delay. 2306 * In HL systems, the txrx SW explicitly performs the 2307 * tx flow control. 2308 */ 2309 /* pEndpoint->TxCredits += 2310 * pPacket->PktInfo.AsTx.CreditsUsed; 2311 */ 2312 2313 /* put this frame back at the front of the sendQueue */ 2314 HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket); 2315 2316 /* put the sendQueue back at the front of 2317 * pEndpoint->TxQueue 2318 */ 2319 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 2320 &sendQueue); 2321 UNLOCK_HTC_TX(target); 2322 break; /* still need to reset TxProcessCount */ 2323 } 2324 } 2325 /* done with this endpoint, we can clear the count */ 2326 qdf_atomic_init(&pEndpoint->TxProcessCount); 2327 2328 if (pEndpoint->ul_is_polled) { 2329 /* 2330 * Start a cleanup timer to poll for download completion. 2331 * The download completion should be noticed promptly from 2332 * other polling calls, but the timer provides a safety net 2333 * in case other polling calls don't occur as expected. 2334 */ 2335 htc_send_complete_poll_timer_start(pEndpoint); 2336 } 2337 2338 return status; 2339 } 2340 #endif /*ATH_11AC_TXCOMPACT */ 2341 qdf_export_symbol(htc_send_data_pkt); 2342 2343 /* 2344 * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC, 2345 * since upper layers expects HTC_PACKET containers we use the completed netbuf 2346 * and lookup its corresponding HTC packet buffer from a lookup list. 2347 * This is extra overhead that can be fixed by re-aligning HIF interfaces 2348 * with HTC. 2349 * 2350 */ 2351 static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, 2352 HTC_ENDPOINT *pEndpoint, 2353 qdf_nbuf_t netbuf) 2354 { 2355 HTC_PACKET *pPacket = NULL; 2356 HTC_PACKET *pFoundPacket = NULL; 2357 HTC_PACKET_QUEUE lookupQueue; 2358 2359 INIT_HTC_PACKET_QUEUE(&lookupQueue); 2360 LOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2361 2362 LOCK_HTC_TX(target); 2363 /* mark that HIF has indicated the send complete for another packet */ 2364 pEndpoint->ul_outstanding_cnt--; 2365 2366 /* Dequeue first packet directly because of in-order completion */ 2367 pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue); 2368 if (qdf_unlikely(!pPacket)) { 2369 UNLOCK_HTC_TX(target); 2370 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2371 return NULL; 2372 } 2373 if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { 2374 UNLOCK_HTC_TX(target); 2375 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2376 return pPacket; 2377 } 2378 HTC_PACKET_ENQUEUE(&lookupQueue, pPacket); 2379 2380 /* 2381 * Move TX lookup queue to temp queue because most of packets that are 2382 * not index 0 are not top 10 packets. 2383 */ 2384 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue, 2385 &pEndpoint->TxLookupQueue); 2386 2387 ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket, 2388 HTC_PACKET, ListLink) { 2389 2390 if (!pPacket) { 2391 pFoundPacket = pPacket; 2392 break; 2393 } 2394 /* check for removal */ 2395 if (netbuf == 2396 (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { 2397 /* found it */ 2398 HTC_PACKET_REMOVE(&lookupQueue, pPacket); 2399 pFoundPacket = pPacket; 2400 break; 2401 } 2402 2403 } 2404 ITERATE_END; 2405 2406 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue, 2407 &lookupQueue); 2408 UNLOCK_HTC_TX(target); 2409 UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); 2410 2411 return pFoundPacket; 2412 } 2413 2414 /** 2415 * htc_tx_completion_handler() - htc tx completion handler 2416 * @Context: pointer to HTC_TARGET structure 2417 * @netbuf: pointer to netbuf for which completion handler is being called 2418 * @EpID: end point Id on which the packet was sent 2419 * @toeplitz_hash_result: toeplitz hash result 2420 * 2421 * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error 2422 */ 2423 QDF_STATUS htc_tx_completion_handler(void *Context, 2424 qdf_nbuf_t netbuf, unsigned int EpID, 2425 uint32_t toeplitz_hash_result) 2426 { 2427 HTC_TARGET *target = (HTC_TARGET *) Context; 2428 HTC_ENDPOINT *pEndpoint; 2429 HTC_PACKET *pPacket; 2430 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 2431 HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4, 2432 ENDPOINT_2, ENDPOINT_3 }; 2433 int epidIdx; 2434 uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */ 2435 uint16_t resources; 2436 uint16_t resourcesMax; 2437 #endif 2438 2439 pEndpoint = &target->endpoint[EpID]; 2440 target->TX_comp_cnt++; 2441 pEndpoint->htc_comp_cnt++; 2442 2443 do { 2444 pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf); 2445 if (!pPacket) { 2446 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2447 ("HTC TX lookup failed!\n")); 2448 /* may have already been flushed and freed */ 2449 netbuf = NULL; 2450 break; 2451 } 2452 if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM && 2453 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RUNTIME_PUT && 2454 pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RTPM_PUT_RC) 2455 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_WMI); 2456 2457 2458 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) { 2459 HTC_PACKET *pPacketTemp; 2460 HTC_PACKET_QUEUE *pQueueSave = 2461 (HTC_PACKET_QUEUE *) pPacket->pContext; 2462 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave, 2463 pPacketTemp) { 2464 pPacket->Status = QDF_STATUS_SUCCESS; 2465 send_packet_completion(target, pPacketTemp); 2466 } 2467 HTC_PACKET_QUEUE_ITERATE_END; 2468 free_htc_bundle_packet(target, pPacket); 2469 2470 if (hif_get_bus_type(target->hif_dev) == 2471 QDF_BUS_TYPE_USB) { 2472 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) 2473 htc_try_send(target, pEndpoint, NULL); 2474 } 2475 2476 return QDF_STATUS_SUCCESS; 2477 } 2478 /* will be giving this buffer back to upper layers */ 2479 netbuf = NULL; 2480 pPacket->Status = QDF_STATUS_SUCCESS; 2481 send_packet_completion(target, pPacket); 2482 2483 } while (false); 2484 2485 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 2486 /* note: when using TX credit flow, the re-checking of queues 2487 * happens when credits flow back from the target. In the non-TX 2488 * credit case, we recheck after the packet completes 2489 */ 2490 if ((qdf_atomic_read(&pEndpoint->TxProcessCount) == 0) || 2491 (!pEndpoint->async_update)) { 2492 htc_try_send(target, pEndpoint, NULL); 2493 } 2494 } 2495 2496 return QDF_STATUS_SUCCESS; 2497 } 2498 2499 #ifdef WLAN_FEATURE_FASTPATH 2500 /** 2501 * htc_ctrl_msg_cmpl(): checks for tx completion for the endpoint specified 2502 * @HTC_HANDLE : pointer to the htc target context 2503 * @htc_ep_id : end point id 2504 * 2505 * checks HTC tx completion 2506 * 2507 * Return: none 2508 */ 2509 void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id) 2510 { 2511 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev); 2512 HTC_ENDPOINT *pendpoint = &target->endpoint[htc_ep_id]; 2513 2514 htc_send_complete_check(pendpoint, 1); 2515 } 2516 qdf_export_symbol(htc_ctrl_msg_cmpl); 2517 #endif 2518 2519 /* callback when TX resources become available */ 2520 void htc_tx_resource_avail_handler(void *context, uint8_t pipeID) 2521 { 2522 int i; 2523 HTC_TARGET *target = (HTC_TARGET *) context; 2524 HTC_ENDPOINT *pEndpoint = NULL; 2525 2526 for (i = 0; i < ENDPOINT_MAX; i++) { 2527 pEndpoint = &target->endpoint[i]; 2528 if (pEndpoint->service_id != 0) { 2529 if (pEndpoint->UL_PipeID == pipeID) 2530 break; 2531 } 2532 } 2533 2534 if (i >= ENDPOINT_MAX) { 2535 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2536 ("Invalid pipe indicated for TX resource avail : %d!\n", 2537 pipeID)); 2538 return; 2539 } 2540 2541 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2542 ("HIF indicated more resources for pipe:%d\n", 2543 pipeID)); 2544 2545 htc_try_send(target, pEndpoint, NULL); 2546 } 2547 2548 #ifdef FEATURE_RUNTIME_PM 2549 /** 2550 * htc_kick_queues(): resumes tx transactions of suspended endpoints 2551 * @context: pointer to the htc target context 2552 * 2553 * Iterates through the endpoints and provides a context to empty queues 2554 * int the hif layer when they are stalled due to runtime suspend. 2555 * 2556 * Return: none 2557 */ 2558 void htc_kick_queues(void *context) 2559 { 2560 int i; 2561 HTC_TARGET *target = (HTC_TARGET *)context; 2562 HTC_ENDPOINT *endpoint = NULL; 2563 2564 if (hif_rtpm_get(HIF_RTPM_GET_SYNC, HIF_RTPM_ID_HTT)) 2565 return; 2566 2567 for (i = 0; i < ENDPOINT_MAX; i++) { 2568 endpoint = &target->endpoint[i]; 2569 2570 if (endpoint->service_id == 0) 2571 continue; 2572 2573 if (endpoint->EpCallBacks.ep_resume_tx_queue) 2574 endpoint->EpCallBacks.ep_resume_tx_queue( 2575 endpoint->EpCallBacks.pContext); 2576 2577 htc_try_send(target, endpoint, NULL); 2578 } 2579 2580 hif_fastpath_resume(target->hif_dev); 2581 2582 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT); 2583 } 2584 #endif 2585 2586 /* flush endpoint TX queue */ 2587 void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, 2588 HTC_TX_TAG Tag) 2589 { 2590 HTC_PACKET *pPacket; 2591 2592 LOCK_HTC_TX(target); 2593 while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { 2594 pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); 2595 2596 if (pPacket) { 2597 /* let the sender know the packet was not delivered */ 2598 pPacket->Status = QDF_STATUS_E_CANCELED; 2599 send_packet_completion(target, pPacket); 2600 } 2601 } 2602 UNLOCK_HTC_TX(target); 2603 } 2604 2605 /* flush pending entries in endpoint TX Lookup queue */ 2606 void htc_flush_endpoint_txlookupQ(HTC_TARGET *target, 2607 HTC_ENDPOINT_ID endpoint_id, 2608 bool call_ep_callback) 2609 { 2610 HTC_PACKET *packet; 2611 HTC_ENDPOINT *endpoint; 2612 2613 endpoint = &target->endpoint[endpoint_id]; 2614 2615 if (!endpoint && endpoint->service_id == 0) 2616 return; 2617 2618 LOCK_HTC_TX(target); 2619 while (HTC_PACKET_QUEUE_DEPTH(&endpoint->TxLookupQueue)) { 2620 packet = htc_packet_dequeue(&endpoint->TxLookupQueue); 2621 2622 if (packet) { 2623 if (call_ep_callback == true) { 2624 packet->Status = QDF_STATUS_E_CANCELED; 2625 send_packet_completion(target, packet); 2626 } else { 2627 qdf_mem_free(packet); 2628 } 2629 } 2630 } 2631 UNLOCK_HTC_TX(target); 2632 } 2633 2634 /* HTC API to flush an endpoint's TX queue*/ 2635 void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, 2636 HTC_TX_TAG Tag) 2637 { 2638 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2639 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; 2640 2641 if (pEndpoint->service_id == 0) { 2642 AR_DEBUG_ASSERT(false); 2643 /* not in use.. */ 2644 return; 2645 } 2646 2647 htc_flush_endpoint_tx(target, pEndpoint, Tag); 2648 } 2649 2650 /* HTC API to indicate activity to the credit distribution function */ 2651 void htc_indicate_activity_change(HTC_HANDLE HTCHandle, 2652 HTC_ENDPOINT_ID Endpoint, bool Active) 2653 { 2654 /* TODO */ 2655 } 2656 2657 bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) 2658 { 2659 return true; 2660 } 2661 2662 void htc_set_pkt_dbg(HTC_HANDLE handle, A_BOOL dbg_flag) 2663 { 2664 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(handle); 2665 2666 target->htc_pkt_dbg = dbg_flag; 2667 } 2668 2669 void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt) 2670 { 2671 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2672 2673 target->is_nodrop_pkt = isNodropPkt; 2674 } 2675 2676 void htc_enable_hdr_length_check(HTC_HANDLE htc_hdl, bool htc_hdr_length_check) 2677 { 2678 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl); 2679 2680 target->htc_hdr_length_check = htc_hdr_length_check; 2681 } 2682 2683 /** 2684 * htc_process_credit_rpt() - process credit report, call distribution function 2685 * @target: pointer to HTC_TARGET 2686 * @pRpt: pointer to HTC_CREDIT_REPORT 2687 * @NumEntries: number of entries in credit report 2688 * @FromEndpoint: endpoint for which credit report is received 2689 * 2690 * Return: A_OK for success or an appropriate A_STATUS error 2691 */ 2692 void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, 2693 int NumEntries, HTC_ENDPOINT_ID FromEndpoint) 2694 { 2695 int i; 2696 HTC_ENDPOINT *pEndpoint; 2697 int totalCredits = 0; 2698 uint8_t rpt_credits, rpt_ep_id; 2699 2700 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2701 ("+htc_process_credit_rpt, Credit Report Entries:%d\n", 2702 NumEntries)); 2703 2704 /* lock out TX while we update credits */ 2705 LOCK_HTC_TX(target); 2706 2707 for (i = 0; i < NumEntries; i++, pRpt++) { 2708 2709 rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID); 2710 2711 if (rpt_ep_id >= ENDPOINT_MAX) { 2712 AR_DEBUG_ASSERT(false); 2713 break; 2714 } 2715 2716 rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS); 2717 2718 pEndpoint = &target->endpoint[rpt_ep_id]; 2719 #if DEBUG_CREDIT 2720 if (ep_debug_mask & (1 << pEndpoint->Id)) { 2721 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 2722 (" <HTC> Increase EP%d %d + %d = %d credits\n", 2723 rpt_ep_id, pEndpoint->TxCredits, 2724 rpt_credits, 2725 pEndpoint->TxCredits + rpt_credits)); 2726 } 2727 #endif 2728 2729 #ifdef HTC_EP_STAT_PROFILING 2730 2731 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1); 2732 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits); 2733 2734 if (FromEndpoint == rpt_ep_id) { 2735 /* this credit report arrived on the same endpoint 2736 * indicating it arrived in an RX packet 2737 */ 2738 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, 2739 rpt_credits); 2740 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1); 2741 } else if (FromEndpoint == ENDPOINT_0) { 2742 /* this credit arrived on endpoint 0 as a NULL msg */ 2743 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, 2744 rpt_credits); 2745 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1); 2746 } else { 2747 /* arrived on another endpoint */ 2748 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, 2749 rpt_credits); 2750 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1); 2751 } 2752 2753 #endif 2754 2755 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 2756 htc_credit_record(HTC_PROCESS_CREDIT_REPORT, 2757 pEndpoint->TxCredits + rpt_credits, 2758 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 2759 TxQueue)); 2760 hif_latency_detect_credit_record_time( 2761 HIF_PROCESS_CREDIT_REPORT, 2762 target->hif_dev); 2763 } 2764 2765 pEndpoint->TxCredits += rpt_credits; 2766 2767 if (pEndpoint->TxCredits 2768 && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { 2769 UNLOCK_HTC_TX(target); 2770 #ifdef ATH_11AC_TXCOMPACT 2771 htc_try_send(target, pEndpoint, NULL); 2772 #else 2773 if (pEndpoint->service_id == HTT_DATA_MSG_SVC) 2774 htc_send_data_pkt((HTC_HANDLE)target, NULL, 0); 2775 else 2776 htc_try_send(target, pEndpoint, NULL); 2777 #endif 2778 LOCK_HTC_TX(target); 2779 } 2780 totalCredits += rpt_credits; 2781 } 2782 2783 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2784 (" Report indicated %d credits to distribute\n", 2785 totalCredits)); 2786 2787 UNLOCK_HTC_TX(target); 2788 2789 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt\n")); 2790 } 2791 2792 /* function to fetch stats from htc layer*/ 2793 struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) 2794 { 2795 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2796 2797 return &(target->htc_pkt_stats); 2798 } 2799 2800 #ifdef SYSTEM_PM_CHECK 2801 void htc_system_resume(HTC_HANDLE htc) 2802 { 2803 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc); 2804 HTC_ENDPOINT *endpoint = NULL; 2805 int i; 2806 2807 if (!target) 2808 return; 2809 2810 for (i = 0; i < ENDPOINT_MAX; i++) { 2811 endpoint = &target->endpoint[i]; 2812 2813 if (endpoint->service_id == 0) 2814 continue; 2815 2816 htc_try_send(target, endpoint, NULL); 2817 } 2818 } 2819 #endif 2820