1 //------------------------------------------------------------------------------
2 // <copyright file="htc_send.c" company="Atheros">
3 //    Copyright (c) 2007-2010 Atheros Corporation.  All rights reserved.
4 //
5 //
6 // Permission to use, copy, modify, and/or distribute this software for any
7 // purpose with or without fee is hereby granted, provided that the above
8 // copyright notice and this permission notice appear in all copies.
9 //
10 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 //
18 //
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // Author(s): ="Atheros"
22 //==============================================================================
23 #include "htc_internal.h"
24 
25 typedef enum _HTC_SEND_QUEUE_RESULT {
26     HTC_SEND_QUEUE_OK = 0,    /* packet was queued */
27     HTC_SEND_QUEUE_DROP = 1,  /* this packet should be dropped */
28 } HTC_SEND_QUEUE_RESULT;
29 
30 #define DO_EP_TX_COMPLETION(ep,q)  DoSendCompletion(ep,q)
31 
32 /* call the distribute credits callback with the distribution */
33 #define DO_DISTRIBUTION(t,reason,description,pList) \
34 {                                             \
35     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,           \
36         ("  calling distribute function (%s) (dfn:0x%lX, ctxt:0x%lX, dist:0x%lX) \n", \
37                 (description),                                           \
38                 (unsigned long)(t)->DistributeCredits,                   \
39                 (unsigned long)(t)->pCredDistContext,                    \
40                 (unsigned long)pList));                                  \
41     (t)->DistributeCredits((t)->pCredDistContext,                        \
42                            (pList),                                      \
43                            (reason));                                    \
44 }
45 
DoSendCompletion(struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueueToIndicate)46 static void DoSendCompletion(struct htc_endpoint       *pEndpoint,
47                              struct htc_packet_queue   *pQueueToIndicate)
48 {
49     do {
50 
51         if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
52                 /* nothing to indicate */
53             break;
54         }
55 
56         if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) {
57             AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d, send complete multiple callback (%d pkts) \n",
58                      pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
59                 /* a multiple send complete handler is being used, pass the queue to the handler */
60             pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint->EpCallBacks.pContext,
61                                                         pQueueToIndicate);
62                 /* all packets are now owned by the callback, reset queue to be safe */
63             INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
64         } else {
65             struct htc_packet *pPacket;
66             /* using legacy EpTxComplete */
67             do {
68                 pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
69                 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d send complete callback on packet 0x%lX \n", \
70                         pEndpoint->Id, (unsigned long)(pPacket)));
71                 pEndpoint->EpCallBacks.EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket);
72             } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
73         }
74 
75     } while (false);
76 
77 }
78 
79 /* do final completion on sent packet */
CompleteSentPacket(struct htc_target * target,struct htc_endpoint * pEndpoint,struct htc_packet * pPacket)80 static INLINE void CompleteSentPacket(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet *pPacket)
81 {
82     pPacket->Completion = NULL;
83 
84     if (pPacket->Status) {
85         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
86             ("CompleteSentPacket: request failed (status:%d, ep:%d, length:%d creds:%d) \n",
87                 pPacket->Status, pPacket->Endpoint, pPacket->ActualLength, pPacket->PktInfo.AsTx.CreditsUsed));
88             /* on failure to submit, reclaim credits for this packet */
89         LOCK_HTC_TX(target);
90         pEndpoint->CreditDist.TxCreditsToDist += pPacket->PktInfo.AsTx.CreditsUsed;
91         pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
92         DO_DISTRIBUTION(target,
93                         HTC_CREDIT_DIST_SEND_COMPLETE,
94                         "Send Complete",
95                         target->EpCreditDistributionListHead->pNext);
96         UNLOCK_HTC_TX(target);
97     }
98         /* first, fixup the head room we allocated */
99     pPacket->pBuffer += HTC_HDR_LENGTH;
100 }
101 
102 /* our internal send packet completion handler when packets are submited to the AR6K device
103  * layer */
HTCSendPktCompletionHandler(void * Context,struct htc_packet * pPacket)104 static void HTCSendPktCompletionHandler(void *Context, struct htc_packet *pPacket)
105 {
106     struct htc_target      *target = (struct htc_target *)Context;
107     struct htc_endpoint    *pEndpoint = &target->EndPoint[pPacket->Endpoint];
108     struct htc_packet_queue container;
109 
110     CompleteSentPacket(target,pEndpoint,pPacket);
111     INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
112         /* do completion */
113     DO_EP_TX_COMPLETION(pEndpoint,&container);
114 }
115 
HTCIssueSend(struct htc_target * target,struct htc_packet * pPacket)116 int HTCIssueSend(struct htc_target *target, struct htc_packet *pPacket)
117 {
118     int status;
119     bool   sync = false;
120 
121     if (pPacket->Completion == NULL) {
122             /* mark that this request was synchronously issued */
123         sync = true;
124     }
125 
126     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
127                     ("+-HTCIssueSend: transmit length : %d (%s) \n",
128                     pPacket->ActualLength + (u32)HTC_HDR_LENGTH,
129                     sync ? "SYNC" : "ASYNC" ));
130 
131         /* send message to device */
132     status = DevSendPacket(&target->Device,
133                            pPacket,
134                            pPacket->ActualLength + HTC_HDR_LENGTH);
135 
136     if (sync) {
137             /* use local sync variable.  If this was issued asynchronously, pPacket is no longer
138              * safe to access. */
139         pPacket->pBuffer += HTC_HDR_LENGTH;
140     }
141 
142     /* if this request was asynchronous, the packet completion routine will be invoked by
143      * the device layer when the HIF layer completes the request */
144 
145     return status;
146 }
147 
148     /* get HTC send packets from the TX queue on an endpoint */
GetHTCSendPackets(struct htc_target * target,struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueue)149 static INLINE void GetHTCSendPackets(struct htc_target        *target,
150                                      struct htc_endpoint      *pEndpoint,
151                                      struct htc_packet_queue  *pQueue)
152 {
153     int          creditsRequired;
154     int          remainder;
155     u8 sendFlags;
156     struct htc_packet   *pPacket;
157     unsigned int transferLength;
158 
159     /****** NOTE : the TX lock is held when this function is called *****************/
160     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+GetHTCSendPackets \n"));
161 
162         /* loop until we can grab as many packets out of the queue as we can */
163     while (true) {
164 
165         sendFlags = 0;
166             /* get packet at head, but don't remove it */
167         pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
168         if (pPacket == NULL) {
169             break;
170         }
171 
172         AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%lX , Queue Depth: %d\n",
173                 (unsigned long)pPacket, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
174 
175         transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, pPacket->ActualLength + HTC_HDR_LENGTH);
176 
177         if (transferLength <= target->TargetCreditSize) {
178             creditsRequired = 1;
179         } else {
180                 /* figure out how many credits this message requires */
181             creditsRequired = transferLength / target->TargetCreditSize;
182             remainder = transferLength % target->TargetCreditSize;
183 
184             if (remainder) {
185                 creditsRequired++;
186             }
187         }
188 
189         AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d   Got:%d\n",
190                             creditsRequired, pEndpoint->CreditDist.TxCredits));
191 
192         if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
193 
194                 /* not enough credits */
195             if (pPacket->Endpoint == ENDPOINT_0) {
196                     /* leave it in the queue */
197                 break;
198             }
199                 /* invoke the registered distribution function only if this is not
200                  * endpoint 0, we let the driver layer provide more credits if it can.
201                  * We pass the credit distribution list starting at the endpoint in question
202                  * */
203 
204                 /* set how many credits we need  */
205             pEndpoint->CreditDist.TxCreditsSeek =
206                                     creditsRequired - pEndpoint->CreditDist.TxCredits;
207             DO_DISTRIBUTION(target,
208                             HTC_CREDIT_DIST_SEEK_CREDITS,
209                             "Seek Credits",
210                             &pEndpoint->CreditDist);
211             pEndpoint->CreditDist.TxCreditsSeek = 0;
212 
213             if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
214                     /* still not enough credits to send, leave packet in the queue */
215                 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
216                     (" Not enough credits for ep %d leaving packet in queue..\n",
217                     pPacket->Endpoint));
218                 break;
219             }
220 
221         }
222 
223         pEndpoint->CreditDist.TxCredits -= creditsRequired;
224         INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
225 
226             /* check if we need credits back from the target */
227         if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
228                 /* we are getting low on credits, see if we can ask for more from the distribution function */
229             pEndpoint->CreditDist.TxCreditsSeek =
230                         pEndpoint->CreditDist.TxCreditsPerMaxMsg - pEndpoint->CreditDist.TxCredits;
231 
232             DO_DISTRIBUTION(target,
233                             HTC_CREDIT_DIST_SEEK_CREDITS,
234                             "Seek Credits",
235                             &pEndpoint->CreditDist);
236 
237             pEndpoint->CreditDist.TxCreditsSeek = 0;
238                 /* see if we were successful in getting more */
239             if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
240                     /* tell the target we need credits ASAP! */
241                 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
242                 INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
243                 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits  \n"));
244             }
245         }
246 
247             /* now we can fully dequeue */
248         pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
249             /* save the number of credits this packet consumed */
250         pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
251             /* all TX packets are handled asynchronously */
252         pPacket->Completion = HTCSendPktCompletionHandler;
253         pPacket->pContext = target;
254         INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
255             /* save send flags */
256         pPacket->PktInfo.AsTx.SendFlags = sendFlags;
257         pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
258         pEndpoint->SeqNo++;
259             /* queue this packet into the caller's queue */
260         HTC_PACKET_ENQUEUE(pQueue,pPacket);
261     }
262 
263     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-GetHTCSendPackets \n"));
264 
265 }
266 
HTCAsyncSendScatterCompletion(struct hif_scatter_req * pScatterReq)267 static void HTCAsyncSendScatterCompletion(struct hif_scatter_req *pScatterReq)
268 {
269     int                 i;
270     struct htc_packet          *pPacket;
271     struct htc_endpoint        *pEndpoint = (struct htc_endpoint *)pScatterReq->Context;
272     struct htc_target          *target = (struct htc_target *)pEndpoint->target;
273     int            status = 0;
274     struct htc_packet_queue    sendCompletes;
275 
276     INIT_HTC_PACKET_QUEUE(&sendCompletes);
277 
278     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCAsyncSendScatterCompletion  TotLen: %d  Entries: %d\n",
279         pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
280 
281     DEV_FINISH_SCATTER_OPERATION(pScatterReq);
282 
283     if (pScatterReq->CompletionStatus) {
284         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Send Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
285         status = A_ERROR;
286     }
287 
288         /* walk through the scatter list and process */
289     for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
290         pPacket = (struct htc_packet *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
291         A_ASSERT(pPacket != NULL);
292         pPacket->Status = status;
293         CompleteSentPacket(target,pEndpoint,pPacket);
294             /* add it to the completion queue */
295         HTC_PACKET_ENQUEUE(&sendCompletes, pPacket);
296     }
297 
298         /* free scatter request */
299     DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
300         /* complete all packets */
301     DO_EP_TX_COMPLETION(pEndpoint,&sendCompletes);
302 
303     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCAsyncSendScatterCompletion \n"));
304 }
305 
306     /* drain a queue and send as bundles
307      * this function may return without fully draining the queue under the following conditions :
308      *    - scatter resources are exhausted
309      *    - a message that will consume a partial credit will stop the bundling process early
310      *    - we drop below the minimum number of messages for a bundle
311      * */
HTCIssueSendBundle(struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueue,int * pBundlesSent,int * pTotalBundlesPkts)312 static void HTCIssueSendBundle(struct htc_endpoint      *pEndpoint,
313                                struct htc_packet_queue  *pQueue,
314                                int               *pBundlesSent,
315                                int               *pTotalBundlesPkts)
316 {
317     int                 pktsToScatter;
318     unsigned int        scatterSpaceRemaining;
319     struct hif_scatter_req     *pScatterReq = NULL;
320     int                 i, packetsInScatterReq;
321     unsigned int        transferLength;
322     struct htc_packet          *pPacket;
323     bool              done = false;
324     int                 bundlesSent = 0;
325     int                 totalPktsInBundle = 0;
326     struct htc_target          *target = pEndpoint->target;
327     int                 creditRemainder = 0;
328     int                 creditPad;
329 
330     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCIssueSendBundle \n"));
331 
332     while (!done) {
333 
334         pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pQueue);
335         pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
336 
337         if (pktsToScatter < HTC_MIN_HTC_MSGS_TO_BUNDLE) {
338                 /* not enough to bundle */
339             break;
340         }
341 
342         pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device);
343 
344         if (pScatterReq == NULL) {
345                 /* no scatter resources  */
346             AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("   No more scatter resources \n"));
347             break;
348         }
349 
350         AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("   pkts to scatter: %d \n", pktsToScatter));
351 
352         pScatterReq->TotalLength = 0;
353         pScatterReq->ValidScatterEntries = 0;
354 
355         packetsInScatterReq = 0;
356         scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device);
357 
358         for (i = 0; i < pktsToScatter; i++) {
359 
360             pScatterReq->ScatterList[i].pCallerContexts[0] = NULL;
361 
362             pPacket = HTC_GET_PKT_AT_HEAD(pQueue);
363             if (pPacket == NULL) {
364                 A_ASSERT(false);
365                 break;
366             }
367 
368             creditPad = 0;
369             transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device,
370                                                       pPacket->ActualLength + HTC_HDR_LENGTH);
371                 /* see if the padded transfer length falls on a credit boundary */
372             creditRemainder = transferLength % target->TargetCreditSize;
373 
374             if (creditRemainder != 0) {
375                     /* the transfer consumes a "partial" credit, this packet cannot be bundled unless
376                      * we add additional "dummy" padding (max 255 bytes) to consume the entire credit
377                      *** NOTE: only allow the send padding if the endpoint is allowed to */
378                 if (pEndpoint->LocalConnectionFlags & HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING) {
379                     if (transferLength < target->TargetCreditSize) {
380                             /* special case where the transfer is less than a credit */
381                         creditPad = target->TargetCreditSize - transferLength;
382                     } else {
383                         creditPad = creditRemainder;
384                     }
385 
386                         /* now check to see if we can indicate padding in the HTC header */
387                     if ((creditPad > 0) && (creditPad <= 255)) {
388                             /* adjust the transferlength of this packet with the new credit padding */
389                         transferLength += creditPad;
390                     } else {
391                             /* the amount to pad is too large, bail on this packet, we have to
392                              * send it using the non-bundled method */
393                         pPacket = NULL;
394                     }
395                 } else {
396                         /* bail on this packet, user does not want padding applied */
397                     pPacket = NULL;
398                 }
399             }
400 
401             if (NULL == pPacket) {
402                     /* can't bundle */
403                 done = true;
404                 break;
405             }
406 
407             if (scatterSpaceRemaining < transferLength) {
408                     /* exceeds what we can transfer */
409                 break;
410             }
411 
412             scatterSpaceRemaining -= transferLength;
413                 /* now remove it from the queue */
414             pPacket = HTC_PACKET_DEQUEUE(pQueue);
415                 /* save it in the scatter list */
416             pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
417                 /* prepare packet and flag message as part of a send bundle */
418             HTC_PREPARE_SEND_PKT(pPacket,
419                                  pPacket->PktInfo.AsTx.SendFlags | HTC_FLAGS_SEND_BUNDLE,
420                                  creditPad,
421                                  pPacket->PktInfo.AsTx.SeqNo);
422             pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
423             pScatterReq->ScatterList[i].Length = transferLength;
424             A_ASSERT(transferLength);
425             pScatterReq->TotalLength += transferLength;
426             pScatterReq->ValidScatterEntries++;
427             packetsInScatterReq++;
428             AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("  %d, Adding packet : 0x%lX, len:%d (remaining space:%d) \n",
429                     i, (unsigned long)pPacket,transferLength,scatterSpaceRemaining));
430         }
431 
432         if (packetsInScatterReq >= HTC_MIN_HTC_MSGS_TO_BUNDLE) {
433                 /* send path is always asynchronous */
434             pScatterReq->CompletionRoutine = HTCAsyncSendScatterCompletion;
435             pScatterReq->Context = pEndpoint;
436             bundlesSent++;
437             totalPktsInBundle += packetsInScatterReq;
438             packetsInScatterReq = 0;
439             AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Send Scatter total bytes: %d , entries: %d\n",
440                                 pScatterReq->TotalLength,pScatterReq->ValidScatterEntries));
441             DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_WRITE, DEV_SCATTER_ASYNC);
442                 /* we don't own this anymore */
443             pScatterReq = NULL;
444                 /* try to send some more */
445             continue;
446         }
447 
448             /* not enough packets to use the scatter request, cleanup */
449         if (pScatterReq != NULL) {
450             if (packetsInScatterReq > 0) {
451                     /* work backwards to requeue requests */
452                 for (i = (packetsInScatterReq - 1); i >= 0; i--) {
453                     pPacket = (struct htc_packet *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
454                     if (pPacket != NULL) {
455                             /* undo any prep */
456                         HTC_UNPREPARE_SEND_PKT(pPacket);
457                             /* queue back to the head */
458                         HTC_PACKET_ENQUEUE_TO_HEAD(pQueue,pPacket);
459                     }
460                 }
461             }
462             DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
463         }
464 
465         /* if we get here, we sent all that we could, get out */
466         break;
467 
468     }
469 
470     *pBundlesSent = bundlesSent;
471     *pTotalBundlesPkts = totalPktsInBundle;
472     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCIssueSendBundle (sent:%d) \n",bundlesSent));
473 
474     return;
475 }
476 
477 /*
478  * if there are no credits, the packet(s) remains in the queue.
479  * this function returns the result of the attempt to send a queue of HTC packets */
HTCTrySend(struct htc_target * target,struct htc_endpoint * pEndpoint,struct htc_packet_queue * pCallersSendQueue)480 static HTC_SEND_QUEUE_RESULT HTCTrySend(struct htc_target       *target,
481                                         struct htc_endpoint     *pEndpoint,
482                                         struct htc_packet_queue *pCallersSendQueue)
483 {
484     struct htc_packet_queue      sendQueue; /* temp queue to hold packets at various stages */
485     struct htc_packet            *pPacket;
486     int                   bundlesSent;
487     int                   pktsInBundles;
488     int                   overflow;
489     HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
490 
491     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (Queue:0x%lX Depth:%d)\n",
492             (unsigned long)pCallersSendQueue,
493             (pCallersSendQueue == NULL) ? 0 : HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue)));
494 
495         /* init the local send queue */
496     INIT_HTC_PACKET_QUEUE(&sendQueue);
497 
498     do {
499 
500         if (NULL == pCallersSendQueue) {
501                 /* caller didn't provide a queue, just wants us to check queues and send */
502             break;
503         }
504 
505         if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
506                 /* empty queue */
507             result = HTC_SEND_QUEUE_DROP;
508             break;
509         }
510 
511         if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= pEndpoint->MaxTxQueueDepth) {
512                     /* we've already overflowed */
513             overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
514         } else {
515                 /* figure out how much we will overflow by */
516             overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
517             overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
518                 /* figure out how much we will overflow the TX queue by */
519             overflow -= pEndpoint->MaxTxQueueDepth;
520         }
521 
522             /* if overflow is negative or zero, we are okay */
523         if (overflow > 0) {
524             AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
525                 (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n",
526                 pEndpoint->Id, overflow, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue), pEndpoint->MaxTxQueueDepth));
527         }
528         if ((overflow <= 0) || (pEndpoint->EpCallBacks.EpSendFull == NULL)) {
529                 /* all packets will fit or caller did not provide send full indication handler
530                  * --  just move all of them to the local sendQueue object */
531             HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, pCallersSendQueue);
532         } else {
533             int               i;
534             int               goodPkts = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - overflow;
535 
536             A_ASSERT(goodPkts >= 0);
537                 /* we have overflowed, and a callback is provided */
538                 /* dequeue all non-overflow packets into the sendqueue */
539             for (i = 0; i < goodPkts; i++) {
540                     /* pop off caller's queue*/
541                 pPacket = HTC_PACKET_DEQUEUE(pCallersSendQueue);
542                 A_ASSERT(pPacket != NULL);
543                     /* insert into local queue */
544                 HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
545             }
546 
547                 /* the caller's queue has all the packets that won't fit*/
548                 /* walk through the caller's queue and indicate each one to the send full handler */
549             ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->QueueHead, pPacket, struct htc_packet, ListLink) {
550 
551                 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Indicating overflowed TX packet: 0x%lX \n",
552                                             (unsigned long)pPacket));
553                 if (pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext,
554                                                       pPacket) == HTC_SEND_FULL_DROP) {
555                         /* callback wants the packet dropped */
556                     INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
557                         /* leave this one in the caller's queue for cleanup */
558                 } else {
559                         /* callback wants to keep this packet, remove from caller's queue */
560                     HTC_PACKET_REMOVE(pCallersSendQueue, pPacket);
561                         /* put it in the send queue */
562                     HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
563                 }
564 
565             } ITERATE_END;
566 
567             if (HTC_QUEUE_EMPTY(&sendQueue)) {
568                     /* no packets made it in, caller will cleanup */
569                 result = HTC_SEND_QUEUE_DROP;
570                 break;
571             }
572         }
573 
574     } while (false);
575 
576     if (result != HTC_SEND_QUEUE_OK) {
577         AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend:  \n"));
578         return result;
579     }
580 
581     LOCK_HTC_TX(target);
582 
583     if (!HTC_QUEUE_EMPTY(&sendQueue)) {
584             /* transfer packets */
585         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,&sendQueue);
586         A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
587         INIT_HTC_PACKET_QUEUE(&sendQueue);
588     }
589 
590         /* increment tx processing count on entry */
591     pEndpoint->TxProcessCount++;
592     if (pEndpoint->TxProcessCount > 1) {
593             /* another thread or task is draining the TX queues on this endpoint
594              * that thread will reset the tx processing count when the queue is drained */
595         pEndpoint->TxProcessCount--;
596         UNLOCK_HTC_TX(target);
597         AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend (busy) \n"));
598         return HTC_SEND_QUEUE_OK;
599     }
600 
601     /***** beyond this point only 1 thread may enter ******/
602 
603         /* now drain the endpoint TX queue for transmission as long as we have enough
604          * credits */
605     while (true) {
606 
607         if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) {
608             break;
609         }
610 
611             /* get all the packets for this endpoint that we can for this pass */
612         GetHTCSendPackets(target, pEndpoint, &sendQueue);
613 
614         if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
615                 /* didn't get any packets due to a lack of credits */
616             break;
617         }
618 
619         UNLOCK_HTC_TX(target);
620 
621             /* any packets to send are now in our local send queue */
622 
623         bundlesSent = 0;
624         pktsInBundles = 0;
625 
626         while (true) {
627 
628                 /* try to send a bundle on each pass */
629             if ((target->SendBundlingEnabled) &&
630                     (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
631                  int temp1,temp2;
632                     /* bundling is enabled and there is at least a minimum number of packets in the send queue
633                      * send what we can in this pass */
634                  HTCIssueSendBundle(pEndpoint, &sendQueue, &temp1, &temp2);
635                  bundlesSent += temp1;
636                  pktsInBundles += temp2;
637             }
638 
639                 /* if not bundling or there was a packet that could not be placed in a bundle, pull it out
640                  * and send it the normal way */
641             pPacket = HTC_PACKET_DEQUEUE(&sendQueue);
642             if (NULL == pPacket) {
643                     /* local queue is fully drained */
644                 break;
645             }
646             HTC_PREPARE_SEND_PKT(pPacket,
647                                  pPacket->PktInfo.AsTx.SendFlags,
648                                  0,
649                                  pPacket->PktInfo.AsTx.SeqNo);
650             HTCIssueSend(target, pPacket);
651 
652                 /* go back and see if we can bundle some more */
653         }
654 
655         LOCK_HTC_TX(target);
656 
657         INC_HTC_EP_STAT(pEndpoint, TxBundles, bundlesSent);
658         INC_HTC_EP_STAT(pEndpoint, TxPacketsBundled, pktsInBundles);
659 
660     }
661 
662         /* done with this endpoint, we can clear the count */
663     pEndpoint->TxProcessCount = 0;
664     UNLOCK_HTC_TX(target);
665 
666     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend:  \n"));
667 
668     return HTC_SEND_QUEUE_OK;
669 }
670 
HTCSendPktsMultiple(HTC_HANDLE HTCHandle,struct htc_packet_queue * pPktQueue)671 int  HTCSendPktsMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
672 {
673     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
674     struct htc_endpoint    *pEndpoint;
675     struct htc_packet      *pPacket;
676 
677     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCSendPktsMultiple: Queue: 0x%lX, Pkts %d \n",
678                     (unsigned long)pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
679 
680         /* get packet at head to figure out which endpoint these packets will go into */
681     pPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
682     if (NULL == pPacket) {
683         AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
684         return A_EINVAL;
685     }
686 
687     AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
688     pEndpoint = &target->EndPoint[pPacket->Endpoint];
689 
690     HTCTrySend(target, pEndpoint, pPktQueue);
691 
692         /* do completion on any packets that couldn't get in */
693     if (!HTC_QUEUE_EMPTY(pPktQueue)) {
694 
695         HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
696             if (HTC_STOPPING(target)) {
697                 pPacket->Status = A_ECANCELED;
698             } else {
699                 pPacket->Status = A_NO_RESOURCE;
700             }
701         } HTC_PACKET_QUEUE_ITERATE_END;
702 
703         DO_EP_TX_COMPLETION(pEndpoint,pPktQueue);
704     }
705 
706     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
707 
708     return 0;
709 }
710 
711 /* HTC API - HTCSendPkt */
HTCSendPkt(HTC_HANDLE HTCHandle,struct htc_packet * pPacket)712 int HTCSendPkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
713 {
714     struct htc_packet_queue queue;
715 
716     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
717                     ("+-HTCSendPkt: Enter endPointId: %d, buffer: 0x%lX, length: %d \n",
718                     pPacket->Endpoint, (unsigned long)pPacket->pBuffer, pPacket->ActualLength));
719     INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
720     return HTCSendPktsMultiple(HTCHandle, &queue);
721 }
722 
723 /* check TX queues to drain because of credit distribution update */
HTCCheckEndpointTxQueues(struct htc_target * target)724 static INLINE void HTCCheckEndpointTxQueues(struct htc_target *target)
725 {
726     struct htc_endpoint                *pEndpoint;
727     struct htc_endpoint_credit_dist    *pDistItem;
728 
729     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
730     pDistItem = target->EpCreditDistributionListHead;
731 
732         /* run through the credit distribution list to see
733          * if there are packets queued
734          * NOTE: no locks need to be taken since the distribution list
735          * is not dynamic (cannot be re-ordered) and we are not modifying any state */
736     while (pDistItem != NULL) {
737         pEndpoint = (struct htc_endpoint *)pDistItem->pHTCReserved;
738 
739         if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) > 0) {
740             AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
741                     pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
742                 /* try to start the stalled queue, this list is ordered by priority.
743                  * Highest priority queue get's processed first, if there are credits available the
744                  * highest priority queue will get a chance to reclaim credits from lower priority
745                  * ones */
746             HTCTrySend(target, pEndpoint, NULL);
747         }
748 
749         pDistItem = pDistItem->pNext;
750     }
751 
752     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
753 }
754 
755 /* process credit reports and call distribution function */
HTCProcessCreditRpt(struct htc_target * target,HTC_CREDIT_REPORT * pRpt,int NumEntries,HTC_ENDPOINT_ID FromEndpoint)756 void HTCProcessCreditRpt(struct htc_target *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
757 {
758     int             i;
759     struct htc_endpoint    *pEndpoint;
760     int             totalCredits = 0;
761     bool          doDist = false;
762 
763     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
764 
765         /* lock out TX while we update credits */
766     LOCK_HTC_TX(target);
767 
768     for (i = 0; i < NumEntries; i++, pRpt++) {
769         if (pRpt->EndpointID >= ENDPOINT_MAX) {
770             AR_DEBUG_ASSERT(false);
771             break;
772         }
773 
774         pEndpoint = &target->EndPoint[pRpt->EndpointID];
775 
776         AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("  Endpoint %d got %d credits \n",
777                 pRpt->EndpointID, pRpt->Credits));
778 
779 
780 #ifdef HTC_EP_STAT_PROFILING
781 
782         INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
783         INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
784 
785         if (FromEndpoint == pRpt->EndpointID) {
786                 /* this credit report arrived on the same endpoint indicating it arrived in an RX
787                  * packet */
788             INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
789             INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
790         } else if (FromEndpoint == ENDPOINT_0) {
791                 /* this credit arrived on endpoint 0 as a NULL message */
792             INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
793             INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
794         } else {
795                 /* arrived on another endpoint */
796             INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
797             INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
798         }
799 
800 #endif
801 
802         if (ENDPOINT_0 == pRpt->EndpointID) {
803                 /* always give endpoint 0 credits back */
804             pEndpoint->CreditDist.TxCredits += pRpt->Credits;
805         } else {
806                 /* for all other endpoints, update credits to distribute, the distribution function
807                  * will handle giving out credits back to the endpoints */
808             pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
809                 /* flag that we have to do the distribution */
810             doDist = true;
811         }
812 
813             /* refresh tx depth for distribution function that will recover these credits
814              * NOTE: this is only valid when there are credits to recover! */
815         pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
816 
817         totalCredits += pRpt->Credits;
818     }
819 
820     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("  Report indicated %d credits to distribute \n", totalCredits));
821 
822     if (doDist) {
823             /* this was a credit return based on a completed send operations
824              * note, this is done with the lock held */
825         DO_DISTRIBUTION(target,
826                         HTC_CREDIT_DIST_SEND_COMPLETE,
827                         "Send Complete",
828                         target->EpCreditDistributionListHead->pNext);
829     }
830 
831     UNLOCK_HTC_TX(target);
832 
833     if (totalCredits) {
834         HTCCheckEndpointTxQueues(target);
835     }
836 
837     AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
838 }
839 
840 /* flush endpoint TX queue */
HTCFlushEndpointTX(struct htc_target * target,struct htc_endpoint * pEndpoint,HTC_TX_TAG Tag)841 static void HTCFlushEndpointTX(struct htc_target *target, struct htc_endpoint *pEndpoint, HTC_TX_TAG Tag)
842 {
843     struct htc_packet          *pPacket;
844     struct htc_packet_queue    discardQueue;
845     struct htc_packet_queue    container;
846 
847         /* initialize the discard queue */
848     INIT_HTC_PACKET_QUEUE(&discardQueue);
849 
850     LOCK_HTC_TX(target);
851 
852         /* interate from the front of the TX queue and flush out packets */
853     ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue.QueueHead, pPacket, struct htc_packet, ListLink) {
854 
855             /* check for removal */
856         if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
857                 /* remove from queue */
858             HTC_PACKET_REMOVE(&pEndpoint->TxQueue, pPacket);
859                 /* add it to the discard pile */
860             HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
861         }
862 
863     } ITERATE_END;
864 
865     UNLOCK_HTC_TX(target);
866 
867         /* empty the discard queue */
868     while (1) {
869         pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
870         if (NULL == pPacket) {
871             break;
872         }
873         pPacket->Status = A_ECANCELED;
874         AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("  Flushing TX packet:0x%lX, length:%d, ep:%d tag:0x%X \n",
875                 (unsigned long)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
876         INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
877         DO_EP_TX_COMPLETION(pEndpoint,&container);
878     }
879 
880 }
881 
DumpCreditDist(struct htc_endpoint_credit_dist * pEPDist)882 void DumpCreditDist(struct htc_endpoint_credit_dist *pEPDist)
883 {
884     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d  ServiceID: 0x%X    --------------\n",
885                         pEPDist->Endpoint, pEPDist->ServiceID));
886     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%lX next:0x%lX prev:0x%lX\n",
887                 (unsigned long)pEPDist, (unsigned long)pEPDist->pNext, (unsigned long)pEPDist->pPrev));
888     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags          : 0x%X \n", pEPDist->DistFlags));
889     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm      : %d \n", pEPDist->TxCreditsNorm));
890     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin       : %d \n", pEPDist->TxCreditsMin));
891     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits          : %d \n", pEPDist->TxCredits));
892     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned  : %d \n", pEPDist->TxCreditsAssigned));
893     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek      : %d \n", pEPDist->TxCreditsSeek));
894     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize       : %d \n", pEPDist->TxCreditSize));
895     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
896     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist    : %d \n", pEPDist->TxCreditsToDist));
897     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth       : %d \n",
898                     HTC_PACKET_QUEUE_DEPTH(&((struct htc_endpoint *)pEPDist->pHTCReserved)->TxQueue)));
899     AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
900 }
901 
DumpCreditDistStates(struct htc_target * target)902 void DumpCreditDistStates(struct htc_target *target)
903 {
904     struct htc_endpoint_credit_dist *pEPList = target->EpCreditDistributionListHead;
905 
906     while (pEPList != NULL) {
907         DumpCreditDist(pEPList);
908         pEPList = pEPList->pNext;
909     }
910 
911     if (target->DistributeCredits != NULL) {
912         DO_DISTRIBUTION(target,
913                         HTC_DUMP_CREDIT_STATE,
914                         "Dump State",
915                         NULL);
916     }
917 }
918 
919 /* flush all send packets from all endpoint queues */
HTCFlushSendPkts(struct htc_target * target)920 void HTCFlushSendPkts(struct htc_target *target)
921 {
922     struct htc_endpoint    *pEndpoint;
923     int             i;
924 
925     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
926         DumpCreditDistStates(target);
927     }
928 
929     for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
930         pEndpoint = &target->EndPoint[i];
931         if (pEndpoint->ServiceID == 0) {
932                 /* not in use.. */
933             continue;
934         }
935         HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
936     }
937 
938 
939 }
940 
941 /* HTC API to flush an endpoint's TX queue*/
HTCFlushEndpoint(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,HTC_TX_TAG Tag)942 void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
943 {
944     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
945     struct htc_endpoint    *pEndpoint = &target->EndPoint[Endpoint];
946 
947     if (pEndpoint->ServiceID == 0) {
948         AR_DEBUG_ASSERT(false);
949         /* not in use.. */
950         return;
951     }
952 
953     HTCFlushEndpointTX(target, pEndpoint, Tag);
954 }
955 
956 /* HTC API to indicate activity to the credit distribution function */
HTCIndicateActivityChange(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,bool Active)957 void HTCIndicateActivityChange(HTC_HANDLE      HTCHandle,
958                                HTC_ENDPOINT_ID Endpoint,
959                                bool          Active)
960 {
961     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
962     struct htc_endpoint    *pEndpoint = &target->EndPoint[Endpoint];
963     bool          doDist = false;
964 
965     if (pEndpoint->ServiceID == 0) {
966         AR_DEBUG_ASSERT(false);
967         /* not in use.. */
968         return;
969     }
970 
971     LOCK_HTC_TX(target);
972 
973     if (Active) {
974         if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
975                 /* mark active now */
976             pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
977             doDist = true;
978         }
979     } else {
980         if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
981                 /* mark inactive now */
982             pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
983             doDist = true;
984         }
985     }
986 
987     if (doDist) {
988             /* indicate current Tx Queue depth to the credit distribution function */
989         pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
990         /* do distribution again based on activity change
991          * note, this is done with the lock held */
992         DO_DISTRIBUTION(target,
993                         HTC_CREDIT_DIST_ACTIVITY_CHANGE,
994                         "Activity Change",
995                         target->EpCreditDistributionListHead->pNext);
996     }
997 
998     UNLOCK_HTC_TX(target);
999 
1000     if (doDist && !Active) {
1001         /* if a stream went inactive and this resulted in a credit distribution change,
1002          * some credits may now be available for HTC packets that are stuck in
1003          * HTC queues */
1004         HTCCheckEndpointTxQueues(target);
1005     }
1006 }
1007 
HTCIsEndpointActive(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint)1008 bool HTCIsEndpointActive(HTC_HANDLE      HTCHandle,
1009                            HTC_ENDPOINT_ID Endpoint)
1010 {
1011     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1012     struct htc_endpoint    *pEndpoint = &target->EndPoint[Endpoint];
1013 
1014     if (pEndpoint->ServiceID == 0) {
1015         return false;
1016     }
1017 
1018     if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
1019         return true;
1020     }
1021 
1022     return false;
1023 }
1024