1 //------------------------------------------------------------------------------
2 // <copyright file="htc_send.c" company="Atheros">
3 // Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
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.
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.
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // Author(s): ="Atheros"
22 //==============================================================================
23 #include "htc_internal.h"
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
;
30 #define DO_EP_TX_COMPLETION(ep,q) DoSendCompletion(ep,q)
32 /* call the distribute credits callback with the distribution */
33 #define DO_DISTRIBUTION(t,reason,description,pList) \
35 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
36 (" calling distribute function (%s) (dfn:0x%lX, ctxt:0x%lX, dist:0x%lX) \n", \
38 (unsigned long)(t)->DistributeCredits, \
39 (unsigned long)(t)->pCredDistContext, \
40 (unsigned long)pList)); \
41 (t)->DistributeCredits((t)->pCredDistContext, \
46 static void DoSendCompletion(HTC_ENDPOINT
*pEndpoint
,
47 HTC_PACKET_QUEUE
*pQueueToIndicate
)
51 if (HTC_QUEUE_EMPTY(pQueueToIndicate
)) {
52 /* nothing to indicate */
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
,
62 /* all packets are now owned by the callback, reset queue to be safe */
63 INIT_HTC_PACKET_QUEUE(pQueueToIndicate
);
66 /* using legacy EpTxComplete */
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
));
79 /* do final completion on sent packet */
80 static INLINE
void CompleteSentPacket(HTC_TARGET
*target
, HTC_ENDPOINT
*pEndpoint
, HTC_PACKET
*pPacket
)
82 pPacket
->Completion
= NULL
;
84 if (A_FAILED(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 */
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
,
95 target
->EpCreditDistributionListHead
->pNext
);
96 UNLOCK_HTC_TX(target
);
98 /* first, fixup the head room we allocated */
99 pPacket
->pBuffer
+= HTC_HDR_LENGTH
;
102 /* our internal send packet completion handler when packets are submited to the AR6K device
104 static void HTCSendPktCompletionHandler(void *Context
, HTC_PACKET
*pPacket
)
106 HTC_TARGET
*target
= (HTC_TARGET
*)Context
;
107 HTC_ENDPOINT
*pEndpoint
= &target
->EndPoint
[pPacket
->Endpoint
];
108 HTC_PACKET_QUEUE container
;
110 CompleteSentPacket(target
,pEndpoint
,pPacket
);
111 INIT_HTC_PACKET_QUEUE_AND_ADD(&container
,pPacket
);
113 DO_EP_TX_COMPLETION(pEndpoint
,&container
);
116 int HTCIssueSend(HTC_TARGET
*target
, HTC_PACKET
*pPacket
)
121 if (pPacket
->Completion
== NULL
) {
122 /* mark that this request was synchronously issued */
126 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,
127 ("+-HTCIssueSend: transmit length : %d (%s) \n",
128 pPacket
->ActualLength
+ (A_UINT32
)HTC_HDR_LENGTH
,
129 sync
? "SYNC" : "ASYNC" ));
131 /* send message to device */
132 status
= DevSendPacket(&target
->Device
,
134 pPacket
->ActualLength
+ HTC_HDR_LENGTH
);
137 /* use local sync variable. If this was issued asynchronously, pPacket is no longer
139 pPacket
->pBuffer
+= HTC_HDR_LENGTH
;
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 */
148 /* get HTC send packets from the TX queue on an endpoint */
149 static INLINE
void GetHTCSendPackets(HTC_TARGET
*target
,
150 HTC_ENDPOINT
*pEndpoint
,
151 HTC_PACKET_QUEUE
*pQueue
)
157 unsigned int transferLength
;
159 /****** NOTE : the TX lock is held when this function is called *****************/
160 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+GetHTCSendPackets \n"));
162 /* loop until we can grab as many packets out of the queue as we can */
166 /* get packet at head, but don't remove it */
167 pPacket
= HTC_GET_PKT_AT_HEAD(&pEndpoint
->TxQueue
);
168 if (pPacket
== NULL
) {
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
)));
175 transferLength
= DEV_CALC_SEND_PADDED_LEN(&target
->Device
, pPacket
->ActualLength
+ HTC_HDR_LENGTH
);
177 if (transferLength
<= target
->TargetCreditSize
) {
180 /* figure out how many credits this message requires */
181 creditsRequired
= transferLength
/ target
->TargetCreditSize
;
182 remainder
= transferLength
% target
->TargetCreditSize
;
189 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,(" Creds Required:%d Got:%d\n",
190 creditsRequired
, pEndpoint
->CreditDist
.TxCredits
));
192 if (pEndpoint
->CreditDist
.TxCredits
< creditsRequired
) {
194 /* not enough credits */
195 if (pPacket
->Endpoint
== ENDPOINT_0
) {
196 /* leave it in the queue */
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
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
,
210 &pEndpoint
->CreditDist
);
211 pEndpoint
->CreditDist
.TxCreditsSeek
= 0;
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",
223 pEndpoint
->CreditDist
.TxCredits
-= creditsRequired
;
224 INC_HTC_EP_STAT(pEndpoint
, TxCreditsConsummed
, creditsRequired
);
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
;
232 DO_DISTRIBUTION(target
,
233 HTC_CREDIT_DIST_SEEK_CREDITS
,
235 &pEndpoint
->CreditDist
);
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"));
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
;
259 /* queue this packet into the caller's queue */
260 HTC_PACKET_ENQUEUE(pQueue
,pPacket
);
263 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-GetHTCSendPackets \n"));
267 static void HTCAsyncSendScatterCompletion(HIF_SCATTER_REQ
*pScatterReq
)
271 HTC_ENDPOINT
*pEndpoint
= (HTC_ENDPOINT
*)pScatterReq
->Context
;
272 HTC_TARGET
*target
= (HTC_TARGET
*)pEndpoint
->target
;
274 HTC_PACKET_QUEUE sendCompletes
;
276 INIT_HTC_PACKET_QUEUE(&sendCompletes
);
278 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+HTCAsyncSendScatterCompletion TotLen: %d Entries: %d\n",
279 pScatterReq
->TotalLength
, pScatterReq
->ValidScatterEntries
));
281 DEV_FINISH_SCATTER_OPERATION(pScatterReq
);
283 if (A_FAILED(pScatterReq
->CompletionStatus
)) {
284 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** Send Scatter Request Failed: %d \n",pScatterReq
->CompletionStatus
));
288 /* walk through the scatter list and process */
289 for (i
= 0; i
< pScatterReq
->ValidScatterEntries
; i
++) {
290 pPacket
= (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
);
298 /* free scatter request */
299 DEV_FREE_SCATTER_REQ(&target
->Device
,pScatterReq
);
300 /* complete all packets */
301 DO_EP_TX_COMPLETION(pEndpoint
,&sendCompletes
);
303 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-HTCAsyncSendScatterCompletion \n"));
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
312 static void HTCIssueSendBundle(HTC_ENDPOINT
*pEndpoint
,
313 HTC_PACKET_QUEUE
*pQueue
,
315 int *pTotalBundlesPkts
)
318 unsigned int scatterSpaceRemaining
;
319 HIF_SCATTER_REQ
*pScatterReq
= NULL
;
320 int i
, packetsInScatterReq
;
321 unsigned int transferLength
;
325 int totalPktsInBundle
= 0;
326 HTC_TARGET
*target
= pEndpoint
->target
;
327 int creditRemainder
= 0;
330 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("+HTCIssueSendBundle \n"));
334 pktsToScatter
= HTC_PACKET_QUEUE_DEPTH(pQueue
);
335 pktsToScatter
= min(pktsToScatter
, target
->MaxMsgPerBundle
);
337 if (pktsToScatter
< HTC_MIN_HTC_MSGS_TO_BUNDLE
) {
338 /* not enough to bundle */
342 pScatterReq
= DEV_ALLOC_SCATTER_REQ(&target
->Device
);
344 if (pScatterReq
== NULL
) {
345 /* no scatter resources */
346 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,(" No more scatter resources \n"));
350 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,(" pkts to scatter: %d \n", pktsToScatter
));
352 pScatterReq
->TotalLength
= 0;
353 pScatterReq
->ValidScatterEntries
= 0;
355 packetsInScatterReq
= 0;
356 scatterSpaceRemaining
= DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target
->Device
);
358 for (i
= 0; i
< pktsToScatter
; i
++) {
360 pScatterReq
->ScatterList
[i
].pCallerContexts
[0] = NULL
;
362 pPacket
= HTC_GET_PKT_AT_HEAD(pQueue
);
363 if (pPacket
== NULL
) {
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
;
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
;
383 creditPad
= creditRemainder
;
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
;
391 /* the amount to pad is too large, bail on this packet, we have to
392 * send it using the non-bundled method */
396 /* bail on this packet, user does not want padding applied */
401 if (NULL
== pPacket
) {
407 if (scatterSpaceRemaining
< transferLength
) {
408 /* exceeds what we can transfer */
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
,
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
));
432 if (packetsInScatterReq
>= HTC_MIN_HTC_MSGS_TO_BUNDLE
) {
433 /* send path is always asynchronous */
434 pScatterReq
->CompletionRoutine
= HTCAsyncSendScatterCompletion
;
435 pScatterReq
->Context
= pEndpoint
;
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 */
444 /* try to send some more */
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
= (HTC_PACKET
*)(pScatterReq
->ScatterList
[i
].pCallerContexts
[0]);
454 if (pPacket
!= NULL
) {
456 HTC_UNPREPARE_SEND_PKT(pPacket
);
457 /* queue back to the head */
458 HTC_PACKET_ENQUEUE_TO_HEAD(pQueue
,pPacket
);
462 DEV_FREE_SCATTER_REQ(&target
->Device
,pScatterReq
);
465 /* if we get here, we sent all that we could, get out */
470 *pBundlesSent
= bundlesSent
;
471 *pTotalBundlesPkts
= totalPktsInBundle
;
472 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-HTCIssueSendBundle (sent:%d) \n",bundlesSent
));
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 */
480 static HTC_SEND_QUEUE_RESULT
HTCTrySend(HTC_TARGET
*target
,
481 HTC_ENDPOINT
*pEndpoint
,
482 HTC_PACKET_QUEUE
*pCallersSendQueue
)
484 HTC_PACKET_QUEUE sendQueue
; /* temp queue to hold packets at various stages */
489 HTC_SEND_QUEUE_RESULT result
= HTC_SEND_QUEUE_OK
;
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
)));
495 /* init the local send queue */
496 INIT_HTC_PACKET_QUEUE(&sendQueue
);
500 if (NULL
== pCallersSendQueue
) {
501 /* caller didn't provide a queue, just wants us to check queues and send */
505 if (HTC_QUEUE_EMPTY(pCallersSendQueue
)) {
507 result
= HTC_SEND_QUEUE_DROP
;
511 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint
->TxQueue
) >= pEndpoint
->MaxTxQueueDepth
) {
512 /* we've already overflowed */
513 overflow
= HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue
);
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
;
522 /* if overflow is negative or zero, we are okay */
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
));
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
);
534 int goodPkts
= HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue
) - overflow
;
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
);
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
, HTC_PACKET
, ListLink
) {
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 */
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
);
567 if (HTC_QUEUE_EMPTY(&sendQueue
)) {
568 /* no packets made it in, caller will cleanup */
569 result
= HTC_SEND_QUEUE_DROP
;
576 if (result
!= HTC_SEND_QUEUE_OK
) {
577 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-HTCTrySend: \n"));
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
);
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
;
601 /***** beyond this point only 1 thread may enter ******/
603 /* now drain the endpoint TX queue for transmission as long as we have enough
607 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint
->TxQueue
) == 0) {
611 /* get all the packets for this endpoint that we can for this pass */
612 GetHTCSendPackets(target
, pEndpoint
, &sendQueue
);
614 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue
) == 0) {
615 /* didn't get any packets due to a lack of credits */
619 UNLOCK_HTC_TX(target
);
621 /* any packets to send are now in our local send queue */
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
)) {
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
;
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 */
646 HTC_PREPARE_SEND_PKT(pPacket
,
647 pPacket
->PktInfo
.AsTx
.SendFlags
,
649 pPacket
->PktInfo
.AsTx
.SeqNo
);
650 HTCIssueSend(target
, pPacket
);
652 /* go back and see if we can bundle some more */
657 INC_HTC_EP_STAT(pEndpoint
, TxBundles
, bundlesSent
);
658 INC_HTC_EP_STAT(pEndpoint
, TxPacketsBundled
, pktsInBundles
);
662 /* done with this endpoint, we can clear the count */
663 pEndpoint
->TxProcessCount
= 0;
664 UNLOCK_HTC_TX(target
);
666 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
,("-HTCTrySend: \n"));
668 return HTC_SEND_QUEUE_OK
;
671 int HTCSendPktsMultiple(HTC_HANDLE HTCHandle
, HTC_PACKET_QUEUE
*pPktQueue
)
673 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
674 HTC_ENDPOINT
*pEndpoint
;
677 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("+HTCSendPktsMultiple: Queue: 0x%lX, Pkts %d \n",
678 (unsigned long)pPktQueue
, HTC_PACKET_QUEUE_DEPTH(pPktQueue
)));
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"));
687 AR_DEBUG_ASSERT(pPacket
->Endpoint
< ENDPOINT_MAX
);
688 pEndpoint
= &target
->EndPoint
[pPacket
->Endpoint
];
690 HTCTrySend(target
, pEndpoint
, pPktQueue
);
692 /* do completion on any packets that couldn't get in */
693 if (!HTC_QUEUE_EMPTY(pPktQueue
)) {
695 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue
,pPacket
) {
696 if (HTC_STOPPING(target
)) {
697 pPacket
->Status
= A_ECANCELED
;
699 pPacket
->Status
= A_NO_RESOURCE
;
701 } HTC_PACKET_QUEUE_ITERATE_END
;
703 DO_EP_TX_COMPLETION(pEndpoint
,pPktQueue
);
706 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("-HTCSendPktsMultiple \n"));
711 /* HTC API - HTCSendPkt */
712 int HTCSendPkt(HTC_HANDLE HTCHandle
, HTC_PACKET
*pPacket
)
714 HTC_PACKET_QUEUE queue
;
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
);
723 /* check TX queues to drain because of credit distribution update */
724 static INLINE
void HTCCheckEndpointTxQueues(HTC_TARGET
*target
)
726 HTC_ENDPOINT
*pEndpoint
;
727 HTC_ENDPOINT_CREDIT_DIST
*pDistItem
;
729 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("+HTCCheckEndpointTxQueues \n"));
730 pDistItem
= target
->EpCreditDistributionListHead
;
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
= (HTC_ENDPOINT
*)pDistItem
->pHTCReserved
;
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
746 HTCTrySend(target
, pEndpoint
, NULL
);
749 pDistItem
= pDistItem
->pNext
;
752 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("-HTCCheckEndpointTxQueues \n"));
755 /* process credit reports and call distribution function */
756 void HTCProcessCreditRpt(HTC_TARGET
*target
, HTC_CREDIT_REPORT
*pRpt
, int NumEntries
, HTC_ENDPOINT_ID FromEndpoint
)
759 HTC_ENDPOINT
*pEndpoint
;
760 int totalCredits
= 0;
761 A_BOOL doDist
= FALSE
;
763 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries
));
765 /* lock out TX while we update credits */
768 for (i
= 0; i
< NumEntries
; i
++, pRpt
++) {
769 if (pRpt
->EndpointID
>= ENDPOINT_MAX
) {
770 AR_DEBUG_ASSERT(FALSE
);
774 pEndpoint
= &target
->EndPoint
[pRpt
->EndpointID
];
776 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, (" Endpoint %d got %d credits \n",
777 pRpt
->EndpointID
, pRpt
->Credits
));
780 #ifdef HTC_EP_STAT_PROFILING
782 INC_HTC_EP_STAT(pEndpoint
, TxCreditRpts
, 1);
783 INC_HTC_EP_STAT(pEndpoint
, TxCreditsReturned
, pRpt
->Credits
);
785 if (FromEndpoint
== pRpt
->EndpointID
) {
786 /* this credit report arrived on the same endpoint indicating it arrived in an RX
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);
795 /* arrived on another endpoint */
796 INC_HTC_EP_STAT(pEndpoint
, TxCreditsFromOther
, pRpt
->Credits
);
797 INC_HTC_EP_STAT(pEndpoint
, TxCreditRptsFromOther
, 1);
802 if (ENDPOINT_0
== pRpt
->EndpointID
) {
803 /* always give endpoint 0 credits back */
804 pEndpoint
->CreditDist
.TxCredits
+= pRpt
->Credits
;
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 */
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
);
817 totalCredits
+= pRpt
->Credits
;
820 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, (" Report indicated %d credits to distribute \n", totalCredits
));
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
,
828 target
->EpCreditDistributionListHead
->pNext
);
831 UNLOCK_HTC_TX(target
);
834 HTCCheckEndpointTxQueues(target
);
837 AR_DEBUG_PRINTF(ATH_DEBUG_SEND
, ("-HTCProcessCreditRpt \n"));
840 /* flush endpoint TX queue */
841 static void HTCFlushEndpointTX(HTC_TARGET
*target
, HTC_ENDPOINT
*pEndpoint
, HTC_TX_TAG Tag
)
844 HTC_PACKET_QUEUE discardQueue
;
845 HTC_PACKET_QUEUE container
;
847 /* initialize the discard queue */
848 INIT_HTC_PACKET_QUEUE(&discardQueue
);
852 /* interate from the front of the TX queue and flush out packets */
853 ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint
->TxQueue
.QueueHead
, pPacket
, HTC_PACKET
, ListLink
) {
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
);
865 UNLOCK_HTC_TX(target
);
867 /* empty the discard queue */
869 pPacket
= HTC_PACKET_DEQUEUE(&discardQueue
);
870 if (NULL
== pPacket
) {
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
);
882 void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST
*pEPDist
)
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(&((HTC_ENDPOINT
*)pEPDist
->pHTCReserved
)->TxQueue
)));
899 AR_DEBUG_PRINTF(ATH_DEBUG_ANY
, ("----------------------------------------------------\n"));
902 void DumpCreditDistStates(HTC_TARGET
*target
)
904 HTC_ENDPOINT_CREDIT_DIST
*pEPList
= target
->EpCreditDistributionListHead
;
906 while (pEPList
!= NULL
) {
907 DumpCreditDist(pEPList
);
908 pEPList
= pEPList
->pNext
;
911 if (target
->DistributeCredits
!= NULL
) {
912 DO_DISTRIBUTION(target
,
913 HTC_DUMP_CREDIT_STATE
,
919 /* flush all send packets from all endpoint queues */
920 void HTCFlushSendPkts(HTC_TARGET
*target
)
922 HTC_ENDPOINT
*pEndpoint
;
925 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC
)) {
926 DumpCreditDistStates(target
);
929 for (i
= ENDPOINT_0
; i
< ENDPOINT_MAX
; i
++) {
930 pEndpoint
= &target
->EndPoint
[i
];
931 if (pEndpoint
->ServiceID
== 0) {
935 HTCFlushEndpointTX(target
,pEndpoint
,HTC_TX_PACKET_TAG_ALL
);
941 /* HTC API to flush an endpoint's TX queue*/
942 void HTCFlushEndpoint(HTC_HANDLE HTCHandle
, HTC_ENDPOINT_ID Endpoint
, HTC_TX_TAG Tag
)
944 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
945 HTC_ENDPOINT
*pEndpoint
= &target
->EndPoint
[Endpoint
];
947 if (pEndpoint
->ServiceID
== 0) {
948 AR_DEBUG_ASSERT(FALSE
);
953 HTCFlushEndpointTX(target
, pEndpoint
, Tag
);
956 /* HTC API to indicate activity to the credit distribution function */
957 void HTCIndicateActivityChange(HTC_HANDLE HTCHandle
,
958 HTC_ENDPOINT_ID Endpoint
,
961 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
962 HTC_ENDPOINT
*pEndpoint
= &target
->EndPoint
[Endpoint
];
963 A_BOOL doDist
= FALSE
;
965 if (pEndpoint
->ServiceID
== 0) {
966 AR_DEBUG_ASSERT(FALSE
);
974 if (!(pEndpoint
->CreditDist
.DistFlags
& HTC_EP_ACTIVE
)) {
975 /* mark active now */
976 pEndpoint
->CreditDist
.DistFlags
|= HTC_EP_ACTIVE
;
980 if (pEndpoint
->CreditDist
.DistFlags
& HTC_EP_ACTIVE
) {
981 /* mark inactive now */
982 pEndpoint
->CreditDist
.DistFlags
&= ~HTC_EP_ACTIVE
;
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
,
995 target
->EpCreditDistributionListHead
->pNext
);
998 UNLOCK_HTC_TX(target
);
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
1004 HTCCheckEndpointTxQueues(target
);
1008 A_BOOL
HTCIsEndpointActive(HTC_HANDLE HTCHandle
,
1009 HTC_ENDPOINT_ID Endpoint
)
1011 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1012 HTC_ENDPOINT
*pEndpoint
= &target
->EndPoint
[Endpoint
];
1014 if (pEndpoint
->ServiceID
== 0) {
1018 if (pEndpoint
->CreditDist
.DistFlags
& HTC_EP_ACTIVE
) {