1 /* 2 * Copyright (c) 2013-2018 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 != NULL) 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 (NULL == 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 AR_DEBUG_ASSERT(pQueueSave); 234 235 INIT_HTC_PACKET_QUEUE(pQueueSave); 236 237 LOCK_HTC_TX(target); 238 if (target->pBundleFreeList == NULL) { 239 target->pBundleFreeList = pPacket; 240 pPacket->ListLink.pNext = NULL; 241 } else { 242 pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList; 243 target->pBundleFreeList = pPacket; 244 } 245 UNLOCK_HTC_TX(target); 246 } 247 248 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) 249 250 /** 251 * htc_send_update_tx_bundle_stats() - update tx bundle stats depends 252 * on max bundle size 253 * @target: hif context 254 * @data_len: tx data len 255 * @TxCreditSize: endpoint tx credit size 256 * 257 * Return: None 258 */ 259 static inline void 260 htc_send_update_tx_bundle_stats(HTC_TARGET *target, 261 qdf_size_t data_len, 262 int TxCreditSize) 263 { 264 if ((data_len / TxCreditSize) <= HTC_MAX_MSG_PER_BUNDLE_TX) 265 target->tx_bundle_stats[(data_len / TxCreditSize) - 1]++; 266 } 267 268 /** 269 * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats 270 * on max bundle size 271 * @target: hif context 272 * 273 * Return: None 274 */ 275 static inline void 276 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) 277 { 278 target->tx_bundle_stats[0]++; 279 } 280 #else 281 282 static inline void 283 htc_send_update_tx_bundle_stats(HTC_TARGET *target, 284 qdf_size_t data_len, 285 int TxCreditSize) 286 { 287 } 288 289 static inline void 290 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) 291 { 292 } 293 #endif 294 295 #if defined(HIF_USB) || defined(HIF_SDIO) 296 #ifdef ENABLE_BUNDLE_TX 297 static QDF_STATUS htc_send_bundled_netbuf(HTC_TARGET *target, 298 HTC_ENDPOINT *pEndpoint, 299 unsigned char *pBundleBuffer, 300 HTC_PACKET *pPacketTx) 301 { 302 qdf_size_t data_len; 303 QDF_STATUS status; 304 qdf_nbuf_t bundleBuf; 305 uint32_t data_attr = 0; 306 307 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 308 data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf); 309 qdf_nbuf_put_tail(bundleBuf, data_len); 310 SET_HTC_PACKET_INFO_TX(pPacketTx, 311 target, 312 pBundleBuffer, 313 data_len, 314 pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED); 315 LOCK_HTC_TX(target); 316 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx); 317 pEndpoint->ul_outstanding_cnt++; 318 UNLOCK_HTC_TX(target); 319 #if DEBUG_BUNDLE 320 qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.\n", 321 pEndpoint->Id, 322 pEndpoint->TxCreditSize, 323 data_len, data_len / pEndpoint->TxCreditSize); 324 #endif 325 326 htc_send_update_tx_bundle_stats(target, data_len, 327 pEndpoint->TxCreditSize); 328 329 status = hif_send_head(target->hif_dev, 330 pEndpoint->UL_PipeID, 331 pEndpoint->Id, data_len, 332 bundleBuf, data_attr); 333 if (status != QDF_STATUS_SUCCESS) { 334 qdf_print("%s:hif_send_head failed(len=%zu).\n", __func__, 335 data_len); 336 } 337 return status; 338 } 339 340 /** 341 * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue 342 * @target: HTC target on which packets need to be sent 343 * @pEndpoint: logical endpoint on which packets needs to be sent 344 * @pPktQueue: HTC packet queue containing the list of packets to be sent 345 * 346 * Return: void 347 */ 348 static void htc_issue_packets_bundle(HTC_TARGET *target, 349 HTC_ENDPOINT *pEndpoint, 350 HTC_PACKET_QUEUE *pPktQueue) 351 { 352 int i, frag_count, nbytes; 353 qdf_nbuf_t netbuf, bundleBuf; 354 unsigned char *pBundleBuffer = NULL; 355 HTC_PACKET *pPacket = NULL, *pPacketTx = NULL; 356 HTC_FRAME_HDR *pHtcHdr; 357 int last_credit_pad = 0; 358 int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining = 359 0; 360 HTC_PACKET_QUEUE *pQueueSave = NULL; 361 362 bundlesSpaceRemaining = 363 target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize; 364 pPacketTx = allocate_htc_bundle_packet(target); 365 if (!pPacketTx) { 366 /* good time to panic */ 367 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 368 ("allocate_htc_bundle_packet failed\n")); 369 AR_DEBUG_ASSERT(false); 370 return; 371 } 372 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 373 pBundleBuffer = qdf_nbuf_data(bundleBuf); 374 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; 375 while (1) { 376 pPacket = htc_packet_dequeue(pPktQueue); 377 if (pPacket == NULL) 378 break; 379 creditPad = 0; 380 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; 381 creditRemainder = transferLength % pEndpoint->TxCreditSize; 382 if (creditRemainder != 0) { 383 if (transferLength < pEndpoint->TxCreditSize) { 384 creditPad = pEndpoint->TxCreditSize - 385 transferLength; 386 } else { 387 creditPad = creditRemainder; 388 } 389 transferLength += creditPad; 390 } 391 392 if (bundlesSpaceRemaining < transferLength) { 393 /* send out previous buffer */ 394 htc_send_bundled_netbuf(target, pEndpoint, 395 pBundleBuffer - last_credit_pad, 396 pPacketTx); 397 /* One packet has been dequeued from sending queue when enter 398 * this loop, so need to add 1 back for this checking. 399 */ 400 if ((HTC_PACKET_QUEUE_DEPTH(pPktQueue) + 1) < 401 HTC_MIN_MSG_PER_BUNDLE) { 402 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 403 return; 404 } 405 bundlesSpaceRemaining = 406 target->MaxMsgsPerHTCBundle * 407 pEndpoint->TxCreditSize; 408 pPacketTx = allocate_htc_bundle_packet(target); 409 if (!pPacketTx) { 410 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 411 /* good time to panic */ 412 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 413 ("allocate_htc_bundle_packet failed\n")); 414 AR_DEBUG_ASSERT(false); 415 return; 416 } 417 bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); 418 pBundleBuffer = qdf_nbuf_data(bundleBuf); 419 pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; 420 } 421 422 bundlesSpaceRemaining -= transferLength; 423 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 424 425 if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) { 426 pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr( 427 netbuf, 0); 428 HTC_WRITE32(pHtcHdr, 429 SM(pPacket->ActualLength, 430 HTC_FRAME_HDR_PAYLOADLEN) | 431 SM(pPacket->PktInfo.AsTx.SendFlags | 432 HTC_FLAGS_SEND_BUNDLE, 433 HTC_FRAME_HDR_FLAGS) | 434 SM(pPacket->Endpoint, 435 HTC_FRAME_HDR_ENDPOINTID)); 436 HTC_WRITE32((uint32_t *) pHtcHdr + 1, 437 SM(pPacket->PktInfo.AsTx.SeqNo, 438 HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad, 439 HTC_FRAME_HDR_RESERVED)); 440 pHtcHdr->reserved = creditPad; 441 } 442 frag_count = qdf_nbuf_get_num_frags(netbuf); 443 nbytes = pPacket->ActualLength + HTC_HDR_LENGTH; 444 for (i = 0; i < frag_count && nbytes > 0; i++) { 445 int frag_len = qdf_nbuf_get_frag_len(netbuf, i); 446 unsigned char *frag_addr = 447 qdf_nbuf_get_frag_vaddr(netbuf, i); 448 if (frag_len > nbytes) 449 frag_len = nbytes; 450 qdf_mem_copy(pBundleBuffer, frag_addr, frag_len); 451 nbytes -= frag_len; 452 pBundleBuffer += frag_len; 453 } 454 HTC_PACKET_ENQUEUE(pQueueSave, pPacket); 455 pBundleBuffer += creditPad; 456 457 /* last one can't be packed. */ 458 if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) 459 last_credit_pad = creditPad; 460 } 461 /* send out remaining buffer */ 462 if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) 463 htc_send_bundled_netbuf(target, pEndpoint, 464 pBundleBuffer - last_credit_pad, 465 pPacketTx); 466 else 467 free_htc_bundle_packet(target, pPacketTx); 468 } 469 #endif /* ENABLE_BUNDLE_TX */ 470 #else 471 static void htc_issue_packets_bundle(HTC_TARGET *target, 472 HTC_ENDPOINT *pEndpoint, 473 HTC_PACKET_QUEUE *pPktQueue) 474 { 475 } 476 #endif 477 478 /** 479 * htc_issue_packets() - HTC function to send packets from a queue 480 * @target: HTC target on which packets need to be sent 481 * @pEndpoint: logical endpoint on which packets needs to be sent 482 * @pPktQueue: HTC packet queue containing the list of packets to be sent 483 * 484 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure 485 */ 486 static QDF_STATUS htc_issue_packets(HTC_TARGET *target, 487 HTC_ENDPOINT *pEndpoint, 488 HTC_PACKET_QUEUE *pPktQueue) 489 { 490 QDF_STATUS status = QDF_STATUS_SUCCESS; 491 qdf_nbuf_t netbuf; 492 HTC_PACKET *pPacket = NULL; 493 uint16_t payloadLen; 494 HTC_FRAME_HDR *pHtcHdr; 495 uint32_t data_attr = 0; 496 enum qdf_bus_type bus_type; 497 QDF_STATUS ret; 498 bool rt_put = false; 499 500 bus_type = hif_get_bus_type(target->hif_dev); 501 502 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 503 ("+htc_issue_packets: Queue: %pK, Pkts %d\n", pPktQueue, 504 HTC_PACKET_QUEUE_DEPTH(pPktQueue))); 505 while (true) { 506 if (HTC_TX_BUNDLE_ENABLED(target) && 507 HTC_PACKET_QUEUE_DEPTH(pPktQueue) >= 508 HTC_MIN_MSG_PER_BUNDLE) { 509 switch (bus_type) { 510 case QDF_BUS_TYPE_SDIO: 511 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) 512 break; 513 case QDF_BUS_TYPE_USB: 514 htc_issue_packets_bundle(target, 515 pEndpoint, 516 pPktQueue); 517 break; 518 default: 519 break; 520 } 521 } 522 /* if not bundling or there was a packet that could not be 523 * placed in a bundle, and send it by normal way 524 */ 525 pPacket = htc_packet_dequeue(pPktQueue); 526 if (NULL == pPacket) { 527 /* local queue is fully drained */ 528 break; 529 } 530 531 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 532 AR_DEBUG_ASSERT(netbuf); 533 /* Non-credit enabled endpoints have been mapped and setup by 534 * now, so no need to revisit the HTC headers 535 */ 536 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 537 538 payloadLen = pPacket->ActualLength; 539 /* setup HTC frame header */ 540 541 pHtcHdr = (HTC_FRAME_HDR *) 542 qdf_nbuf_get_frag_vaddr(netbuf, 0); 543 AR_DEBUG_ASSERT(pHtcHdr); 544 545 HTC_WRITE32(pHtcHdr, 546 SM(payloadLen, 547 HTC_FRAME_HDR_PAYLOADLEN) | 548 SM(pPacket->PktInfo.AsTx.SendFlags, 549 HTC_FRAME_HDR_FLAGS) | 550 SM(pPacket->Endpoint, 551 HTC_FRAME_HDR_ENDPOINTID)); 552 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, 553 SM(pPacket->PktInfo.AsTx.SeqNo, 554 HTC_FRAME_HDR_CONTROLBYTES1)); 555 556 /* 557 * Now that the HTC frame header has been added, the 558 * netbuf can be mapped. This only applies to non-data 559 * frames, since data frames were already mapped as they 560 * entered into the driver. 561 */ 562 pPacket->PktInfo.AsTx.Flags |= 563 HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 564 565 ret = qdf_nbuf_map(target->osdev, 566 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 567 QDF_DMA_TO_DEVICE); 568 if (ret != QDF_STATUS_SUCCESS) { 569 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 570 ("%s nbuf Map Fail Endpnt %pK\n", 571 __func__, pEndpoint)); 572 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 573 status = QDF_STATUS_E_FAILURE; 574 break; 575 } 576 } 577 578 if (!pEndpoint->async_update) { 579 LOCK_HTC_TX(target); 580 } 581 /* store in look up queue to match completions */ 582 HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); 583 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); 584 pEndpoint->ul_outstanding_cnt++; 585 if (!pEndpoint->async_update) { 586 UNLOCK_HTC_TX(target); 587 hif_send_complete_check(target->hif_dev, 588 pEndpoint->UL_PipeID, false); 589 } 590 591 htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE); 592 /* 593 * For HTT messages without a response from fw, 594 * do the runtime put here. 595 * otherwise runtime put will be done when the fw response comes 596 */ 597 if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT) 598 rt_put = true; 599 #if DEBUG_BUNDLE 600 qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n", 601 pEndpoint->Id, 602 pEndpoint->TxCreditSize, 603 HTC_HDR_LENGTH + pPacket->ActualLength); 604 #endif 605 status = hif_send_head(target->hif_dev, 606 pEndpoint->UL_PipeID, pEndpoint->Id, 607 HTC_HDR_LENGTH + pPacket->ActualLength, 608 netbuf, data_attr); 609 610 htc_issue_tx_bundle_stats_inc(target); 611 612 target->ce_send_cnt++; 613 614 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 615 if (status != QDF_STATUS_E_RESOURCES) { 616 /* TODO : if more than 1 endpoint maps to the 617 * same PipeID it is possible to run out of 618 * resources in the HIF layer. Don't emit the 619 * error 620 */ 621 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 622 ("hif_send Failed status:%d\n", 623 status)); 624 } 625 qdf_nbuf_unmap(target->osdev, 626 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 627 QDF_DMA_TO_DEVICE); 628 if (!pEndpoint->async_update) { 629 LOCK_HTC_TX(target); 630 } 631 target->ce_send_cnt--; 632 pEndpoint->ul_outstanding_cnt--; 633 HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); 634 /* reclaim credits */ 635 pEndpoint->TxCredits += 636 pPacket->PktInfo.AsTx.CreditsUsed; 637 htc_packet_set_magic_cookie(pPacket, 0); 638 /* put it back into the callers queue */ 639 HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); 640 if (!pEndpoint->async_update) { 641 UNLOCK_HTC_TX(target); 642 } 643 break; 644 } 645 if (rt_put) { 646 hif_pm_runtime_put(target->hif_dev); 647 rt_put = false; 648 } 649 } 650 if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { 651 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 652 ("htc_issue_packets, failed pkt:0x%pK status:%d", 653 pPacket, status)); 654 } 655 656 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets\n")); 657 658 return status; 659 } 660 661 #ifdef FEATURE_RUNTIME_PM 662 /** 663 * extract_htc_pm_packets(): move pm packets from endpoint into queue 664 * @endpoint: which enpoint to extract packets from 665 * @queue: a queue to store extracted packets in. 666 * 667 * remove pm packets from the endpoint's tx queue. 668 * queue them into a queue 669 */ 670 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, 671 HTC_PACKET_QUEUE *queue) 672 { 673 HTC_PACKET *packet; 674 675 /* only WMI endpoint has power management packets */ 676 if (endpoint->service_id != WMI_CONTROL_SVC) 677 return; 678 679 ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, 680 HTC_PACKET, ListLink) { 681 if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) { 682 HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); 683 HTC_PACKET_ENQUEUE(queue, packet); 684 } 685 } ITERATE_END 686 } 687 688 /** 689 * queue_htc_pm_packets(): queue pm packets with priority 690 * @endpoint: enpoint to queue packets to 691 * @queue: queue of pm packets to enque 692 * 693 * suspend resume packets get special treatment & priority. 694 * need to queue them at the front of the queue. 695 */ 696 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, 697 HTC_PACKET_QUEUE *queue) 698 { 699 if (endpoint->service_id != WMI_CONTROL_SVC) 700 return; 701 702 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue); 703 } 704 #else 705 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, 706 HTC_PACKET_QUEUE *queue) 707 {} 708 709 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, 710 HTC_PACKET_QUEUE *queue) 711 {} 712 #endif 713 714 /** 715 * get_htc_send_packets_credit_based() - get packets based on available credits 716 * @target: HTC target on which packets need to be sent 717 * @pEndpoint: logical endpoint on which packets needs to be sent 718 * @pQueue: HTC packet queue containing the list of packets to be sent 719 * 720 * Get HTC send packets from TX queue on an endpoint based on available credits. 721 * The function moves the packets from TX queue of the endpoint to pQueue. 722 * 723 * Return: None 724 */ 725 static void get_htc_send_packets_credit_based(HTC_TARGET *target, 726 HTC_ENDPOINT *pEndpoint, 727 HTC_PACKET_QUEUE *pQueue) 728 { 729 int creditsRequired; 730 int remainder; 731 uint8_t sendFlags; 732 HTC_PACKET *pPacket; 733 unsigned int transferLength; 734 HTC_PACKET_QUEUE *tx_queue; 735 HTC_PACKET_QUEUE pm_queue; 736 bool do_pm_get = false; 737 738 /*** NOTE : the TX lock is held when this function is called ***/ 739 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 740 ("+get_htc_send_packets_credit_based\n")); 741 742 INIT_HTC_PACKET_QUEUE(&pm_queue); 743 extract_htc_pm_packets(pEndpoint, &pm_queue); 744 if (HTC_QUEUE_EMPTY(&pm_queue)) { 745 tx_queue = &pEndpoint->TxQueue; 746 do_pm_get = true; 747 } else { 748 tx_queue = &pm_queue; 749 } 750 751 /* loop until we can grab as many packets out of the queue as we can */ 752 while (true) { 753 if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) { 754 /* bus suspended, runtime resume issued */ 755 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 756 break; 757 } 758 759 sendFlags = 0; 760 /* get packet at head, but don't remove it */ 761 pPacket = htc_get_pkt_at_head(tx_queue); 762 if (pPacket == NULL) { 763 if (do_pm_get) 764 hif_pm_runtime_put(target->hif_dev); 765 break; 766 } 767 768 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 769 (" Got head packet:%pK , Queue Depth: %d\n", 770 pPacket, 771 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 772 773 transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; 774 775 if (transferLength <= pEndpoint->TxCreditSize) { 776 creditsRequired = 1; 777 } else { 778 /* figure out how many credits this message requires */ 779 creditsRequired = 780 transferLength / pEndpoint->TxCreditSize; 781 remainder = transferLength % pEndpoint->TxCreditSize; 782 783 if (remainder) 784 creditsRequired++; 785 } 786 787 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 788 (" Credits Required:%d Got:%d\n", 789 creditsRequired, pEndpoint->TxCredits)); 790 791 if (pEndpoint->Id == ENDPOINT_0) { 792 /* 793 * endpoint 0 is special, it always has a credit and 794 * does not require credit based flow control 795 */ 796 creditsRequired = 0; 797 } else { 798 799 if (pEndpoint->TxCredits < creditsRequired) { 800 #if DEBUG_CREDIT 801 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 802 ("EP%d,No Credit now.%d < %d\n", 803 pEndpoint->Id, 804 pEndpoint->TxCredits, 805 creditsRequired)); 806 #endif 807 if (do_pm_get) 808 hif_pm_runtime_put(target->hif_dev); 809 break; 810 } 811 812 pEndpoint->TxCredits -= creditsRequired; 813 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, 814 creditsRequired); 815 816 /* check if we need credits back from the target */ 817 if (pEndpoint->TxCredits <= 818 pEndpoint->TxCreditsPerMaxMsg) { 819 /* tell the target we need credits ASAP! */ 820 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; 821 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 822 htc_credit_record(HTC_REQUEST_CREDIT, 823 pEndpoint->TxCredits, 824 HTC_PACKET_QUEUE_DEPTH 825 (tx_queue)); 826 } 827 INC_HTC_EP_STAT(pEndpoint, 828 TxCreditLowIndications, 1); 829 #if DEBUG_CREDIT 830 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 831 (" EP%d Needs Credits\n", 832 pEndpoint->Id)); 833 #endif 834 } 835 } 836 837 /* now we can fully dequeue */ 838 pPacket = htc_packet_dequeue(tx_queue); 839 if (pPacket) { 840 /* save the number of credits this packet consumed */ 841 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; 842 /* save send flags */ 843 pPacket->PktInfo.AsTx.SendFlags = sendFlags; 844 845 /* queue this packet into the caller's queue */ 846 HTC_PACKET_ENQUEUE(pQueue, pPacket); 847 } 848 } 849 850 if (!HTC_QUEUE_EMPTY(&pm_queue)) 851 queue_htc_pm_packets(pEndpoint, &pm_queue); 852 853 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 854 ("-get_htc_send_packets_credit_based\n")); 855 856 } 857 858 static void get_htc_send_packets(HTC_TARGET *target, 859 HTC_ENDPOINT *pEndpoint, 860 HTC_PACKET_QUEUE *pQueue, int Resources) 861 { 862 863 HTC_PACKET *pPacket; 864 HTC_PACKET_QUEUE *tx_queue; 865 HTC_PACKET_QUEUE pm_queue; 866 bool do_pm_get = false; 867 868 /*** NOTE : the TX lock is held when this function is called ***/ 869 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 870 ("+get_htc_send_packets %d resources\n", Resources)); 871 872 INIT_HTC_PACKET_QUEUE(&pm_queue); 873 extract_htc_pm_packets(pEndpoint, &pm_queue); 874 if (HTC_QUEUE_EMPTY(&pm_queue)) { 875 tx_queue = &pEndpoint->TxQueue; 876 do_pm_get = true; 877 } else { 878 tx_queue = &pm_queue; 879 } 880 881 /* loop until we can grab as many packets out of the queue as we can */ 882 while (Resources > 0) { 883 int num_frags; 884 885 if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) { 886 /* bus suspended, runtime resume issued */ 887 QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); 888 break; 889 } 890 891 pPacket = htc_packet_dequeue(tx_queue); 892 if (pPacket == NULL) { 893 if (do_pm_get) 894 hif_pm_runtime_put(target->hif_dev); 895 break; 896 } 897 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 898 (" Got packet:%pK , New Queue Depth: %d\n", 899 pPacket, 900 HTC_PACKET_QUEUE_DEPTH(tx_queue))); 901 /* For non-credit path the sequence number is already embedded 902 * in the constructed HTC header 903 */ 904 pPacket->PktInfo.AsTx.SendFlags = 0; 905 pPacket->PktInfo.AsTx.CreditsUsed = 0; 906 /* queue this packet into the caller's queue */ 907 HTC_PACKET_ENQUEUE(pQueue, pPacket); 908 909 /* 910 * FIX THIS: 911 * For now, avoid calling qdf_nbuf_get_num_frags before calling 912 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't 913 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has 914 * been done. 915 * Assume that the non-data netbufs, i.e. WMI message netbufs, 916 * consist of a single fragment. 917 */ 918 /* WMI messages are in a single-fragment network buf */ 919 num_frags = 920 (pPacket->PktInfo.AsTx. 921 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 : 922 qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT 923 (pPacket)); 924 Resources -= num_frags; 925 } 926 927 if (!HTC_QUEUE_EMPTY(&pm_queue)) 928 queue_htc_pm_packets(pEndpoint, &pm_queue); 929 930 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n")); 931 932 } 933 934 /** 935 * htc_try_send() - Send packets in a queue on an endpoint 936 * @target: HTC target on which packets need to be sent 937 * @pEndpoint: logical endpoint on which packets needs to be sent 938 * @pCallersSendQueue: packet queue containing the list of packets to be sent 939 * 940 * Return: enum HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to 941 * be sent or the packet should be dropped by the upper layer 942 */ 943 static enum HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target, 944 HTC_ENDPOINT *pEndpoint, 945 HTC_PACKET_QUEUE *pCallersSendQueue) 946 { 947 /* temp queue to hold packets at various stages */ 948 HTC_PACKET_QUEUE sendQueue; 949 HTC_PACKET *pPacket; 950 int tx_resources; 951 int overflow; 952 enum HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; 953 954 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%pK Depth:%d)\n", 955 pCallersSendQueue, 956 (pCallersSendQueue == 957 NULL) ? 0 : 958 HTC_PACKET_QUEUE_DEPTH 959 (pCallersSendQueue))); 960 961 /* init the local send queue */ 962 INIT_HTC_PACKET_QUEUE(&sendQueue); 963 964 do { 965 966 /* caller didn't provide a queue, just wants us to check 967 * queues and send 968 */ 969 if (pCallersSendQueue == NULL) 970 break; 971 972 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { 973 /* empty queue */ 974 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 975 HTC_PKT_Q_EMPTY); 976 result = HTC_SEND_QUEUE_DROP; 977 break; 978 } 979 980 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= 981 pEndpoint->MaxTxQueueDepth) { 982 /* we've already overflowed */ 983 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 984 } else { 985 /* figure out how much we will overflow by */ 986 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 987 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 988 /* get how much we will overflow the TX queue by */ 989 overflow -= pEndpoint->MaxTxQueueDepth; 990 } 991 992 /* if overflow is negative or zero, we are okay */ 993 if (overflow > 0) { 994 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 995 ("Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d\n", 996 pEndpoint->Id, overflow, 997 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 998 TxQueue), 999 pEndpoint->MaxTxQueueDepth)); 1000 } 1001 if ((overflow <= 0) 1002 || (pEndpoint->EpCallBacks.EpSendFull == NULL)) { 1003 /* all packets will fit or caller did not provide send 1004 * full indication handler 1005 * just move all of them to local sendQueue object 1006 */ 1007 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, 1008 pCallersSendQueue); 1009 } else { 1010 int i; 1011 int goodPkts = 1012 HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - 1013 overflow; 1014 1015 A_ASSERT(goodPkts >= 0); 1016 /* we have overflowed and callback is provided. Dequeue 1017 * all non-overflow packets into the sendqueue 1018 */ 1019 for (i = 0; i < goodPkts; i++) { 1020 /* pop off caller's queue */ 1021 pPacket = htc_packet_dequeue(pCallersSendQueue); 1022 A_ASSERT(pPacket != NULL); 1023 /* insert into local queue */ 1024 HTC_PACKET_ENQUEUE(&sendQueue, pPacket); 1025 } 1026 1027 /* the caller's queue has all the packets that won't fit 1028 * walk through the caller's queue and indicate each one 1029 * to the send full handler 1030 */ 1031 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue-> 1032 QueueHead, pPacket, 1033 HTC_PACKET, ListLink) { 1034 1035 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1036 ("Indicating overflowed TX packet: %pK\n", 1037 pPacket)); 1038 /* 1039 * Remove headroom reserved for HTC_FRAME_HDR 1040 * before giving the packet back to the user via 1041 * the EpSendFull callback. 1042 */ 1043 restore_tx_packet(target, pPacket); 1044 1045 if (pEndpoint->EpCallBacks. 1046 EpSendFull(pEndpoint->EpCallBacks.pContext, 1047 pPacket) == HTC_SEND_FULL_DROP) { 1048 /* callback wants the packet dropped */ 1049 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1050 1); 1051 /* leave this one in the caller's queue 1052 * for cleanup 1053 */ 1054 } else { 1055 /* callback wants to keep this packet, 1056 * remove from caller's queue 1057 */ 1058 HTC_PACKET_REMOVE(pCallersSendQueue, 1059 pPacket); 1060 /* put it in the send queue 1061 * add HTC_FRAME_HDR space reservation 1062 * again 1063 */ 1064 qdf_nbuf_push_head 1065 (GET_HTC_PACKET_NET_BUF_CONTEXT 1066 (pPacket), 1067 sizeof(HTC_FRAME_HDR)); 1068 1069 HTC_PACKET_ENQUEUE(&sendQueue, pPacket); 1070 } 1071 1072 } 1073 ITERATE_END; 1074 1075 if (HTC_QUEUE_EMPTY(&sendQueue)) { 1076 /* no packets made it in, caller will cleanup */ 1077 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, 1078 HTC_SEND_Q_EMPTY); 1079 result = HTC_SEND_QUEUE_DROP; 1080 break; 1081 } 1082 } 1083 1084 } while (false); 1085 1086 if (result != HTC_SEND_QUEUE_OK) { 1087 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n", 1088 result)); 1089 return result; 1090 } 1091 1092 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1093 tx_resources = 1094 hif_get_free_queue_number(target->hif_dev, 1095 pEndpoint->UL_PipeID); 1096 } else { 1097 tx_resources = 0; 1098 } 1099 1100 LOCK_HTC_TX(target); 1101 1102 if (!HTC_QUEUE_EMPTY(&sendQueue)) { 1103 if (target->is_nodrop_pkt) { 1104 /* 1105 * nodrop pkts have higher priority than normal pkts, 1106 * insert nodrop pkt to head for proper 1107 * start/termination of test. 1108 */ 1109 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1110 &sendQueue); 1111 target->is_nodrop_pkt = false; 1112 } else { 1113 /* transfer packets to tail */ 1114 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue, 1115 &sendQueue); 1116 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); 1117 INIT_HTC_PACKET_QUEUE(&sendQueue); 1118 } 1119 } 1120 1121 /* increment tx processing count on entry */ 1122 if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) { 1123 /* another thread or task is draining the TX queues on this 1124 * endpoint that thread will reset the tx processing count when 1125 * the queue is drained 1126 */ 1127 qdf_atomic_dec(&pEndpoint->TxProcessCount); 1128 UNLOCK_HTC_TX(target); 1129 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy)\n")); 1130 return HTC_SEND_QUEUE_OK; 1131 } 1132 1133 /***** beyond this point only 1 thread may enter ******/ 1134 1135 /* now drain the endpoint TX queue for transmission as long as we have 1136 * enough transmit resources 1137 */ 1138 while (true) { 1139 1140 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) 1141 break; 1142 1143 if (pEndpoint->async_update && 1144 (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) && 1145 (!tx_resources)) 1146 break; 1147 1148 if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1149 #if DEBUG_CREDIT 1150 int cred = pEndpoint->TxCredits; 1151 #endif 1152 /* credit based mechanism provides flow control based on 1153 * target transmit resource availability, we assume that 1154 * the HIF layer will always have bus resources greater 1155 * than target transmit resources 1156 */ 1157 get_htc_send_packets_credit_based(target, pEndpoint, 1158 &sendQueue); 1159 #if DEBUG_CREDIT 1160 if (ep_debug_mask & (1 << pEndpoint->Id)) { 1161 if (cred - pEndpoint->TxCredits > 0) { 1162 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1163 (" <HTC> Decrease EP%d %d - %d = %d credits.\n", 1164 pEndpoint->Id, cred, 1165 cred - 1166 pEndpoint->TxCredits, 1167 pEndpoint->TxCredits)); 1168 } 1169 } 1170 #endif 1171 } else { 1172 1173 /* 1174 * Header and payload belongs to the different fragments and 1175 * consume 2 resource for one HTC package but USB combine into 1176 * one transfer.And one WMI message only consumes one single 1177 * resource. 1178 */ 1179 if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources && 1180 hif_get_bus_type(target->hif_dev) == 1181 QDF_BUS_TYPE_USB) { 1182 if (pEndpoint->service_id == 1183 WMI_CONTROL_SVC) 1184 tx_resources = 1185 HTC_MAX_MSG_PER_BUNDLE_TX; 1186 else 1187 tx_resources = 1188 (HTC_MAX_MSG_PER_BUNDLE_TX * 2); 1189 } 1190 /* get all the packets for this endpoint that we can for 1191 * this pass 1192 */ 1193 get_htc_send_packets(target, pEndpoint, &sendQueue, 1194 tx_resources); 1195 } 1196 1197 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { 1198 /* didn't get any packets due to a lack of resources or 1199 * TX queue was drained 1200 */ 1201 break; 1202 } 1203 1204 if (!pEndpoint->async_update) 1205 UNLOCK_HTC_TX(target); 1206 1207 /* send what we can */ 1208 if (htc_issue_packets(target, pEndpoint, &sendQueue)) { 1209 int i; 1210 1211 result = HTC_SEND_QUEUE_DROP; 1212 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1213 ("htc_issue_packets, failed status:%d put it back to head of callersSendQueue", 1214 result)); 1215 1216 for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) 1217 hif_pm_runtime_put(target->hif_dev); 1218 if (!pEndpoint->async_update) { 1219 LOCK_HTC_TX(target); 1220 } 1221 HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, 1222 &sendQueue); 1223 break; 1224 } 1225 1226 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1227 tx_resources = 1228 hif_get_free_queue_number(target->hif_dev, 1229 pEndpoint->UL_PipeID); 1230 } 1231 1232 if (!pEndpoint->async_update) { 1233 LOCK_HTC_TX(target); 1234 } 1235 1236 } 1237 1238 /* done with this endpoint, we can clear the count */ 1239 qdf_atomic_init(&pEndpoint->TxProcessCount); 1240 1241 UNLOCK_HTC_TX(target); 1242 1243 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send:\n")); 1244 1245 return HTC_SEND_QUEUE_OK; 1246 } 1247 1248 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1249 static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, 1250 HTC_ENDPOINT_ID id) 1251 { 1252 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1253 HTC_ENDPOINT *pEndpoint; 1254 HTC_ENDPOINT_ID eid; 1255 HTC_PACKET_QUEUE *pTxQueue; 1256 uint16_t resources; 1257 uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 }; 1258 1259 if (id < ENDPOINT_2 || id > ENDPOINT_5) 1260 return 1; 1261 1262 for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) { 1263 pEndpoint = &target->endpoint[eid]; 1264 pTxQueue = &pEndpoint->TxQueue; 1265 1266 if (HTC_QUEUE_EMPTY(pTxQueue)) 1267 acQueueStatus[eid - 2] = 1; 1268 } 1269 1270 switch (id) { 1271 case ENDPOINT_2: /* BE */ 1272 return acQueueStatus[0] && acQueueStatus[2] 1273 && acQueueStatus[3]; 1274 case ENDPOINT_3: /* BK */ 1275 return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2] 1276 && acQueueStatus[3]; 1277 case ENDPOINT_4: /* VI */ 1278 return acQueueStatus[2] && acQueueStatus[3]; 1279 case ENDPOINT_5: /* VO */ 1280 return acQueueStatus[3]; 1281 default: 1282 return 0; 1283 } 1284 1285 } 1286 1287 static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target, 1288 HTC_PACKET_QUEUE *pPktQueue, 1289 HTC_ENDPOINT_ID eid) 1290 { 1291 HTC_ENDPOINT *pEndpoint; 1292 HTC_PACKET_QUEUE *pTxQueue; 1293 HTC_PACKET *pPacket; 1294 int goodPkts; 1295 1296 pEndpoint = &target->endpoint[eid]; 1297 pTxQueue = &pEndpoint->TxQueue; 1298 1299 LOCK_HTC_TX(target); 1300 1301 goodPkts = 1302 pEndpoint->MaxTxQueueDepth - 1303 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); 1304 1305 if (goodPkts > 0) { 1306 while (!HTC_QUEUE_EMPTY(pPktQueue)) { 1307 pPacket = htc_packet_dequeue(pPktQueue); 1308 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1309 goodPkts--; 1310 1311 if (goodPkts <= 0) 1312 break; 1313 } 1314 } 1315 1316 if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) { 1317 ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket, 1318 HTC_PACKET, ListLink) { 1319 1320 if (pEndpoint->EpCallBacks. 1321 EpSendFull(pEndpoint->EpCallBacks.pContext, 1322 pPacket) == HTC_SEND_FULL_DROP) { 1323 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); 1324 } else { 1325 HTC_PACKET_REMOVE(pPktQueue, pPacket); 1326 HTC_PACKET_ENQUEUE(pTxQueue, pPacket); 1327 } 1328 } 1329 ITERATE_END; 1330 } 1331 1332 UNLOCK_HTC_TX(target); 1333 1334 return A_OK; 1335 } 1336 1337 #endif 1338 1339 static inline QDF_STATUS __htc_send_pkt(HTC_HANDLE HTCHandle, 1340 HTC_PACKET *pPacket) 1341 { 1342 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 1343 HTC_ENDPOINT *pEndpoint; 1344 HTC_PACKET_QUEUE pPktQueue; 1345 qdf_nbuf_t netbuf; 1346 HTC_FRAME_HDR *pHtcHdr; 1347 QDF_STATUS status; 1348 1349 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1350 ("+__htc_send_pkt\n")); 1351 1352 /* get packet at head to figure out which endpoint these packets will 1353 * go into 1354 */ 1355 if (NULL == pPacket) { 1356 OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL); 1357 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1358 return QDF_STATUS_E_INVAL; 1359 } 1360 1361 if ((pPacket->Endpoint >= ENDPOINT_MAX) || 1362 (pPacket->Endpoint <= ENDPOINT_UNUSED)) { 1363 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1364 ("%s endpoint is invalid\n", __func__)); 1365 AR_DEBUG_ASSERT(0); 1366 return QDF_STATUS_E_INVAL; 1367 } 1368 pEndpoint = &target->endpoint[pPacket->Endpoint]; 1369 1370 if (!pEndpoint->service_id) { 1371 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n", 1372 __func__)); 1373 return QDF_STATUS_E_INVAL; 1374 } 1375 1376 #ifdef HTC_EP_STAT_PROFILING 1377 LOCK_HTC_TX(target); 1378 INC_HTC_EP_STAT(pEndpoint, TxPosted, 1); 1379 UNLOCK_HTC_TX(target); 1380 #endif 1381 1382 /* provide room in each packet's netbuf for the HTC frame header */ 1383 netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); 1384 AR_DEBUG_ASSERT(netbuf); 1385 1386 qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); 1387 /* setup HTC frame header */ 1388 pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); 1389 AR_DEBUG_ASSERT(pHtcHdr); 1390 HTC_WRITE32(pHtcHdr, 1391 SM(pPacket->ActualLength, 1392 HTC_FRAME_HDR_PAYLOADLEN) | 1393 SM(pPacket->Endpoint, 1394 HTC_FRAME_HDR_ENDPOINTID)); 1395 LOCK_HTC_TX(target); 1396 1397 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; 1398 pEndpoint->SeqNo++; 1399 1400 HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, 1401 SM(pPacket->PktInfo.AsTx.SeqNo, 1402 HTC_FRAME_HDR_CONTROLBYTES1)); 1403 1404 UNLOCK_HTC_TX(target); 1405 1406 /* 1407 * For flow control enabled endpoints mapping is done in 1408 * htc_issue_packets and for non flow control enabled endpoints 1409 * its done here. 1410 */ 1411 if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { 1412 pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF; 1413 status = qdf_nbuf_map(target->osdev, 1414 GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), 1415 QDF_DMA_TO_DEVICE); 1416 if (status != QDF_STATUS_SUCCESS) { 1417 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1418 ("%s: nbuf map failed, endpoint %pK, seq_no. %d\n", 1419 __func__, pEndpoint, pEndpoint->SeqNo)); 1420 return status; 1421 } 1422 } 1423 1424 INIT_HTC_PACKET_QUEUE_AND_ADD(&pPktQueue, pPacket); 1425 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED 1426 if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) 1427 htc_send_pkts_sched_queue(HTCHandle, &pPktQueue, pEndpoint->Id); 1428 else 1429 htc_try_send(target, pEndpoint, &pPktQueue); 1430 #else 1431 htc_try_send(target, pEndpoint, &pPktQueue); 1432 #endif 1433 1434 /* do completion on any packets that couldn't get in */ 1435 while (!HTC_QUEUE_EMPTY(&pPktQueue)) { 1436 pPacket = htc_packet_dequeue(&pPktQueue); 1437 1438 if (HTC_STOPPING(target)) 1439 pPacket->Status = QDF_STATUS_E_CANCELED; 1440 else 1441 pPacket->Status = QDF_STATUS_E_RESOURCES; 1442 1443 send_packet_completion(target, pPacket); 1444 } 1445 1446 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n")); 1447 1448 return QDF_STATUS_SUCCESS; 1449 } 1450 1451 /* HTC API - htc_send_pkt */ 1452 QDF_STATUS htc_send_pkt(HTC_HANDLE htc_handle, HTC_PACKET *htc_packet) 1453 { 1454 if (!htc_handle) { 1455 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1456 ("%s: HTCHandle is NULL \n", __func__)); 1457 return QDF_STATUS_E_FAILURE; 1458 } 1459 1460 if (!htc_packet) { 1461 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 1462 ("%s: pPacket is NULL \n", __func__)); 1463 return QDF_STATUS_E_FAILURE; 1464 } 1465 1466 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 1467 ("+-htc_send_pkt: Enter endPointId: %d, buffer: %pK, length: %d\n", 1468 htc_packet->Endpoint, htc_packet->pBuffer, 1469 htc_packet->ActualLength)); 1470 return __htc_send_pkt(htc_handle, htc_packet); 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_TRACE_DEFAULT_PDEV_ID, 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 through 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 if (pEndpoint->service_id == WMI_CONTROL_SVC) { 2158 htc_credit_record(HTC_PROCESS_CREDIT_REPORT, 2159 pEndpoint->TxCredits + rpt_credits, 2160 HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> 2161 TxQueue)); 2162 } 2163 2164 pEndpoint->TxCredits += rpt_credits; 2165 2166 if (pEndpoint->TxCredits 2167 && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { 2168 UNLOCK_HTC_TX(target); 2169 #ifdef ATH_11AC_TXCOMPACT 2170 htc_try_send(target, pEndpoint, NULL); 2171 #else 2172 if (pEndpoint->service_id == HTT_DATA_MSG_SVC) 2173 htc_send_data_pkt(target, NULL, 0); 2174 else 2175 htc_try_send(target, pEndpoint, NULL); 2176 #endif 2177 LOCK_HTC_TX(target); 2178 } 2179 totalCredits += rpt_credits; 2180 } 2181 2182 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 2183 (" Report indicated %d credits to distribute\n", 2184 totalCredits)); 2185 2186 UNLOCK_HTC_TX(target); 2187 2188 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt\n")); 2189 } 2190 2191 /* function to fetch stats from htc layer*/ 2192 struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) 2193 { 2194 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 2195 2196 return &(target->htc_pkt_stats); 2197 } 2198