ath6kl: remove-typedef HTC_ENDPOINT
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / ath6kl / htc2 / htc_send.c
blob4e1d9bc732d09a5f37c01c9b749ad50274830830
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.
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) \
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)); \
46 static void DoSendCompletion(struct htc_endpoint *pEndpoint,
47 HTC_PACKET_QUEUE *pQueueToIndicate)
49 do {
51 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
52 /* nothing to indicate */
53 break;
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 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));
75 } while (false);
79 /* do final completion on sent packet */
80 static INLINE void CompleteSentPacket(HTC_TARGET *target, struct htc_endpoint *pEndpoint, HTC_PACKET *pPacket)
82 pPacket->Completion = NULL;
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);
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
103 * layer */
104 static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
106 HTC_TARGET *target = (HTC_TARGET *)Context;
107 struct 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);
112 /* do completion */
113 DO_EP_TX_COMPLETION(pEndpoint,&container);
116 int HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket)
118 int status;
119 bool sync = false;
121 if (pPacket->Completion == NULL) {
122 /* mark that this request was synchronously issued */
123 sync = true;
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" ));
131 /* send message to device */
132 status = DevSendPacket(&target->Device,
133 pPacket,
134 pPacket->ActualLength + HTC_HDR_LENGTH);
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;
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 */
145 return status;
148 /* get HTC send packets from the TX queue on an endpoint */
149 static INLINE void GetHTCSendPackets(HTC_TARGET *target,
150 struct htc_endpoint *pEndpoint,
151 HTC_PACKET_QUEUE *pQueue)
153 int creditsRequired;
154 int remainder;
155 u8 sendFlags;
156 HTC_PACKET *pPacket;
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 */
163 while (true) {
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;
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) {
178 creditsRequired = 1;
179 } else {
180 /* figure out how many credits this message requires */
181 creditsRequired = transferLength / target->TargetCreditSize;
182 remainder = transferLength % target->TargetCreditSize;
184 if (remainder) {
185 creditsRequired++;
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 */
197 break;
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 * */
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;
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;
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,
234 "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;
258 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(struct hif_scatter_req *pScatterReq)
269 int i;
270 HTC_PACKET *pPacket;
271 struct htc_endpoint *pEndpoint = (struct htc_endpoint *)pScatterReq->Context;
272 HTC_TARGET *target = (HTC_TARGET *)pEndpoint->target;
273 int status = 0;
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 (pScatterReq->CompletionStatus) {
284 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Send Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
285 status = A_ERROR;
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
311 * */
312 static void HTCIssueSendBundle(struct htc_endpoint *pEndpoint,
313 HTC_PACKET_QUEUE *pQueue,
314 int *pBundlesSent,
315 int *pTotalBundlesPkts)
317 int pktsToScatter;
318 unsigned int scatterSpaceRemaining;
319 struct hif_scatter_req *pScatterReq = NULL;
320 int i, packetsInScatterReq;
321 unsigned int transferLength;
322 HTC_PACKET *pPacket;
323 bool done = false;
324 int bundlesSent = 0;
325 int totalPktsInBundle = 0;
326 HTC_TARGET *target = pEndpoint->target;
327 int creditRemainder = 0;
328 int creditPad;
330 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCIssueSendBundle \n"));
332 while (!done) {
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 */
339 break;
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"));
347 break;
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) {
364 A_ASSERT(false);
365 break;
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;
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;
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;
395 } else {
396 /* bail on this packet, user does not want padding applied */
397 pPacket = NULL;
401 if (NULL == pPacket) {
402 /* can't bundle */
403 done = true;
404 break;
407 if (scatterSpaceRemaining < transferLength) {
408 /* exceeds what we can transfer */
409 break;
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));
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;
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) {
455 /* undo any prep */
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 */
466 break;
470 *pBundlesSent = bundlesSent;
471 *pTotalBundlesPkts = totalPktsInBundle;
472 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCIssueSendBundle (sent:%d) \n",bundlesSent));
474 return;
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 struct htc_endpoint *pEndpoint,
482 HTC_PACKET_QUEUE *pCallersSendQueue)
484 HTC_PACKET_QUEUE sendQueue; /* temp queue to hold packets at various stages */
485 HTC_PACKET *pPacket;
486 int bundlesSent;
487 int pktsInBundles;
488 int overflow;
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);
498 do {
500 if (NULL == pCallersSendQueue) {
501 /* caller didn't provide a queue, just wants us to check queues and send */
502 break;
505 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
506 /* empty queue */
507 result = HTC_SEND_QUEUE_DROP;
508 break;
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;
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));
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;
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 */
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);
565 } ITERATE_END;
567 if (HTC_QUEUE_EMPTY(&sendQueue)) {
568 /* no packets made it in, caller will cleanup */
569 result = HTC_SEND_QUEUE_DROP;
570 break;
574 } while (false);
576 if (result != HTC_SEND_QUEUE_OK) {
577 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
578 return result;
581 LOCK_HTC_TX(target);
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
604 * credits */
605 while (true) {
607 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) {
608 break;
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 */
616 break;
619 UNLOCK_HTC_TX(target);
621 /* any packets to send are now in our local send queue */
623 bundlesSent = 0;
624 pktsInBundles = 0;
626 while (true) {
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;
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;
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 */
655 LOCK_HTC_TX(target);
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 struct htc_endpoint *pEndpoint;
675 HTC_PACKET *pPacket;
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"));
684 return A_EINVAL;
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;
698 } else {
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"));
708 return 0;
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 struct 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 = (struct 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
745 * ones */
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)
758 int i;
759 struct htc_endpoint *pEndpoint;
760 int totalCredits = 0;
761 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 */
766 LOCK_HTC_TX(target);
768 for (i = 0; i < NumEntries; i++, pRpt++) {
769 if (pRpt->EndpointID >= ENDPOINT_MAX) {
770 AR_DEBUG_ASSERT(false);
771 break;
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
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);
800 #endif
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;
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));
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);
831 UNLOCK_HTC_TX(target);
833 if (totalCredits) {
834 HTCCheckEndpointTxQueues(target);
837 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
840 /* flush endpoint TX queue */
841 static void HTCFlushEndpointTX(HTC_TARGET *target, struct htc_endpoint *pEndpoint, HTC_TX_TAG Tag)
843 HTC_PACKET *pPacket;
844 HTC_PACKET_QUEUE discardQueue;
845 HTC_PACKET_QUEUE container;
847 /* initialize the discard queue */
848 INIT_HTC_PACKET_QUEUE(&discardQueue);
850 LOCK_HTC_TX(target);
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);
863 } ITERATE_END;
865 UNLOCK_HTC_TX(target);
867 /* empty the discard queue */
868 while (1) {
869 pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
870 if (NULL == pPacket) {
871 break;
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(&((struct 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,
914 "Dump State",
915 NULL);
919 /* flush all send packets from all endpoint queues */
920 void HTCFlushSendPkts(HTC_TARGET *target)
922 struct htc_endpoint *pEndpoint;
923 int i;
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) {
932 /* not in use.. */
933 continue;
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 struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
947 if (pEndpoint->ServiceID == 0) {
948 AR_DEBUG_ASSERT(false);
949 /* not in use.. */
950 return;
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,
959 bool Active)
961 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
962 struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
963 bool doDist = false;
965 if (pEndpoint->ServiceID == 0) {
966 AR_DEBUG_ASSERT(false);
967 /* not in use.. */
968 return;
971 LOCK_HTC_TX(target);
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;
979 } else {
980 if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
981 /* mark inactive now */
982 pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
983 doDist = true;
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);
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
1003 * HTC queues */
1004 HTCCheckEndpointTxQueues(target);
1008 bool HTCIsEndpointActive(HTC_HANDLE HTCHandle,
1009 HTC_ENDPOINT_ID Endpoint)
1011 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1012 struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
1014 if (pEndpoint->ServiceID == 0) {
1015 return false;
1018 if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
1019 return true;
1022 return false;