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