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