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