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