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