1 //------------------------------------------------------------------------------
2 // <copyright file="htc_recv.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 #define HTCIssueRecv(t, p) \
26 DevRecvPacket(&(t)->Device, \
30 #define DO_RCV_COMPLETION(e,q) DoRecvCompletion(e,q)
32 #define DUMP_RECV_PKT_INFO(pP) \
33 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC RECV packet 0x%lX (%d bytes) (hdr:0x%X) on ep : %d \n", \
34 (unsigned long)(pP), \
36 (pP)->PktInfo.AsRx.ExpectedHdr, \
39 #ifdef HTC_EP_STAT_PROFILING
40 #define HTC_RX_STAT_PROFILE(t,ep,numLookAheads) \
42 INC_HTC_EP_STAT((ep), RxReceived, 1); \
43 if ((numLookAheads) == 1) { \
44 INC_HTC_EP_STAT((ep), RxLookAheads, 1); \
45 } else if ((numLookAheads) > 1) { \
46 INC_HTC_EP_STAT((ep), RxBundleLookAheads, 1); \
50 #define HTC_RX_STAT_PROFILE(t,ep,lookAhead)
53 static void DoRecvCompletion(HTC_ENDPOINT
*pEndpoint
,
54 HTC_PACKET_QUEUE
*pQueueToIndicate
)
59 if (HTC_QUEUE_EMPTY(pQueueToIndicate
)) {
60 /* nothing to indicate */
64 if (pEndpoint
->EpCallBacks
.EpRecvPktMultiple
!= NULL
) {
65 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, (" HTC calling ep %d, recv multiple callback (%d pkts) \n",
66 pEndpoint
->Id
, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate
)));
67 /* a recv multiple handler is being used, pass the queue to the handler */
68 pEndpoint
->EpCallBacks
.EpRecvPktMultiple(pEndpoint
->EpCallBacks
.pContext
,
70 INIT_HTC_PACKET_QUEUE(pQueueToIndicate
);
73 /* using legacy EpRecv */
75 pPacket
= HTC_PACKET_DEQUEUE(pQueueToIndicate
);
76 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, (" HTC calling ep %d recv callback on packet 0x%lX \n", \
77 pEndpoint
->Id
, (unsigned long)(pPacket
)));
78 pEndpoint
->EpCallBacks
.EpRecv(pEndpoint
->EpCallBacks
.pContext
, pPacket
);
79 } while (!HTC_QUEUE_EMPTY(pQueueToIndicate
));
86 static INLINE
int HTCProcessTrailer(HTC_TARGET
*target
,
89 A_UINT32
*pNextLookAheads
,
91 HTC_ENDPOINT_ID FromEndpoint
)
93 HTC_RECORD_HDR
*pRecord
;
95 HTC_LOOKAHEAD_REPORT
*pLookAhead
;
100 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("+HTCProcessTrailer (length:%d) \n", Length
));
102 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV
)) {
103 AR_DEBUG_PRINTBUF(pBuffer
,Length
,"Recv Trailer");
106 pOrigBuffer
= pBuffer
;
112 if (Length
< sizeof(HTC_RECORD_HDR
)) {
116 /* these are byte aligned structs */
117 pRecord
= (HTC_RECORD_HDR
*)pBuffer
;
118 Length
-= sizeof(HTC_RECORD_HDR
);
119 pBuffer
+= sizeof(HTC_RECORD_HDR
);
121 if (pRecord
->Length
> Length
) {
122 /* no room left in buffer for record */
123 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
124 (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
125 pRecord
->Length
, pRecord
->RecordID
, Length
));
129 /* start of record follows the header */
130 pRecordBuf
= pBuffer
;
132 switch (pRecord
->RecordID
) {
133 case HTC_RECORD_CREDITS
:
134 AR_DEBUG_ASSERT(pRecord
->Length
>= sizeof(HTC_CREDIT_REPORT
));
135 HTCProcessCreditRpt(target
,
136 (HTC_CREDIT_REPORT
*)pRecordBuf
,
137 pRecord
->Length
/ (sizeof(HTC_CREDIT_REPORT
)),
140 case HTC_RECORD_LOOKAHEAD
:
141 AR_DEBUG_ASSERT(pRecord
->Length
>= sizeof(HTC_LOOKAHEAD_REPORT
));
142 pLookAhead
= (HTC_LOOKAHEAD_REPORT
*)pRecordBuf
;
143 if ((pLookAhead
->PreValid
== ((~pLookAhead
->PostValid
) & 0xFF)) &&
144 (pNextLookAheads
!= NULL
)) {
146 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
147 (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
148 pLookAhead
->PreValid
,
149 pLookAhead
->PostValid
));
151 /* look ahead bytes are valid, copy them over */
152 ((A_UINT8
*)(&pNextLookAheads
[0]))[0] = pLookAhead
->LookAhead
[0];
153 ((A_UINT8
*)(&pNextLookAheads
[0]))[1] = pLookAhead
->LookAhead
[1];
154 ((A_UINT8
*)(&pNextLookAheads
[0]))[2] = pLookAhead
->LookAhead
[2];
155 ((A_UINT8
*)(&pNextLookAheads
[0]))[3] = pLookAhead
->LookAhead
[3];
157 #ifdef ATH_DEBUG_MODULE
158 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV
)) {
159 DebugDumpBytes((A_UINT8
*)pNextLookAheads
,4,"Next Look Ahead");
162 /* just one normal lookahead */
166 case HTC_RECORD_LOOKAHEAD_BUNDLE
:
167 AR_DEBUG_ASSERT(pRecord
->Length
>= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT
));
168 if (pRecord
->Length
>= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT
) &&
169 (pNextLookAheads
!= NULL
)) {
170 HTC_BUNDLED_LOOKAHEAD_REPORT
*pBundledLookAheadRpt
;
173 pBundledLookAheadRpt
= (HTC_BUNDLED_LOOKAHEAD_REPORT
*)pRecordBuf
;
175 #ifdef ATH_DEBUG_MODULE
176 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV
)) {
177 DebugDumpBytes(pRecordBuf
,pRecord
->Length
,"Bundle LookAhead");
181 if ((pRecord
->Length
/ (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT
))) >
182 HTC_HOST_MAX_MSG_PER_BUNDLE
) {
183 /* this should never happen, the target restricts the number
184 * of messages per bundle configured by the host */
190 for (i
= 0; i
< (int)(pRecord
->Length
/ (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT
))); i
++) {
191 ((A_UINT8
*)(&pNextLookAheads
[i
]))[0] = pBundledLookAheadRpt
->LookAhead
[0];
192 ((A_UINT8
*)(&pNextLookAheads
[i
]))[1] = pBundledLookAheadRpt
->LookAhead
[1];
193 ((A_UINT8
*)(&pNextLookAheads
[i
]))[2] = pBundledLookAheadRpt
->LookAhead
[2];
194 ((A_UINT8
*)(&pNextLookAheads
[i
]))[3] = pBundledLookAheadRpt
->LookAhead
[3];
195 pBundledLookAheadRpt
++;
202 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, (" unhandled record: id:%d length:%d \n",
203 pRecord
->RecordID
, pRecord
->Length
));
211 /* advance buffer past this record for next time around */
212 pBuffer
+= pRecord
->Length
;
213 Length
-= pRecord
->Length
;
216 #ifdef ATH_DEBUG_MODULE
218 DebugDumpBytes(pOrigBuffer
,origLength
,"BAD Recv Trailer");
222 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("-HTCProcessTrailer \n"));
227 /* process a received message (i.e. strip off header, process any trailer data)
228 * note : locks must be released when this function is called */
229 static int HTCProcessRecvHeader(HTC_TARGET
*target
,
231 A_UINT32
*pNextLookAheads
,
240 pBuf
= pPacket
->pBuffer
;
242 if (pNumLookAheads
!= NULL
) {
246 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("+HTCProcessRecvHeader \n"));
248 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV
)) {
249 AR_DEBUG_PRINTBUF(pBuf
,pPacket
->ActualLength
,"HTC Recv PKT");
253 /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
254 * retrieve 16 bit fields */
255 payloadLen
= A_GET_UINT16_FIELD(pBuf
, HTC_FRAME_HDR
, PayloadLen
);
257 ((A_UINT8
*)&lookAhead
)[0] = pBuf
[0];
258 ((A_UINT8
*)&lookAhead
)[1] = pBuf
[1];
259 ((A_UINT8
*)&lookAhead
)[2] = pBuf
[2];
260 ((A_UINT8
*)&lookAhead
)[3] = pBuf
[3];
262 if (pPacket
->PktInfo
.AsRx
.HTCRxFlags
& HTC_RX_PKT_REFRESH_HDR
) {
263 /* refresh expected hdr, since this was unknown at the time we grabbed the packets
264 * as part of a bundle */
265 pPacket
->PktInfo
.AsRx
.ExpectedHdr
= lookAhead
;
266 /* refresh actual length since we now have the real header */
267 pPacket
->ActualLength
= payloadLen
+ HTC_HDR_LENGTH
;
269 /* validate the actual header that was refreshed */
270 if (pPacket
->ActualLength
> pPacket
->BufferLength
) {
271 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
272 ("Refreshed HDR payload length (%d) in bundled RECV is invalid (hdr: 0x%X) \n",
273 payloadLen
, lookAhead
));
274 /* limit this to max buffer just to print out some of the buffer */
275 pPacket
->ActualLength
= min(pPacket
->ActualLength
, pPacket
->BufferLength
);
280 if (pPacket
->Endpoint
!= A_GET_UINT8_FIELD(pBuf
, HTC_FRAME_HDR
, EndpointID
)) {
281 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
282 ("Refreshed HDR endpoint (%d) does not match expected endpoint (%d) \n",
283 A_GET_UINT8_FIELD(pBuf
, HTC_FRAME_HDR
, EndpointID
), pPacket
->Endpoint
));
289 if (lookAhead
!= pPacket
->PktInfo
.AsRx
.ExpectedHdr
) {
290 /* somehow the lookahead that gave us the full read length did not
291 * reflect the actual header in the pending message */
292 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
293 ("HTCProcessRecvHeader, lookahead mismatch! (pPkt:0x%lX flags:0x%X) \n",
294 (unsigned long)pPacket
, pPacket
->PktInfo
.AsRx
.HTCRxFlags
));
295 #ifdef ATH_DEBUG_MODULE
296 DebugDumpBytes((A_UINT8
*)&pPacket
->PktInfo
.AsRx
.ExpectedHdr
,4,"Expected Message LookAhead");
297 DebugDumpBytes(pBuf
,sizeof(HTC_FRAME_HDR
),"Current Frame Header");
298 #ifdef HTC_CAPTURE_LAST_FRAME
299 DebugDumpBytes((A_UINT8
*)&target
->LastFrameHdr
,sizeof(HTC_FRAME_HDR
),"Last Frame Header");
300 if (target
->LastTrailerLength
!= 0) {
301 DebugDumpBytes(target
->LastTrailer
,
302 target
->LastTrailerLength
,
312 temp
= A_GET_UINT8_FIELD(pBuf
, HTC_FRAME_HDR
, Flags
);
314 if (temp
& HTC_FLAGS_RECV_TRAILER
) {
315 /* this packet has a trailer */
317 /* extract the trailer length in control byte 0 */
318 temp
= A_GET_UINT8_FIELD(pBuf
, HTC_FRAME_HDR
, ControlBytes
[0]);
320 if ((temp
< sizeof(HTC_RECORD_HDR
)) || (temp
> payloadLen
)) {
321 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
322 ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
328 if (pPacket
->PktInfo
.AsRx
.HTCRxFlags
& HTC_RX_PKT_IGNORE_LOOKAHEAD
) {
329 /* this packet was fetched as part of an HTC bundle, the embedded lookahead is
330 * not valid since the next packet may have already been fetched as part of the
332 pNextLookAheads
= NULL
;
333 pNumLookAheads
= NULL
;
336 /* process trailer data that follows HDR + application payload */
337 status
= HTCProcessTrailer(target
,
338 (pBuf
+ HTC_HDR_LENGTH
+ payloadLen
- temp
),
348 #ifdef HTC_CAPTURE_LAST_FRAME
349 A_MEMCPY(target
->LastTrailer
, (pBuf
+ HTC_HDR_LENGTH
+ payloadLen
- temp
), temp
);
350 target
->LastTrailerLength
= temp
;
352 /* trim length by trailer bytes */
353 pPacket
->ActualLength
-= temp
;
355 #ifdef HTC_CAPTURE_LAST_FRAME
357 target
->LastTrailerLength
= 0;
361 /* if we get to this point, the packet is good */
362 /* remove header and adjust length */
363 pPacket
->pBuffer
+= HTC_HDR_LENGTH
;
364 pPacket
->ActualLength
-= HTC_HDR_LENGTH
;
369 /* dump the whole packet */
370 #ifdef ATH_DEBUG_MODULE
371 DebugDumpBytes(pBuf
,pPacket
->ActualLength
< 256 ? pPacket
->ActualLength
: 256 ,"BAD HTC Recv PKT");
374 #ifdef HTC_CAPTURE_LAST_FRAME
375 A_MEMCPY(&target
->LastFrameHdr
,pBuf
,sizeof(HTC_FRAME_HDR
));
377 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV
)) {
378 if (pPacket
->ActualLength
> 0) {
379 AR_DEBUG_PRINTBUF(pPacket
->pBuffer
,pPacket
->ActualLength
,"HTC - Application Msg");
384 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("-HTCProcessRecvHeader \n"));
388 static INLINE
void HTCAsyncRecvCheckMorePackets(HTC_TARGET
*target
,
389 A_UINT32 NextLookAheads
[],
393 /* was there a lookahead for the next packet? */
394 if (NumLookAheads
> 0) {
397 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
398 ("HTCAsyncRecvCheckMorePackets - num lookaheads were non-zero : %d \n",
400 /* force status re-check */
401 REF_IRQ_STATUS_RECHECK(&target
->Device
);
402 /* we have more packets, get the next packet fetch started */
403 nextStatus
= HTCRecvMessagePendingHandler(target
, NextLookAheads
, NumLookAheads
, NULL
, &fetched
);
404 if (A_EPROTO
== nextStatus
) {
405 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
406 ("Next look ahead from recv header was INVALID\n"));
407 #ifdef ATH_DEBUG_MODULE
408 DebugDumpBytes((A_UINT8
*)NextLookAheads
,
409 NumLookAheads
* (sizeof(A_UINT32
)),
410 "BAD lookaheads from lookahead report");
413 if (!nextStatus
&& !fetched
) {
414 /* we could not fetch any more packets due to resources */
415 DevAsyncIrqProcessComplete(&target
->Device
);
419 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
420 ("HTCAsyncRecvCheckMorePackets - rechecking for more messages...\n"));
421 /* if we did not get anything on the look-ahead,
422 * call device layer to asynchronously re-check for messages. If we can keep the async
423 * processing going we get better performance. If there is a pending message we will keep processing
424 * messages asynchronously which should pipeline things nicely */
425 DevCheckPendingRecvMsgsAsync(&target
->Device
);
427 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("HTCAsyncRecvCheckMorePackets - no check \n"));
434 /* unload the recv completion queue */
435 static INLINE
void DrainRecvIndicationQueue(HTC_TARGET
*target
, HTC_ENDPOINT
*pEndpoint
)
437 HTC_PACKET_QUEUE recvCompletions
;
439 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("+DrainRecvIndicationQueue \n"));
441 INIT_HTC_PACKET_QUEUE(&recvCompletions
);
445 /* increment rx processing count on entry */
446 pEndpoint
->RxProcessCount
++;
447 if (pEndpoint
->RxProcessCount
> 1) {
448 pEndpoint
->RxProcessCount
--;
449 /* another thread or task is draining the RX completion queue on this endpoint
450 * that thread will reset the rx processing count when the queue is drained */
451 UNLOCK_HTC_RX(target
);
455 /******* at this point only 1 thread may enter ******/
459 /* transfer items from main recv queue to the local one so we can release the lock */
460 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&recvCompletions
, &pEndpoint
->RecvIndicationQueue
);
462 if (HTC_QUEUE_EMPTY(&recvCompletions
)) {
467 /* release lock while we do the recv completions
468 * other threads can now queue more recv completions */
469 UNLOCK_HTC_RX(target
);
471 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
472 ("DrainRecvIndicationQueue : completing %d RECV packets \n",
473 HTC_PACKET_QUEUE_DEPTH(&recvCompletions
)));
475 DO_RCV_COMPLETION(pEndpoint
,&recvCompletions
);
477 /* re-acquire lock to grab some more completions */
482 pEndpoint
->RxProcessCount
= 0;
483 UNLOCK_HTC_RX(target
);
485 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("-DrainRecvIndicationQueue \n"));
489 /* optimization for recv packets, we can indicate a "hint" that there are more
490 * single-packets to fetch on this endpoint */
491 #define SET_MORE_RX_PACKET_INDICATION_FLAG(L,N,E,P) \
492 if ((N) > 0) { SetRxPacketIndicationFlags((L)[0],(E),(P)); }
494 /* for bundled frames, we can force the flag to indicate there are more packets */
495 #define FORCE_MORE_RX_PACKET_INDICATION_FLAG(P) \
496 (P)->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS;
498 /* note: this function can be called with the RX lock held */
499 static INLINE
void SetRxPacketIndicationFlags(A_UINT32 LookAhead
,
500 HTC_ENDPOINT
*pEndpoint
,
503 HTC_FRAME_HDR
*pHdr
= (HTC_FRAME_HDR
*)&LookAhead
;
504 /* check to see if the "next" packet is from the same endpoint of the
506 if (pHdr
->EndpointID
== pPacket
->Endpoint
) {
507 /* check that there is a buffer available to actually fetch it */
508 if (!HTC_QUEUE_EMPTY(&pEndpoint
->RxBuffers
)) {
509 /* provide a hint that there are more RX packets to fetch */
510 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket
);
516 /* asynchronous completion handler for recv packet fetching, when the device layer
517 * completes a read request, it will call this completion handler */
518 void HTCRecvCompleteHandler(void *Context
, HTC_PACKET
*pPacket
)
520 HTC_TARGET
*target
= (HTC_TARGET
*)Context
;
521 HTC_ENDPOINT
*pEndpoint
;
522 A_UINT32 nextLookAheads
[HTC_HOST_MAX_MSG_PER_BUNDLE
];
523 int numLookAheads
= 0;
525 bool checkMorePkts
= true;
527 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("+HTCRecvCompleteHandler (pkt:0x%lX, status:%d, ep:%d) \n",
528 (unsigned long)pPacket
, pPacket
->Status
, pPacket
->Endpoint
));
530 A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target
->Device
));
531 AR_DEBUG_ASSERT(pPacket
->Endpoint
< ENDPOINT_MAX
);
532 pEndpoint
= &target
->EndPoint
[pPacket
->Endpoint
];
533 pPacket
->Completion
= NULL
;
535 /* get completion status */
536 status
= pPacket
->Status
;
541 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
542 pPacket
->Status
, pPacket
->Endpoint
));
545 /* process the header for any trailer data */
546 status
= HTCProcessRecvHeader(target
,pPacket
,nextLookAheads
,&numLookAheads
);
552 if (pPacket
->PktInfo
.AsRx
.HTCRxFlags
& HTC_RX_PKT_IGNORE_LOOKAHEAD
) {
553 /* this packet was part of a bundle that had to be broken up.
554 * It was fetched one message at a time. There may be other asynchronous reads queued behind this one.
555 * Do no issue another check for more packets since the last one in the series of requests
557 checkMorePkts
= false;
560 DUMP_RECV_PKT_INFO(pPacket
);
562 SET_MORE_RX_PACKET_INDICATION_FLAG(nextLookAheads
,numLookAheads
,pEndpoint
,pPacket
);
563 /* we have a good packet, queue it to the completion queue */
564 HTC_PACKET_ENQUEUE(&pEndpoint
->RecvIndicationQueue
,pPacket
);
565 HTC_RX_STAT_PROFILE(target
,pEndpoint
,numLookAheads
);
566 UNLOCK_HTC_RX(target
);
568 /* check for more recv packets before indicating */
569 HTCAsyncRecvCheckMorePackets(target
,nextLookAheads
,numLookAheads
,checkMorePkts
);
574 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
575 ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
577 /* recycle this packet */
578 HTC_RECYCLE_RX_PKT(target
, pPacket
, pEndpoint
);
580 /* a good packet was queued, drain the queue */
581 DrainRecvIndicationQueue(target
,pEndpoint
);
584 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, ("-HTCRecvCompleteHandler\n"));
587 /* synchronously wait for a control message from the target,
588 * This function is used at initialization time ONLY. At init messages
589 * on ENDPOINT 0 are expected. */
590 int HTCWaitforControlMessage(HTC_TARGET
*target
, HTC_PACKET
**ppControlPacket
)
594 HTC_PACKET
*pPacket
= NULL
;
597 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HTCWaitforControlMessage \n"));
601 *ppControlPacket
= NULL
;
603 /* call the polling function to see if we have a message */
604 status
= DevPollMboxMsgRecv(&target
->Device
,
606 HTC_TARGET_RESPONSE_TIMEOUT
);
612 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
613 ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead
));
615 /* check the lookahead */
616 pHdr
= (HTC_FRAME_HDR
*)&lookAhead
;
618 if (pHdr
->EndpointID
!= ENDPOINT_0
) {
619 /* unexpected endpoint number, should be zero */
620 AR_DEBUG_ASSERT(false);
627 AR_DEBUG_ASSERT(false);
632 pPacket
= HTC_ALLOC_CONTROL_RX(target
);
634 if (pPacket
== NULL
) {
635 AR_DEBUG_ASSERT(false);
636 status
= A_NO_MEMORY
;
640 pPacket
->PktInfo
.AsRx
.HTCRxFlags
= 0;
641 pPacket
->PktInfo
.AsRx
.ExpectedHdr
= lookAhead
;
642 pPacket
->ActualLength
= pHdr
->PayloadLen
+ HTC_HDR_LENGTH
;
644 if (pPacket
->ActualLength
> pPacket
->BufferLength
) {
645 AR_DEBUG_ASSERT(false);
650 /* we want synchronous operation */
651 pPacket
->Completion
= NULL
;
653 /* get the message from the device, this will block */
654 status
= HTCIssueRecv(target
, pPacket
);
660 /* process receive header */
661 status
= HTCProcessRecvHeader(target
,pPacket
,NULL
,NULL
);
663 pPacket
->Status
= status
;
666 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
667 ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
672 /* give the caller this control message packet, they are responsible to free */
673 *ppControlPacket
= pPacket
;
678 if (pPacket
!= NULL
) {
679 /* cleanup buffer on error */
680 HTC_FREE_CONTROL_RX(target
,pPacket
);
684 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HTCWaitforControlMessage \n"));
689 static int AllocAndPrepareRxPackets(HTC_TARGET
*target
,
690 A_UINT32 LookAheads
[],
692 HTC_ENDPOINT
*pEndpoint
,
693 HTC_PACKET_QUEUE
*pQueue
)
703 /* lock RX while we assemble the packet buffers */
706 for (i
= 0; i
< Messages
; i
++) {
708 pHdr
= (HTC_FRAME_HDR
*)&LookAheads
[i
];
710 if (pHdr
->EndpointID
>= ENDPOINT_MAX
) {
711 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Invalid Endpoint in look-ahead: %d \n",pHdr
->EndpointID
));
712 /* invalid endpoint */
717 if (pHdr
->EndpointID
!= pEndpoint
->Id
) {
718 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Invalid Endpoint in look-ahead: %d should be : %d (index:%d)\n",
719 pHdr
->EndpointID
, pEndpoint
->Id
, i
));
720 /* invalid endpoint */
725 if (pHdr
->PayloadLen
> HTC_MAX_PAYLOAD_LENGTH
) {
726 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Payload length %d exceeds max HTC : %d !\n",
727 pHdr
->PayloadLen
, (A_UINT32
)HTC_MAX_PAYLOAD_LENGTH
));
732 if (0 == pEndpoint
->ServiceID
) {
733 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("Endpoint %d is not connected !\n",pHdr
->EndpointID
));
734 /* endpoint isn't even connected */
739 if ((pHdr
->Flags
& HTC_FLAGS_RECV_BUNDLE_CNT_MASK
) == 0) {
740 /* HTC header only indicates 1 message to fetch */
743 /* HTC header indicates that every packet to follow has the same padded length so that it can
744 * be optimally fetched as a full bundle */
745 numMessages
= (pHdr
->Flags
& HTC_FLAGS_RECV_BUNDLE_CNT_MASK
) >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT
;
746 /* the count doesn't include the starter frame, just a count of frames to follow */
748 A_ASSERT(numMessages
<= target
->MaxMsgPerBundle
);
749 INC_HTC_EP_STAT(pEndpoint
, RxBundleIndFromHdr
, 1);
750 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
751 ("HTC header indicates :%d messages can be fetched as a bundle \n",numMessages
));
754 fullLength
= DEV_CALC_RECV_PADDED_LEN(&target
->Device
,pHdr
->PayloadLen
+ sizeof(HTC_FRAME_HDR
));
756 /* get packet buffers for each message, if there was a bundle detected in the header,
757 * use pHdr as a template to fetch all packets in the bundle */
758 for (j
= 0; j
< numMessages
; j
++) {
760 /* reset flag, any packets allocated using the RecvAlloc() API cannot be recycled on cleanup,
761 * they must be explicitly returned */
764 if (pEndpoint
->EpCallBacks
.EpRecvAlloc
!= NULL
) {
765 UNLOCK_HTC_RX(target
);
767 /* user is using a per-packet allocation callback */
768 pPacket
= pEndpoint
->EpCallBacks
.EpRecvAlloc(pEndpoint
->EpCallBacks
.pContext
,
773 } else if ((pEndpoint
->EpCallBacks
.EpRecvAllocThresh
!= NULL
) &&
774 (fullLength
> pEndpoint
->EpCallBacks
.RecvAllocThreshold
)) {
775 INC_HTC_EP_STAT(pEndpoint
,RxAllocThreshHit
,1);
776 INC_HTC_EP_STAT(pEndpoint
,RxAllocThreshBytes
,pHdr
->PayloadLen
);
777 /* threshold was hit, call the special recv allocation callback */
778 UNLOCK_HTC_RX(target
);
780 /* user wants to allocate packets above a certain threshold */
781 pPacket
= pEndpoint
->EpCallBacks
.EpRecvAllocThresh(pEndpoint
->EpCallBacks
.pContext
,
787 /* user is using a refill handler that can refill multiple HTC buffers */
789 /* get a packet from the endpoint recv queue */
790 pPacket
= HTC_PACKET_DEQUEUE(&pEndpoint
->RxBuffers
);
792 if (NULL
== pPacket
) {
793 /* check for refill handler */
794 if (pEndpoint
->EpCallBacks
.EpRecvRefill
!= NULL
) {
795 UNLOCK_HTC_RX(target
);
796 /* call the re-fill handler */
797 pEndpoint
->EpCallBacks
.EpRecvRefill(pEndpoint
->EpCallBacks
.pContext
,
800 /* check if we have more buffers */
801 pPacket
= HTC_PACKET_DEQUEUE(&pEndpoint
->RxBuffers
);
807 if (NULL
== pPacket
) {
808 /* this is not an error, we simply need to mark that we are waiting for buffers.*/
809 target
->RecvStateFlags
|= HTC_RECV_WAIT_BUFFERS
;
810 target
->EpWaitingForBuffers
= pEndpoint
->Id
;
811 status
= A_NO_RESOURCE
;
815 AR_DEBUG_ASSERT(pPacket
->Endpoint
== pEndpoint
->Id
);
817 pPacket
->PktInfo
.AsRx
.HTCRxFlags
= 0;
818 pPacket
->PktInfo
.AsRx
.IndicationFlags
= 0;
819 pPacket
->Status
= A_OK
;
822 /* flag that these packets cannot be recycled, they have to be returned to the
824 pPacket
->PktInfo
.AsRx
.HTCRxFlags
|= HTC_RX_PKT_NO_RECYCLE
;
826 /* add packet to queue (also incase we need to cleanup down below) */
827 HTC_PACKET_ENQUEUE(pQueue
,pPacket
);
829 if (HTC_STOPPING(target
)) {
830 status
= A_ECANCELED
;
834 /* make sure this message can fit in the endpoint buffer */
835 if ((A_UINT32
)fullLength
> pPacket
->BufferLength
) {
836 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
837 ("Payload Length Error : header reports payload of: %d (%d) endpoint buffer size: %d \n",
838 pHdr
->PayloadLen
, fullLength
, pPacket
->BufferLength
));
844 /* for messages fetched in a bundle the expected lookahead is unknown since we
845 * are only using the lookahead of the first packet as a template of what to
846 * expect for lengths */
847 /* flag that once we get the real HTC header we need to refesh the information */
848 pPacket
->PktInfo
.AsRx
.HTCRxFlags
|= HTC_RX_PKT_REFRESH_HDR
;
849 /* set it to something invalid */
850 pPacket
->PktInfo
.AsRx
.ExpectedHdr
= 0xFFFFFFFF;
853 pPacket
->PktInfo
.AsRx
.ExpectedHdr
= LookAheads
[i
]; /* set expected look ahead */
855 /* set the amount of data to fetch */
856 pPacket
->ActualLength
= pHdr
->PayloadLen
+ HTC_HDR_LENGTH
;
860 if (A_NO_RESOURCE
== status
) {
861 /* this is actually okay */
869 UNLOCK_HTC_RX(target
);
872 while (!HTC_QUEUE_EMPTY(pQueue
)) {
873 pPacket
= HTC_PACKET_DEQUEUE(pQueue
);
874 /* recycle all allocated packets */
875 HTC_RECYCLE_RX_PKT(target
,pPacket
,&target
->EndPoint
[pPacket
->Endpoint
]);
882 static void HTCAsyncRecvScatterCompletion(HIF_SCATTER_REQ
*pScatterReq
)
886 HTC_ENDPOINT
*pEndpoint
;
887 A_UINT32 lookAheads
[HTC_HOST_MAX_MSG_PER_BUNDLE
];
888 int numLookAheads
= 0;
889 HTC_TARGET
*target
= (HTC_TARGET
*)pScatterReq
->Context
;
891 bool partialBundle
= false;
892 HTC_PACKET_QUEUE localRecvQueue
;
893 bool procError
= false;
895 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HTCAsyncRecvScatterCompletion TotLen: %d Entries: %d\n",
896 pScatterReq
->TotalLength
, pScatterReq
->ValidScatterEntries
));
898 A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target
->Device
));
900 if (pScatterReq
->CompletionStatus
) {
901 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("** Recv Scatter Request Failed: %d \n",pScatterReq
->CompletionStatus
));
904 if (pScatterReq
->CallerFlags
& HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE
) {
905 partialBundle
= true;
908 DEV_FINISH_SCATTER_OPERATION(pScatterReq
);
910 INIT_HTC_PACKET_QUEUE(&localRecvQueue
);
912 pPacket
= (HTC_PACKET
*)pScatterReq
->ScatterList
[0].pCallerContexts
[0];
913 /* note: all packets in a scatter req are for the same endpoint ! */
914 pEndpoint
= &target
->EndPoint
[pPacket
->Endpoint
];
916 /* walk through the scatter list and process */
917 /* **** NOTE: DO NOT HOLD ANY LOCKS here, HTCProcessRecvHeader can take the TX lock
918 * as it processes credit reports */
919 for (i
= 0; i
< pScatterReq
->ValidScatterEntries
; i
++) {
920 pPacket
= (HTC_PACKET
*)pScatterReq
->ScatterList
[i
].pCallerContexts
[0];
921 A_ASSERT(pPacket
!= NULL
);
922 /* reset count, we are only interested in the look ahead in the last packet when we
923 * break out of this loop */
926 if (!pScatterReq
->CompletionStatus
) {
927 /* process header for each of the recv packets */
928 status
= HTCProcessRecvHeader(target
,pPacket
,lookAheads
,&numLookAheads
);
934 #ifdef HTC_EP_STAT_PROFILING
936 HTC_RX_STAT_PROFILE(target
,pEndpoint
,numLookAheads
);
937 INC_HTC_EP_STAT(pEndpoint
, RxPacketsBundled
, 1);
938 UNLOCK_HTC_RX(target
);
940 if (i
== (pScatterReq
->ValidScatterEntries
- 1)) {
941 /* last packet's more packets flag is set based on the lookahead */
942 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads
,numLookAheads
,pEndpoint
,pPacket
);
944 /* packets in a bundle automatically have this flag set */
945 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket
);
948 DUMP_RECV_PKT_INFO(pPacket
);
949 /* since we can't hold a lock in this loop, we insert into our local recv queue for
950 * storage until we can transfer them to the recv completion queue */
951 HTC_PACKET_ENQUEUE(&localRecvQueue
,pPacket
);
954 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,(" Recv packet scatter entry %d failed (out of %d) \n",
955 i
, pScatterReq
->ValidScatterEntries
));
956 /* recycle failed recv */
957 HTC_RECYCLE_RX_PKT(target
, pPacket
, pEndpoint
);
958 /* set flag and continue processing the remaining scatter entries */
964 /* free scatter request */
965 DEV_FREE_SCATTER_REQ(&target
->Device
,pScatterReq
);
968 /* transfer the packets in the local recv queue to the recv completion queue */
969 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint
->RecvIndicationQueue
, &localRecvQueue
);
971 UNLOCK_HTC_RX(target
);
974 /* pipeline the next check (asynchronously) for more packets */
975 HTCAsyncRecvCheckMorePackets(target
,
978 partialBundle
? false : true);
981 /* now drain the indication queue */
982 DrainRecvIndicationQueue(target
,pEndpoint
);
984 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HTCAsyncRecvScatterCompletion \n"));
987 static int HTCIssueRecvPacketBundle(HTC_TARGET
*target
,
988 HTC_PACKET_QUEUE
*pRecvPktQueue
,
989 HTC_PACKET_QUEUE
*pSyncCompletionQueue
,
990 int *pNumPacketsFetched
,
994 HIF_SCATTER_REQ
*pScatterReq
;
998 bool asyncMode
= (pSyncCompletionQueue
== NULL
) ? true : false;
999 int scatterSpaceRemaining
= DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target
->Device
);
1001 pktsToScatter
= HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue
);
1002 pktsToScatter
= min(pktsToScatter
, target
->MaxMsgPerBundle
);
1004 if ((HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue
) - pktsToScatter
) > 0) {
1005 /* we were forced to split this bundle receive operation
1006 * all packets in this partial bundle must have their lookaheads ignored */
1007 PartialBundle
= true;
1008 /* this would only happen if the target ignored our max bundle limit */
1009 AR_DEBUG_PRINTF(ATH_DEBUG_WARN
,
1010 ("HTCIssueRecvPacketBundle : partial bundle detected num:%d , %d \n",
1011 HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue
), pktsToScatter
));
1016 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HTCIssueRecvPacketBundle (Numpackets: %d , actual : %d) \n",
1017 HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue
), pktsToScatter
));
1021 pScatterReq
= DEV_ALLOC_SCATTER_REQ(&target
->Device
);
1023 if (pScatterReq
== NULL
) {
1024 /* no scatter resources left, just let caller handle it the legacy way */
1028 pScatterReq
->CallerFlags
= 0;
1030 if (PartialBundle
) {
1031 /* mark that this is a partial bundle, this has special ramifications to the
1032 * scatter completion routine */
1033 pScatterReq
->CallerFlags
|= HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE
;
1036 /* convert HTC packets to scatter list */
1037 for (i
= 0; i
< pktsToScatter
; i
++) {
1040 pPacket
= HTC_PACKET_DEQUEUE(pRecvPktQueue
);
1041 A_ASSERT(pPacket
!= NULL
);
1043 paddedLength
= DEV_CALC_RECV_PADDED_LEN(&target
->Device
, pPacket
->ActualLength
);
1045 if ((scatterSpaceRemaining
- paddedLength
) < 0) {
1046 /* exceeds what we can transfer, put the packet back */
1047 HTC_PACKET_ENQUEUE_TO_HEAD(pRecvPktQueue
,pPacket
);
1051 scatterSpaceRemaining
-= paddedLength
;
1053 if (PartialBundle
|| (i
< (pktsToScatter
- 1))) {
1054 /* packet 0..n-1 cannot be checked for look-aheads since we are fetching a bundle
1055 * the last packet however can have it's lookahead used */
1056 pPacket
->PktInfo
.AsRx
.HTCRxFlags
|= HTC_RX_PKT_IGNORE_LOOKAHEAD
;
1059 /* note: 1 HTC packet per scatter entry */
1060 /* setup packet into */
1061 pScatterReq
->ScatterList
[i
].pBuffer
= pPacket
->pBuffer
;
1062 pScatterReq
->ScatterList
[i
].Length
= paddedLength
;
1064 pPacket
->PktInfo
.AsRx
.HTCRxFlags
|= HTC_RX_PKT_PART_OF_BUNDLE
;
1067 /* save HTC packet for async completion routine */
1068 pScatterReq
->ScatterList
[i
].pCallerContexts
[0] = pPacket
;
1070 /* queue to caller's sync completion queue, caller will unload this when we return */
1071 HTC_PACKET_ENQUEUE(pSyncCompletionQueue
,pPacket
);
1074 A_ASSERT(pScatterReq
->ScatterList
[i
].Length
);
1075 totalLength
+= pScatterReq
->ScatterList
[i
].Length
;
1078 pScatterReq
->TotalLength
= totalLength
;
1079 pScatterReq
->ValidScatterEntries
= i
;
1082 pScatterReq
->CompletionRoutine
= HTCAsyncRecvScatterCompletion
;
1083 pScatterReq
->Context
= target
;
1086 status
= DevSubmitScatterRequest(&target
->Device
, pScatterReq
, DEV_SCATTER_READ
, asyncMode
);
1089 *pNumPacketsFetched
= i
;
1093 /* free scatter request */
1094 DEV_FREE_SCATTER_REQ(&target
->Device
, pScatterReq
);
1099 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HTCIssueRecvPacketBundle (status:%d) (fetched:%d) \n",
1100 status
,*pNumPacketsFetched
));
1105 static INLINE
void CheckRecvWaterMark(HTC_ENDPOINT
*pEndpoint
)
1107 /* see if endpoint is using a refill watermark
1108 * ** no need to use a lock here, since we are only inspecting...
1109 * caller may must not hold locks when calling this function */
1110 if (pEndpoint
->EpCallBacks
.RecvRefillWaterMark
> 0) {
1111 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint
->RxBuffers
) < pEndpoint
->EpCallBacks
.RecvRefillWaterMark
) {
1112 /* call the re-fill handler before we continue */
1113 pEndpoint
->EpCallBacks
.EpRecvRefill(pEndpoint
->EpCallBacks
.pContext
,
1119 /* callback when device layer or lookahead report parsing detects a pending message */
1120 int HTCRecvMessagePendingHandler(void *Context
, A_UINT32 MsgLookAheads
[], int NumLookAheads
, bool *pAsyncProc
, int *pNumPktsFetched
)
1122 HTC_TARGET
*target
= (HTC_TARGET
*)Context
;
1124 HTC_PACKET
*pPacket
;
1125 HTC_ENDPOINT
*pEndpoint
;
1126 bool asyncProc
= false;
1127 A_UINT32 lookAheads
[HTC_HOST_MAX_MSG_PER_BUNDLE
];
1129 HTC_PACKET_QUEUE recvPktQueue
, syncCompletedPktsQueue
;
1132 int totalFetched
= 0;
1134 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("+HTCRecvMessagePendingHandler NumLookAheads: %d \n",NumLookAheads
));
1136 if (pNumPktsFetched
!= NULL
) {
1137 *pNumPktsFetched
= 0;
1140 if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target
->Device
)) {
1141 /* We use async mode to get the packets if the device layer supports it.
1142 * The device layer interfaces with HIF in which HIF may have restrictions on
1143 * how interrupts are processed */
1147 if (pAsyncProc
!= NULL
) {
1148 /* indicate to caller how we decided to process this */
1149 *pAsyncProc
= asyncProc
;
1152 if (NumLookAheads
> HTC_HOST_MAX_MSG_PER_BUNDLE
) {
1157 /* on first entry copy the lookaheads into our temp array for processing */
1158 A_MEMCPY(lookAheads
, MsgLookAheads
, (sizeof(A_UINT32
)) * NumLookAheads
);
1162 /* reset packets queues */
1163 INIT_HTC_PACKET_QUEUE(&recvPktQueue
);
1164 INIT_HTC_PACKET_QUEUE(&syncCompletedPktsQueue
);
1166 if (NumLookAheads
> HTC_HOST_MAX_MSG_PER_BUNDLE
) {
1172 /* first lookahead sets the expected endpoint IDs for all packets in a bundle */
1173 id
= ((HTC_FRAME_HDR
*)&lookAheads
[0])->EndpointID
;
1174 pEndpoint
= &target
->EndPoint
[id
];
1176 if (id
>= ENDPOINT_MAX
) {
1177 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,("MsgPend, Invalid Endpoint in look-ahead: %d \n",id
));
1182 /* try to allocate as many HTC RX packets indicated by the lookaheads
1183 * these packets are stored in the recvPkt queue */
1184 status
= AllocAndPrepareRxPackets(target
,
1193 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue
) >= 2) {
1194 /* a recv bundle was detected, force IRQ status re-check again */
1195 REF_IRQ_STATUS_RECHECK(&target
->Device
);
1198 totalFetched
+= HTC_PACKET_QUEUE_DEPTH(&recvPktQueue
);
1200 /* we've got packet buffers for all we can currently fetch,
1201 * this count is not valid anymore */
1203 partialBundle
= false;
1205 /* now go fetch the list of HTC packets */
1206 while (!HTC_QUEUE_EMPTY(&recvPktQueue
)) {
1210 if (target
->RecvBundlingEnabled
&& (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue
) > 1)) {
1211 /* there are enough packets to attempt a bundle transfer and recv bundling is allowed */
1212 status
= HTCIssueRecvPacketBundle(target
,
1214 asyncProc
? NULL
: &syncCompletedPktsQueue
,
1221 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue
) != 0) {
1222 /* we couldn't fetch all packets at one time, this creates a broken
1224 partialBundle
= true;
1228 /* see if the previous operation fetched any packets using bundling */
1229 if (0 == pktsFetched
) {
1230 /* dequeue one packet */
1231 pPacket
= HTC_PACKET_DEQUEUE(&recvPktQueue
);
1232 A_ASSERT(pPacket
!= NULL
);
1235 /* we use async mode to get the packet if the device layer supports it
1236 * set our callback and context */
1237 pPacket
->Completion
= HTCRecvCompleteHandler
;
1238 pPacket
->pContext
= target
;
1240 /* fully synchronous */
1241 pPacket
->Completion
= NULL
;
1244 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue
) > 0) {
1245 /* lookaheads in all packets except the last one in the bundle must be ignored */
1246 pPacket
->PktInfo
.AsRx
.HTCRxFlags
|= HTC_RX_PKT_IGNORE_LOOKAHEAD
;
1249 /* go fetch the packet */
1250 status
= HTCIssueRecv(target
, pPacket
);
1256 /* sent synchronously, queue this packet for synchronous completion */
1257 HTC_PACKET_ENQUEUE(&syncCompletedPktsQueue
,pPacket
);
1265 CheckRecvWaterMark(pEndpoint
);
1269 /* we did this asynchronously so we can get out of the loop, the asynch processing
1270 * creates a chain of requests to continue processing pending messages in the
1271 * context of callbacks */
1275 /* synchronous handling */
1276 if (target
->Device
.DSRCanYield
) {
1277 /* for the SYNC case, increment count that tracks when the DSR should yield */
1278 target
->Device
.CurrentDSRRecvCount
++;
1281 /* in the sync case, all packet buffers are now filled,
1282 * we can process each packet, check lookaheads and then repeat */
1284 /* unload sync completion queue */
1285 while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue
)) {
1286 HTC_PACKET_QUEUE container
;
1288 pPacket
= HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue
);
1289 A_ASSERT(pPacket
!= NULL
);
1291 pEndpoint
= &target
->EndPoint
[pPacket
->Endpoint
];
1292 /* reset count on each iteration, we are only interested in the last packet's lookahead
1293 * information when we break out of this loop */
1295 /* process header for each of the recv packets
1296 * note: the lookahead of the last packet is useful for us to continue in this loop */
1297 status
= HTCProcessRecvHeader(target
,pPacket
,lookAheads
,&NumLookAheads
);
1302 if (HTC_QUEUE_EMPTY(&syncCompletedPktsQueue
)) {
1303 /* last packet's more packets flag is set based on the lookahead */
1304 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads
,NumLookAheads
,pEndpoint
,pPacket
);
1306 /* packets in a bundle automatically have this flag set */
1307 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket
);
1309 /* good packet, indicate it */
1310 HTC_RX_STAT_PROFILE(target
,pEndpoint
,NumLookAheads
);
1312 if (pPacket
->PktInfo
.AsRx
.HTCRxFlags
& HTC_RX_PKT_PART_OF_BUNDLE
) {
1313 INC_HTC_EP_STAT(pEndpoint
, RxPacketsBundled
, 1);
1316 INIT_HTC_PACKET_QUEUE_AND_ADD(&container
,pPacket
);
1317 DO_RCV_COMPLETION(pEndpoint
,&container
);
1324 if (NumLookAheads
== 0) {
1325 /* no more look aheads */
1329 /* when we process recv synchronously we need to check if we should yield and stop
1330 * fetching more packets indicated by the embedded lookaheads */
1331 if (target
->Device
.DSRCanYield
) {
1332 if (DEV_CHECK_RECV_YIELD(&target
->Device
)) {
1333 /* break out, don't fetch any more packets */
1339 /* check whether other OS contexts have queued any WMI command/data for WLAN.
1340 * This check is needed only if WLAN Tx and Rx happens in same thread context */
1343 /* for SYNCH processing, if we get here, we are running through the loop again due to a detected lookahead.
1344 * Set flag that we should re-check IRQ status registers again before leaving IRQ processing,
1345 * this can net better performance in high throughput situations */
1346 REF_IRQ_STATUS_RECHECK(&target
->Device
);
1350 AR_DEBUG_PRINTF(ATH_DEBUG_ERR
,
1351 ("Failed to get pending recv messages (%d) \n",status
));
1352 /* cleanup any packets we allocated but didn't use to actually fetch any packets */
1353 while (!HTC_QUEUE_EMPTY(&recvPktQueue
)) {
1354 pPacket
= HTC_PACKET_DEQUEUE(&recvPktQueue
);
1355 /* clean up packets */
1356 HTC_RECYCLE_RX_PKT(target
, pPacket
, &target
->EndPoint
[pPacket
->Endpoint
]);
1358 /* cleanup any packets in sync completion queue */
1359 while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue
)) {
1360 pPacket
= HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue
);
1361 /* clean up packets */
1362 HTC_RECYCLE_RX_PKT(target
, pPacket
, &target
->EndPoint
[pPacket
->Endpoint
]);
1364 if (HTC_STOPPING(target
)) {
1365 AR_DEBUG_PRINTF(ATH_DEBUG_WARN
,
1366 (" Host is going to stop. blocking receiver for HTCStop.. \n"));
1367 DevStopRecv(&target
->Device
, asyncProc
? DEV_STOP_RECV_ASYNC
: DEV_STOP_RECV_SYNC
);
1370 /* before leaving, check to see if host ran out of buffers and needs to stop the
1372 if (target
->RecvStateFlags
& HTC_RECV_WAIT_BUFFERS
) {
1373 AR_DEBUG_PRINTF(ATH_DEBUG_WARN
,
1374 (" Host has no RX buffers, blocking receiver to prevent overrun.. \n"));
1375 /* try to stop receive at the device layer */
1376 DevStopRecv(&target
->Device
, asyncProc
? DEV_STOP_RECV_ASYNC
: DEV_STOP_RECV_SYNC
);
1379 if (pNumPktsFetched
!= NULL
) {
1380 *pNumPktsFetched
= totalFetched
;
1383 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("-HTCRecvMessagePendingHandler \n"));
1388 int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle
, HTC_PACKET_QUEUE
*pPktQueue
)
1390 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1391 HTC_ENDPOINT
*pEndpoint
;
1392 bool unblockRecv
= false;
1394 HTC_PACKET
*pFirstPacket
;
1396 pFirstPacket
= HTC_GET_PKT_AT_HEAD(pPktQueue
);
1398 if (NULL
== pFirstPacket
) {
1403 AR_DEBUG_ASSERT(pFirstPacket
->Endpoint
< ENDPOINT_MAX
);
1405 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,
1406 ("+- HTCAddReceivePktMultiple : endPointId: %d, cnt:%d, length: %d\n",
1407 pFirstPacket
->Endpoint
,
1408 HTC_PACKET_QUEUE_DEPTH(pPktQueue
),
1409 pFirstPacket
->BufferLength
));
1413 pEndpoint
= &target
->EndPoint
[pFirstPacket
->Endpoint
];
1415 LOCK_HTC_RX(target
);
1417 if (HTC_STOPPING(target
)) {
1418 HTC_PACKET
*pPacket
;
1420 UNLOCK_HTC_RX(target
);
1422 /* walk through queue and mark each one canceled */
1423 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue
,pPacket
) {
1424 pPacket
->Status
= A_ECANCELED
;
1425 } HTC_PACKET_QUEUE_ITERATE_END
;
1427 DO_RCV_COMPLETION(pEndpoint
,pPktQueue
);
1431 /* store receive packets */
1432 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint
->RxBuffers
, pPktQueue
);
1434 /* check if we are blocked waiting for a new buffer */
1435 if (target
->RecvStateFlags
& HTC_RECV_WAIT_BUFFERS
) {
1436 if (target
->EpWaitingForBuffers
== pFirstPacket
->Endpoint
) {
1437 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,(" receiver was blocked on ep:%d, unblocking.. \n",
1438 target
->EpWaitingForBuffers
));
1439 target
->RecvStateFlags
&= ~HTC_RECV_WAIT_BUFFERS
;
1440 target
->EpWaitingForBuffers
= ENDPOINT_MAX
;
1445 UNLOCK_HTC_RX(target
);
1447 if (unblockRecv
&& !HTC_STOPPING(target
)) {
1448 /* TODO : implement a buffer threshold count? */
1449 DevEnableRecv(&target
->Device
,DEV_ENABLE_RECV_SYNC
);
1457 /* Makes a buffer available to the HTC module */
1458 int HTCAddReceivePkt(HTC_HANDLE HTCHandle
, HTC_PACKET
*pPacket
)
1460 HTC_PACKET_QUEUE queue
;
1461 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue
,pPacket
);
1462 return HTCAddReceivePktMultiple(HTCHandle
, &queue
);
1465 void HTCUnblockRecv(HTC_HANDLE HTCHandle
)
1467 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1468 bool unblockRecv
= false;
1470 LOCK_HTC_RX(target
);
1472 /* check if we are blocked waiting for a new buffer */
1473 if (target
->RecvStateFlags
& HTC_RECV_WAIT_BUFFERS
) {
1474 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
,("HTCUnblockRx : receiver was blocked on ep:%d, unblocking.. \n",
1475 target
->EpWaitingForBuffers
));
1476 target
->RecvStateFlags
&= ~HTC_RECV_WAIT_BUFFERS
;
1477 target
->EpWaitingForBuffers
= ENDPOINT_MAX
;
1481 UNLOCK_HTC_RX(target
);
1483 if (unblockRecv
&& !HTC_STOPPING(target
)) {
1485 DevEnableRecv(&target
->Device
,DEV_ENABLE_RECV_ASYNC
);
1489 static void HTCFlushRxQueue(HTC_TARGET
*target
, HTC_ENDPOINT
*pEndpoint
, HTC_PACKET_QUEUE
*pQueue
)
1491 HTC_PACKET
*pPacket
;
1492 HTC_PACKET_QUEUE container
;
1494 LOCK_HTC_RX(target
);
1497 pPacket
= HTC_PACKET_DEQUEUE(pQueue
);
1498 if (NULL
== pPacket
) {
1501 UNLOCK_HTC_RX(target
);
1502 pPacket
->Status
= A_ECANCELED
;
1503 pPacket
->ActualLength
= 0;
1504 AR_DEBUG_PRINTF(ATH_DEBUG_RECV
, (" Flushing RX packet:0x%lX, length:%d, ep:%d \n",
1505 (unsigned long)pPacket
, pPacket
->BufferLength
, pPacket
->Endpoint
));
1506 INIT_HTC_PACKET_QUEUE_AND_ADD(&container
,pPacket
);
1507 /* give the packet back */
1508 DO_RCV_COMPLETION(pEndpoint
,&container
);
1509 LOCK_HTC_RX(target
);
1512 UNLOCK_HTC_RX(target
);
1515 static void HTCFlushEndpointRX(HTC_TARGET
*target
, HTC_ENDPOINT
*pEndpoint
)
1517 /* flush any recv indications not already made */
1518 HTCFlushRxQueue(target
,pEndpoint
,&pEndpoint
->RecvIndicationQueue
);
1519 /* flush any rx buffers */
1520 HTCFlushRxQueue(target
,pEndpoint
,&pEndpoint
->RxBuffers
);
1523 void HTCFlushRecvBuffers(HTC_TARGET
*target
)
1525 HTC_ENDPOINT
*pEndpoint
;
1528 for (i
= ENDPOINT_0
; i
< ENDPOINT_MAX
; i
++) {
1529 pEndpoint
= &target
->EndPoint
[i
];
1530 if (pEndpoint
->ServiceID
== 0) {
1534 HTCFlushEndpointRX(target
,pEndpoint
);
1539 void HTCEnableRecv(HTC_HANDLE HTCHandle
)
1541 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1543 if (!HTC_STOPPING(target
)) {
1545 DevEnableRecv(&target
->Device
,DEV_ENABLE_RECV_SYNC
);
1549 void HTCDisableRecv(HTC_HANDLE HTCHandle
)
1551 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1553 if (!HTC_STOPPING(target
)) {
1555 DevStopRecv(&target
->Device
,DEV_ENABLE_RECV_SYNC
);
1559 int HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle
,
1560 HTC_ENDPOINT_ID Endpoint
)
1562 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1563 return HTC_PACKET_QUEUE_DEPTH(&(target
->EndPoint
[Endpoint
].RxBuffers
));
1566 int HTCWaitForPendingRecv(HTC_HANDLE HTCHandle
,
1567 A_UINT32 TimeoutInMs
,
1568 bool *pbIsRecvPending
)
1571 HTC_TARGET
*target
= GET_HTC_TARGET_FROM_HANDLE(HTCHandle
);
1573 status
= DevWaitForPendingRecv(&target
->Device
,