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