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