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