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 #define HTC_RX_STAT_PROFILE(t,ep,numLookAheads) \
41 INC_HTC_EP_STAT((ep), RxReceived, 1); \
42 if ((numLookAheads) == 1) { \
43 INC_HTC_EP_STAT((ep), RxLookAheads, 1); \
44 } else if ((numLookAheads) > 1) { \
45 INC_HTC_EP_STAT((ep), RxBundleLookAheads, 1); \
49 static void DoRecvCompletion(struct htc_endpoint *pEndpoint,
50 struct htc_packet_queue *pQueueToIndicate)
55 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
56 /* nothing to indicate */
60 if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) {
61 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d, recv multiple callback (%d pkts) \n",
62 pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
63 /* a recv multiple handler is being used, pass the queue to the handler */
64 pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->EpCallBacks.pContext,
66 INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
68 struct htc_packet *pPacket;
69 /* using legacy EpRecv */
71 pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
72 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d recv callback on packet 0x%lX \n", \
73 pEndpoint->Id, (unsigned long)(pPacket)));
74 pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket);
75 } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
82 static INLINE int HTCProcessTrailer(struct htc_target *target,
87 HTC_ENDPOINT_ID FromEndpoint)
89 HTC_RECORD_HDR *pRecord;
91 HTC_LOOKAHEAD_REPORT *pLookAhead;
96 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
98 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
99 AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
102 pOrigBuffer = pBuffer;
108 if (Length < sizeof(HTC_RECORD_HDR)) {
112 /* these are byte aligned structs */
113 pRecord = (HTC_RECORD_HDR *)pBuffer;
114 Length -= sizeof(HTC_RECORD_HDR);
115 pBuffer += sizeof(HTC_RECORD_HDR);
117 if (pRecord->Length > Length) {
118 /* no room left in buffer for record */
119 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
120 (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
121 pRecord->Length, pRecord->RecordID, Length));
125 /* start of record follows the header */
126 pRecordBuf = pBuffer;
128 switch (pRecord->RecordID) {
129 case HTC_RECORD_CREDITS:
130 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
131 HTCProcessCreditRpt(target,
132 (HTC_CREDIT_REPORT *)pRecordBuf,
133 pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
136 case HTC_RECORD_LOOKAHEAD:
137 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
138 pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
139 if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
140 (pNextLookAheads != NULL)) {
142 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
143 (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
144 pLookAhead->PreValid,
145 pLookAhead->PostValid));
147 /* look ahead bytes are valid, copy them over */
148 ((u8 *)(&pNextLookAheads[0]))[0] = pLookAhead->LookAhead[0];
149 ((u8 *)(&pNextLookAheads[0]))[1] = pLookAhead->LookAhead[1];
150 ((u8 *)(&pNextLookAheads[0]))[2] = pLookAhead->LookAhead[2];
151 ((u8 *)(&pNextLookAheads[0]))[3] = pLookAhead->LookAhead[3];
153 #ifdef ATH_DEBUG_MODULE
154 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
155 DebugDumpBytes((u8 *)pNextLookAheads,4,"Next Look Ahead");
158 /* just one normal lookahead */
162 case HTC_RECORD_LOOKAHEAD_BUNDLE:
163 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
164 if (pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT) &&
165 (pNextLookAheads != NULL)) {
166 HTC_BUNDLED_LOOKAHEAD_REPORT *pBundledLookAheadRpt;
169 pBundledLookAheadRpt = (HTC_BUNDLED_LOOKAHEAD_REPORT *)pRecordBuf;
171 #ifdef ATH_DEBUG_MODULE
172 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
173 DebugDumpBytes(pRecordBuf,pRecord->Length,"Bundle LookAhead");
177 if ((pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))) >
178 HTC_HOST_MAX_MSG_PER_BUNDLE) {
179 /* this should never happen, the target restricts the number
180 * of messages per bundle configured by the host */
186 for (i = 0; i < (int)(pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))); i++) {
187 ((u8 *)(&pNextLookAheads[i]))[0] = pBundledLookAheadRpt->LookAhead[0];
188 ((u8 *)(&pNextLookAheads[i]))[1] = pBundledLookAheadRpt->LookAhead[1];
189 ((u8 *)(&pNextLookAheads[i]))[2] = pBundledLookAheadRpt->LookAhead[2];
190 ((u8 *)(&pNextLookAheads[i]))[3] = pBundledLookAheadRpt->LookAhead[3];
191 pBundledLookAheadRpt++;
198 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
199 pRecord->RecordID, pRecord->Length));
207 /* advance buffer past this record for next time around */
208 pBuffer += pRecord->Length;
209 Length -= pRecord->Length;
212 #ifdef ATH_DEBUG_MODULE
214 DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
218 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
223 /* process a received message (i.e. strip off header, process any trailer data)
224 * note : locks must be released when this function is called */
225 static int HTCProcessRecvHeader(struct htc_target *target,
226 struct htc_packet *pPacket,
227 u32 *pNextLookAheads,
236 pBuf = pPacket->pBuffer;
238 if (pNumLookAheads != NULL) {
242 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
244 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
245 AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
249 /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
250 * retrieve 16 bit fields */
251 payloadLen = A_GET_UINT16_FIELD(pBuf, struct htc_frame_hdr, PayloadLen);
253 ((u8 *)&lookAhead)[0] = pBuf[0];
254 ((u8 *)&lookAhead)[1] = pBuf[1];
255 ((u8 *)&lookAhead)[2] = pBuf[2];
256 ((u8 *)&lookAhead)[3] = pBuf[3];
258 if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
259 /* refresh expected hdr, since this was unknown at the time we grabbed the packets
260 * as part of a bundle */
261 pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
262 /* refresh actual length since we now have the real header */
263 pPacket->ActualLength = payloadLen + HTC_HDR_LENGTH;
265 /* validate the actual header that was refreshed */
266 if (pPacket->ActualLength > pPacket->BufferLength) {
267 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
268 ("Refreshed HDR payload length (%d) in bundled RECV is invalid (hdr: 0x%X) \n",
269 payloadLen, lookAhead));
270 /* limit this to max buffer just to print out some of the buffer */
271 pPacket->ActualLength = min(pPacket->ActualLength, pPacket->BufferLength);
276 if (pPacket->Endpoint != A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID)) {
277 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
278 ("Refreshed HDR endpoint (%d) does not match expected endpoint (%d) \n",
279 A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID), pPacket->Endpoint));
285 if (lookAhead != pPacket->PktInfo.AsRx.ExpectedHdr) {
286 /* somehow the lookahead that gave us the full read length did not
287 * reflect the actual header in the pending message */
288 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
289 ("HTCProcessRecvHeader, lookahead mismatch! (pPkt:0x%lX flags:0x%X) \n",
290 (unsigned long)pPacket, pPacket->PktInfo.AsRx.HTCRxFlags));
291 #ifdef ATH_DEBUG_MODULE
292 DebugDumpBytes((u8 *)&pPacket->PktInfo.AsRx.ExpectedHdr,4,"Expected Message LookAhead");
293 DebugDumpBytes(pBuf,sizeof(struct htc_frame_hdr),"Current Frame Header");
294 #ifdef HTC_CAPTURE_LAST_FRAME
295 DebugDumpBytes((u8 *)&target->LastFrameHdr,sizeof(struct htc_frame_hdr),"Last Frame Header");
296 if (target->LastTrailerLength != 0) {
297 DebugDumpBytes(target->LastTrailer,
298 target->LastTrailerLength,
308 temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, Flags);
310 if (temp & HTC_FLAGS_RECV_TRAILER) {
311 /* this packet has a trailer */
313 /* extract the trailer length in control byte 0 */
314 temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, ControlBytes[0]);
316 if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
317 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
318 ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
324 if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
325 /* this packet was fetched as part of an HTC bundle, the embedded lookahead is
326 * not valid since the next packet may have already been fetched as part of the
328 pNextLookAheads = NULL;
329 pNumLookAheads = NULL;
332 /* process trailer data that follows HDR + application payload */
333 status = HTCProcessTrailer(target,
334 (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
344 #ifdef HTC_CAPTURE_LAST_FRAME
345 memcpy(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
346 target->LastTrailerLength = temp;
348 /* trim length by trailer bytes */
349 pPacket->ActualLength -= temp;
351 #ifdef HTC_CAPTURE_LAST_FRAME
353 target->LastTrailerLength = 0;
357 /* if we get to this point, the packet is good */
358 /* remove header and adjust length */
359 pPacket->pBuffer += HTC_HDR_LENGTH;
360 pPacket->ActualLength -= HTC_HDR_LENGTH;
365 /* dump the whole packet */
366 #ifdef ATH_DEBUG_MODULE
367 DebugDumpBytes(pBuf,pPacket->ActualLength < 256 ? pPacket->ActualLength : 256 ,"BAD HTC Recv PKT");
370 #ifdef HTC_CAPTURE_LAST_FRAME
371 memcpy(&target->LastFrameHdr,pBuf,sizeof(struct htc_frame_hdr));
373 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
374 if (pPacket->ActualLength > 0) {
375 AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
380 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
384 static INLINE void HTCAsyncRecvCheckMorePackets(struct htc_target *target,
385 u32 NextLookAheads[],
389 /* was there a lookahead for the next packet? */
390 if (NumLookAheads > 0) {
393 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
394 ("HTCAsyncRecvCheckMorePackets - num lookaheads were non-zero : %d \n",
396 /* force status re-check */
397 REF_IRQ_STATUS_RECHECK(&target->Device);
398 /* we have more packets, get the next packet fetch started */
399 nextStatus = HTCRecvMessagePendingHandler(target, NextLookAheads, NumLookAheads, NULL, &fetched);
400 if (A_EPROTO == nextStatus) {
401 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
402 ("Next look ahead from recv header was INVALID\n"));
403 #ifdef ATH_DEBUG_MODULE
404 DebugDumpBytes((u8 *)NextLookAheads,
405 NumLookAheads * (sizeof(u32)),
406 "BAD lookaheads from lookahead report");
409 if (!nextStatus && !fetched) {
410 /* we could not fetch any more packets due to resources */
411 DevAsyncIrqProcessComplete(&target->Device);
415 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
416 ("HTCAsyncRecvCheckMorePackets - rechecking for more messages...\n"));
417 /* if we did not get anything on the look-ahead,
418 * call device layer to asynchronously re-check for messages. If we can keep the async
419 * processing going we get better performance. If there is a pending message we will keep processing
420 * messages asynchronously which should pipeline things nicely */
421 DevCheckPendingRecvMsgsAsync(&target->Device);
423 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCAsyncRecvCheckMorePackets - no check \n"));
430 /* unload the recv completion queue */
431 static INLINE void DrainRecvIndicationQueue(struct htc_target *target, struct htc_endpoint *pEndpoint)
433 struct htc_packet_queue recvCompletions;
435 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+DrainRecvIndicationQueue \n"));
437 INIT_HTC_PACKET_QUEUE(&recvCompletions);
441 /* increment rx processing count on entry */
442 pEndpoint->RxProcessCount++;
443 if (pEndpoint->RxProcessCount > 1) {
444 pEndpoint->RxProcessCount--;
445 /* another thread or task is draining the RX completion queue on this endpoint
446 * that thread will reset the rx processing count when the queue is drained */
447 UNLOCK_HTC_RX(target);
451 /******* at this point only 1 thread may enter ******/
455 /* transfer items from main recv queue to the local one so we can release the lock */
456 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&recvCompletions, &pEndpoint->RecvIndicationQueue);
458 if (HTC_QUEUE_EMPTY(&recvCompletions)) {
463 /* release lock while we do the recv completions
464 * other threads can now queue more recv completions */
465 UNLOCK_HTC_RX(target);
467 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
468 ("DrainRecvIndicationQueue : completing %d RECV packets \n",
469 HTC_PACKET_QUEUE_DEPTH(&recvCompletions)));
471 DO_RCV_COMPLETION(pEndpoint,&recvCompletions);
473 /* re-acquire lock to grab some more completions */
478 pEndpoint->RxProcessCount = 0;
479 UNLOCK_HTC_RX(target);
481 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-DrainRecvIndicationQueue \n"));
485 /* optimization for recv packets, we can indicate a "hint" that there are more
486 * single-packets to fetch on this endpoint */
487 #define SET_MORE_RX_PACKET_INDICATION_FLAG(L,N,E,P) \
488 if ((N) > 0) { SetRxPacketIndicationFlags((L)[0],(E),(P)); }
490 /* for bundled frames, we can force the flag to indicate there are more packets */
491 #define FORCE_MORE_RX_PACKET_INDICATION_FLAG(P) \
492 (P)->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS;
494 /* note: this function can be called with the RX lock held */
495 static INLINE void SetRxPacketIndicationFlags(u32 LookAhead,
496 struct htc_endpoint *pEndpoint,
497 struct htc_packet *pPacket)
499 struct htc_frame_hdr *pHdr = (struct htc_frame_hdr *)&LookAhead;
500 /* check to see if the "next" packet is from the same endpoint of the
502 if (pHdr->EndpointID == pPacket->Endpoint) {
503 /* check that there is a buffer available to actually fetch it */
504 if (!HTC_QUEUE_EMPTY(&pEndpoint->RxBuffers)) {
505 /* provide a hint that there are more RX packets to fetch */
506 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
512 /* asynchronous completion handler for recv packet fetching, when the device layer
513 * completes a read request, it will call this completion handler */
514 void HTCRecvCompleteHandler(void *Context, struct htc_packet *pPacket)
516 struct htc_target *target = (struct htc_target *)Context;
517 struct htc_endpoint *pEndpoint;
518 u32 nextLookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
519 int numLookAheads = 0;
521 bool checkMorePkts = true;
523 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (pkt:0x%lX, status:%d, ep:%d) \n",
524 (unsigned long)pPacket, pPacket->Status, pPacket->Endpoint));
526 A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
527 AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
528 pEndpoint = &target->EndPoint[pPacket->Endpoint];
529 pPacket->Completion = NULL;
531 /* get completion status */
532 status = pPacket->Status;
537 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
538 pPacket->Status, pPacket->Endpoint));
541 /* process the header for any trailer data */
542 status = HTCProcessRecvHeader(target,pPacket,nextLookAheads,&numLookAheads);
548 if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
549 /* this packet was part of a bundle that had to be broken up.
550 * It was fetched one message at a time. There may be other asynchronous reads queued behind this one.
551 * Do no issue another check for more packets since the last one in the series of requests
553 checkMorePkts = false;
556 DUMP_RECV_PKT_INFO(pPacket);
558 SET_MORE_RX_PACKET_INDICATION_FLAG(nextLookAheads,numLookAheads,pEndpoint,pPacket);
559 /* we have a good packet, queue it to the completion queue */
560 HTC_PACKET_ENQUEUE(&pEndpoint->RecvIndicationQueue,pPacket);
561 HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
562 UNLOCK_HTC_RX(target);
564 /* check for more recv packets before indicating */
565 HTCAsyncRecvCheckMorePackets(target,nextLookAheads,numLookAheads,checkMorePkts);
570 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
571 ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
573 /* recycle this packet */
574 HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
576 /* a good packet was queued, drain the queue */
577 DrainRecvIndicationQueue(target,pEndpoint);
580 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
583 /* synchronously wait for a control message from the target,
584 * This function is used at initialization time ONLY. At init messages
585 * on ENDPOINT 0 are expected. */
586 int HTCWaitforControlMessage(struct htc_target *target, struct htc_packet **ppControlPacket)
590 struct htc_packet *pPacket = NULL;
591 struct htc_frame_hdr *pHdr;
593 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
597 *ppControlPacket = NULL;
599 /* call the polling function to see if we have a message */
600 status = DevPollMboxMsgRecv(&target->Device,
602 HTC_TARGET_RESPONSE_TIMEOUT);
608 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
609 ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
611 /* check the lookahead */
612 pHdr = (struct htc_frame_hdr *)&lookAhead;
614 if (pHdr->EndpointID != ENDPOINT_0) {
615 /* unexpected endpoint number, should be zero */
616 AR_DEBUG_ASSERT(false);
623 AR_DEBUG_ASSERT(false);
628 pPacket = HTC_ALLOC_CONTROL_RX(target);
630 if (pPacket == NULL) {
631 AR_DEBUG_ASSERT(false);
632 status = A_NO_MEMORY;
636 pPacket->PktInfo.AsRx.HTCRxFlags = 0;
637 pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
638 pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
640 if (pPacket->ActualLength > pPacket->BufferLength) {
641 AR_DEBUG_ASSERT(false);
646 /* we want synchronous operation */
647 pPacket->Completion = NULL;
649 /* get the message from the device, this will block */
650 status = HTCIssueRecv(target, pPacket);
656 /* process receive header */
657 status = HTCProcessRecvHeader(target,pPacket,NULL,NULL);
659 pPacket->Status = status;
662 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
663 ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
668 /* give the caller this control message packet, they are responsible to free */
669 *ppControlPacket = pPacket;
674 if (pPacket != NULL) {
675 /* cleanup buffer on error */
676 HTC_FREE_CONTROL_RX(target,pPacket);
680 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
685 static int AllocAndPrepareRxPackets(struct htc_target *target,
688 struct htc_endpoint *pEndpoint,
689 struct htc_packet_queue *pQueue)
692 struct htc_packet *pPacket;
693 struct htc_frame_hdr *pHdr;
699 /* lock RX while we assemble the packet buffers */
702 for (i = 0; i < Messages; i++) {
704 pHdr = (struct htc_frame_hdr *)&LookAheads[i];
706 if (pHdr->EndpointID >= ENDPOINT_MAX) {
707 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
708 /* invalid endpoint */
713 if (pHdr->EndpointID != pEndpoint->Id) {
714 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d should be : %d (index:%d)\n",
715 pHdr->EndpointID, pEndpoint->Id, i));
716 /* invalid endpoint */
721 if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
722 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
723 pHdr->PayloadLen, (u32)HTC_MAX_PAYLOAD_LENGTH));
728 if (0 == pEndpoint->ServiceID) {
729 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
730 /* endpoint isn't even connected */
735 if ((pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
736 /* HTC header only indicates 1 message to fetch */
739 /* HTC header indicates that every packet to follow has the same padded length so that it can
740 * be optimally fetched as a full bundle */
741 numMessages = (pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT;
742 /* the count doesn't include the starter frame, just a count of frames to follow */
744 A_ASSERT(numMessages <= target->MaxMsgPerBundle);
745 INC_HTC_EP_STAT(pEndpoint, RxBundleIndFromHdr, 1);
746 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
747 ("HTC header indicates :%d messages can be fetched as a bundle \n",numMessages));
750 fullLength = DEV_CALC_RECV_PADDED_LEN(&target->Device,pHdr->PayloadLen + sizeof(struct htc_frame_hdr));
752 /* get packet buffers for each message, if there was a bundle detected in the header,
753 * use pHdr as a template to fetch all packets in the bundle */
754 for (j = 0; j < numMessages; j++) {
756 /* reset flag, any packets allocated using the RecvAlloc() API cannot be recycled on cleanup,
757 * they must be explicitly returned */
760 if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) {
761 UNLOCK_HTC_RX(target);
763 /* user is using a per-packet allocation callback */
764 pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext,
769 } else if ((pEndpoint->EpCallBacks.EpRecvAllocThresh != NULL) &&
770 (fullLength > pEndpoint->EpCallBacks.RecvAllocThreshold)) {
771 INC_HTC_EP_STAT(pEndpoint,RxAllocThreshHit,1);
772 INC_HTC_EP_STAT(pEndpoint,RxAllocThreshBytes,pHdr->PayloadLen);
773 /* threshold was hit, call the special recv allocation callback */
774 UNLOCK_HTC_RX(target);
776 /* user wants to allocate packets above a certain threshold */
777 pPacket = pEndpoint->EpCallBacks.EpRecvAllocThresh(pEndpoint->EpCallBacks.pContext,
783 /* user is using a refill handler that can refill multiple HTC buffers */
785 /* get a packet from the endpoint recv queue */
786 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
788 if (NULL == pPacket) {
789 /* check for refill handler */
790 if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
791 UNLOCK_HTC_RX(target);
792 /* call the re-fill handler */
793 pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
796 /* check if we have more buffers */
797 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
803 if (NULL == pPacket) {
804 /* this is not an error, we simply need to mark that we are waiting for buffers.*/
805 target->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
806 target->EpWaitingForBuffers = pEndpoint->Id;
807 status = A_NO_RESOURCE;
811 AR_DEBUG_ASSERT(pPacket->Endpoint == pEndpoint->Id);
813 pPacket->PktInfo.AsRx.HTCRxFlags = 0;
814 pPacket->PktInfo.AsRx.IndicationFlags = 0;
818 /* flag that these packets cannot be recycled, they have to be returned to the
820 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_NO_RECYCLE;
822 /* add packet to queue (also incase we need to cleanup down below) */
823 HTC_PACKET_ENQUEUE(pQueue,pPacket);
825 if (HTC_STOPPING(target)) {
826 status = A_ECANCELED;
830 /* make sure this message can fit in the endpoint buffer */
831 if ((u32)fullLength > pPacket->BufferLength) {
832 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
833 ("Payload Length Error : header reports payload of: %d (%d) endpoint buffer size: %d \n",
834 pHdr->PayloadLen, fullLength, pPacket->BufferLength));
840 /* for messages fetched in a bundle the expected lookahead is unknown since we
841 * are only using the lookahead of the first packet as a template of what to
842 * expect for lengths */
843 /* flag that once we get the real HTC header we need to refesh the information */
844 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_REFRESH_HDR;
845 /* set it to something invalid */
846 pPacket->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
849 pPacket->PktInfo.AsRx.ExpectedHdr = LookAheads[i]; /* set expected look ahead */
851 /* set the amount of data to fetch */
852 pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
856 if (A_NO_RESOURCE == status) {
857 /* this is actually okay */
865 UNLOCK_HTC_RX(target);
868 while (!HTC_QUEUE_EMPTY(pQueue)) {
869 pPacket = HTC_PACKET_DEQUEUE(pQueue);
870 /* recycle all allocated packets */
871 HTC_RECYCLE_RX_PKT(target,pPacket,&target->EndPoint[pPacket->Endpoint]);
878 static void HTCAsyncRecvScatterCompletion(struct hif_scatter_req *pScatterReq)
881 struct htc_packet *pPacket;
882 struct htc_endpoint *pEndpoint;
883 u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
884 int numLookAheads = 0;
885 struct htc_target *target = (struct htc_target *)pScatterReq->Context;
887 bool partialBundle = false;
888 struct htc_packet_queue localRecvQueue;
889 bool procError = false;
891 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCAsyncRecvScatterCompletion TotLen: %d Entries: %d\n",
892 pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
894 A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
896 if (pScatterReq->CompletionStatus) {
897 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Recv Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
900 if (pScatterReq->CallerFlags & HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE) {
901 partialBundle = true;
904 DEV_FINISH_SCATTER_OPERATION(pScatterReq);
906 INIT_HTC_PACKET_QUEUE(&localRecvQueue);
908 pPacket = (struct htc_packet *)pScatterReq->ScatterList[0].pCallerContexts[0];
909 /* note: all packets in a scatter req are for the same endpoint ! */
910 pEndpoint = &target->EndPoint[pPacket->Endpoint];
912 /* walk through the scatter list and process */
913 /* **** NOTE: DO NOT HOLD ANY LOCKS here, HTCProcessRecvHeader can take the TX lock
914 * as it processes credit reports */
915 for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
916 pPacket = (struct htc_packet *)pScatterReq->ScatterList[i].pCallerContexts[0];
917 A_ASSERT(pPacket != NULL);
918 /* reset count, we are only interested in the look ahead in the last packet when we
919 * break out of this loop */
922 if (!pScatterReq->CompletionStatus) {
923 /* process header for each of the recv packets */
924 status = HTCProcessRecvHeader(target,pPacket,lookAheads,&numLookAheads);
931 HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
932 INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
933 UNLOCK_HTC_RX(target);
934 if (i == (pScatterReq->ValidScatterEntries - 1)) {
935 /* last packet's more packets flag is set based on the lookahead */
936 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,numLookAheads,pEndpoint,pPacket);
938 /* packets in a bundle automatically have this flag set */
939 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
942 DUMP_RECV_PKT_INFO(pPacket);
943 /* since we can't hold a lock in this loop, we insert into our local recv queue for
944 * storage until we can transfer them to the recv completion queue */
945 HTC_PACKET_ENQUEUE(&localRecvQueue,pPacket);
948 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Recv packet scatter entry %d failed (out of %d) \n",
949 i, pScatterReq->ValidScatterEntries));
950 /* recycle failed recv */
951 HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
952 /* set flag and continue processing the remaining scatter entries */
958 /* free scatter request */
959 DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
962 /* transfer the packets in the local recv queue to the recv completion queue */
963 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RecvIndicationQueue, &localRecvQueue);
965 UNLOCK_HTC_RX(target);
968 /* pipeline the next check (asynchronously) for more packets */
969 HTCAsyncRecvCheckMorePackets(target,
972 partialBundle ? false : true);
975 /* now drain the indication queue */
976 DrainRecvIndicationQueue(target,pEndpoint);
978 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCAsyncRecvScatterCompletion \n"));
981 static int HTCIssueRecvPacketBundle(struct htc_target *target,
982 struct htc_packet_queue *pRecvPktQueue,
983 struct htc_packet_queue *pSyncCompletionQueue,
984 int *pNumPacketsFetched,
988 struct hif_scatter_req *pScatterReq;
991 struct htc_packet *pPacket;
992 bool asyncMode = (pSyncCompletionQueue == NULL) ? true : false;
993 int scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device);
995 pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue);
996 pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
998 if ((HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue) - pktsToScatter) > 0) {
999 /* we were forced to split this bundle receive operation
1000 * all packets in this partial bundle must have their lookaheads ignored */
1001 PartialBundle = true;
1002 /* this would only happen if the target ignored our max bundle limit */
1003 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1004 ("HTCIssueRecvPacketBundle : partial bundle detected num:%d , %d \n",
1005 HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
1010 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCIssueRecvPacketBundle (Numpackets: %d , actual : %d) \n",
1011 HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
1015 pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device);
1017 if (pScatterReq == NULL) {
1018 /* no scatter resources left, just let caller handle it the legacy way */
1022 pScatterReq->CallerFlags = 0;
1024 if (PartialBundle) {
1025 /* mark that this is a partial bundle, this has special ramifications to the
1026 * scatter completion routine */
1027 pScatterReq->CallerFlags |= HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE;
1030 /* convert HTC packets to scatter list */
1031 for (i = 0; i < pktsToScatter; i++) {
1034 pPacket = HTC_PACKET_DEQUEUE(pRecvPktQueue);
1035 A_ASSERT(pPacket != NULL);
1037 paddedLength = DEV_CALC_RECV_PADDED_LEN(&target->Device, pPacket->ActualLength);
1039 if ((scatterSpaceRemaining - paddedLength) < 0) {
1040 /* exceeds what we can transfer, put the packet back */
1041 HTC_PACKET_ENQUEUE_TO_HEAD(pRecvPktQueue,pPacket);
1045 scatterSpaceRemaining -= paddedLength;
1047 if (PartialBundle || (i < (pktsToScatter - 1))) {
1048 /* packet 0..n-1 cannot be checked for look-aheads since we are fetching a bundle
1049 * the last packet however can have it's lookahead used */
1050 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
1053 /* note: 1 HTC packet per scatter entry */
1054 /* setup packet into */
1055 pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
1056 pScatterReq->ScatterList[i].Length = paddedLength;
1058 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE;
1061 /* save HTC packet for async completion routine */
1062 pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
1064 /* queue to caller's sync completion queue, caller will unload this when we return */
1065 HTC_PACKET_ENQUEUE(pSyncCompletionQueue,pPacket);
1068 A_ASSERT(pScatterReq->ScatterList[i].Length);
1069 totalLength += pScatterReq->ScatterList[i].Length;
1072 pScatterReq->TotalLength = totalLength;
1073 pScatterReq->ValidScatterEntries = i;
1076 pScatterReq->CompletionRoutine = HTCAsyncRecvScatterCompletion;
1077 pScatterReq->Context = target;
1080 status = DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_READ, asyncMode);
1083 *pNumPacketsFetched = i;
1087 /* free scatter request */
1088 DEV_FREE_SCATTER_REQ(&target->Device, pScatterReq);
1093 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCIssueRecvPacketBundle (status:%d) (fetched:%d) \n",
1094 status,*pNumPacketsFetched));
1099 static INLINE void CheckRecvWaterMark(struct htc_endpoint *pEndpoint)
1101 /* see if endpoint is using a refill watermark
1102 * ** no need to use a lock here, since we are only inspecting...
1103 * caller may must not hold locks when calling this function */
1104 if (pEndpoint->EpCallBacks.RecvRefillWaterMark > 0) {
1105 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBuffers) < pEndpoint->EpCallBacks.RecvRefillWaterMark) {
1106 /* call the re-fill handler before we continue */
1107 pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
1113 /* callback when device layer or lookahead report parsing detects a pending message */
1114 int HTCRecvMessagePendingHandler(void *Context, u32 MsgLookAheads[], int NumLookAheads, bool *pAsyncProc, int *pNumPktsFetched)
1116 struct htc_target *target = (struct htc_target *)Context;
1118 struct htc_packet *pPacket;
1119 struct htc_endpoint *pEndpoint;
1120 bool asyncProc = false;
1121 u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
1123 struct htc_packet_queue recvPktQueue, syncCompletedPktsQueue;
1126 int totalFetched = 0;
1128 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler NumLookAheads: %d \n",NumLookAheads));
1130 if (pNumPktsFetched != NULL) {
1131 *pNumPktsFetched = 0;
1134 if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
1135 /* We use async mode to get the packets if the device layer supports it.
1136 * The device layer interfaces with HIF in which HIF may have restrictions on
1137 * how interrupts are processed */
1141 if (pAsyncProc != NULL) {
1142 /* indicate to caller how we decided to process this */
1143 *pAsyncProc = asyncProc;
1146 if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1151 /* on first entry copy the lookaheads into our temp array for processing */
1152 memcpy(lookAheads, MsgLookAheads, (sizeof(u32)) * NumLookAheads);
1156 /* reset packets queues */
1157 INIT_HTC_PACKET_QUEUE(&recvPktQueue);
1158 INIT_HTC_PACKET_QUEUE(&syncCompletedPktsQueue);
1160 if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1166 /* first lookahead sets the expected endpoint IDs for all packets in a bundle */
1167 id = ((struct htc_frame_hdr *)&lookAheads[0])->EndpointID;
1168 pEndpoint = &target->EndPoint[id];
1170 if (id >= ENDPOINT_MAX) {
1171 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MsgPend, Invalid Endpoint in look-ahead: %d \n",id));
1176 /* try to allocate as many HTC RX packets indicated by the lookaheads
1177 * these packets are stored in the recvPkt queue */
1178 status = AllocAndPrepareRxPackets(target,
1187 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) >= 2) {
1188 /* a recv bundle was detected, force IRQ status re-check again */
1189 REF_IRQ_STATUS_RECHECK(&target->Device);
1192 totalFetched += HTC_PACKET_QUEUE_DEPTH(&recvPktQueue);
1194 /* we've got packet buffers for all we can currently fetch,
1195 * this count is not valid anymore */
1197 partialBundle = false;
1199 /* now go fetch the list of HTC packets */
1200 while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
1204 if (target->RecvBundlingEnabled && (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 1)) {
1205 /* there are enough packets to attempt a bundle transfer and recv bundling is allowed */
1206 status = HTCIssueRecvPacketBundle(target,
1208 asyncProc ? NULL : &syncCompletedPktsQueue,
1215 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) != 0) {
1216 /* we couldn't fetch all packets at one time, this creates a broken
1218 partialBundle = true;
1222 /* see if the previous operation fetched any packets using bundling */
1223 if (0 == pktsFetched) {
1224 /* dequeue one packet */
1225 pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
1226 A_ASSERT(pPacket != NULL);
1229 /* we use async mode to get the packet if the device layer supports it
1230 * set our callback and context */
1231 pPacket->Completion = HTCRecvCompleteHandler;
1232 pPacket->pContext = target;
1234 /* fully synchronous */
1235 pPacket->Completion = NULL;
1238 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 0) {
1239 /* lookaheads in all packets except the last one in the bundle must be ignored */
1240 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
1243 /* go fetch the packet */
1244 status = HTCIssueRecv(target, pPacket);
1250 /* sent synchronously, queue this packet for synchronous completion */
1251 HTC_PACKET_ENQUEUE(&syncCompletedPktsQueue,pPacket);
1259 CheckRecvWaterMark(pEndpoint);
1263 /* we did this asynchronously so we can get out of the loop, the asynch processing
1264 * creates a chain of requests to continue processing pending messages in the
1265 * context of callbacks */
1269 /* synchronous handling */
1270 if (target->Device.DSRCanYield) {
1271 /* for the SYNC case, increment count that tracks when the DSR should yield */
1272 target->Device.CurrentDSRRecvCount++;
1275 /* in the sync case, all packet buffers are now filled,
1276 * we can process each packet, check lookaheads and then repeat */
1278 /* unload sync completion queue */
1279 while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1280 struct htc_packet_queue container;
1282 pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
1283 A_ASSERT(pPacket != NULL);
1285 pEndpoint = &target->EndPoint[pPacket->Endpoint];
1286 /* reset count on each iteration, we are only interested in the last packet's lookahead
1287 * information when we break out of this loop */
1289 /* process header for each of the recv packets
1290 * note: the lookahead of the last packet is useful for us to continue in this loop */
1291 status = HTCProcessRecvHeader(target,pPacket,lookAheads,&NumLookAheads);
1296 if (HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1297 /* last packet's more packets flag is set based on the lookahead */
1298 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,NumLookAheads,pEndpoint,pPacket);
1300 /* packets in a bundle automatically have this flag set */
1301 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
1303 /* good packet, indicate it */
1304 HTC_RX_STAT_PROFILE(target,pEndpoint,NumLookAheads);
1306 if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_PART_OF_BUNDLE) {
1307 INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
1310 INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
1311 DO_RCV_COMPLETION(pEndpoint,&container);
1318 if (NumLookAheads == 0) {
1319 /* no more look aheads */
1323 /* when we process recv synchronously we need to check if we should yield and stop
1324 * fetching more packets indicated by the embedded lookaheads */
1325 if (target->Device.DSRCanYield) {
1326 if (DEV_CHECK_RECV_YIELD(&target->Device)) {
1327 /* break out, don't fetch any more packets */
1333 /* check whether other OS contexts have queued any WMI command/data for WLAN.
1334 * This check is needed only if WLAN Tx and Rx happens in same thread context */
1337 /* for SYNCH processing, if we get here, we are running through the loop again due to a detected lookahead.
1338 * Set flag that we should re-check IRQ status registers again before leaving IRQ processing,
1339 * this can net better performance in high throughput situations */
1340 REF_IRQ_STATUS_RECHECK(&target->Device);
1344 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1345 ("Failed to get pending recv messages (%d) \n",status));
1346 /* cleanup any packets we allocated but didn't use to actually fetch any packets */
1347 while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
1348 pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
1349 /* clean up packets */
1350 HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
1352 /* cleanup any packets in sync completion queue */
1353 while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1354 pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
1355 /* clean up packets */
1356 HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
1358 if (HTC_STOPPING(target)) {
1359 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1360 (" Host is going to stop. blocking receiver for HTCStop.. \n"));
1361 DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
1364 /* before leaving, check to see if host ran out of buffers and needs to stop the
1366 if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1367 AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1368 (" Host has no RX buffers, blocking receiver to prevent overrun.. \n"));
1369 /* try to stop receive at the device layer */
1370 DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
1373 if (pNumPktsFetched != NULL) {
1374 *pNumPktsFetched = totalFetched;
1377 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
1382 int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
1384 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1385 struct htc_endpoint *pEndpoint;
1386 bool unblockRecv = false;
1388 struct htc_packet *pFirstPacket;
1390 pFirstPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
1392 if (NULL == pFirstPacket) {
1397 AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
1399 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
1400 ("+- HTCAddReceivePktMultiple : endPointId: %d, cnt:%d, length: %d\n",
1401 pFirstPacket->Endpoint,
1402 HTC_PACKET_QUEUE_DEPTH(pPktQueue),
1403 pFirstPacket->BufferLength));
1407 pEndpoint = &target->EndPoint[pFirstPacket->Endpoint];
1409 LOCK_HTC_RX(target);
1411 if (HTC_STOPPING(target)) {
1412 struct htc_packet *pPacket;
1414 UNLOCK_HTC_RX(target);
1416 /* walk through queue and mark each one canceled */
1417 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
1418 pPacket->Status = A_ECANCELED;
1419 } HTC_PACKET_QUEUE_ITERATE_END;
1421 DO_RCV_COMPLETION(pEndpoint,pPktQueue);
1425 /* store receive packets */
1426 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBuffers, pPktQueue);
1428 /* check if we are blocked waiting for a new buffer */
1429 if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1430 if (target->EpWaitingForBuffers == pFirstPacket->Endpoint) {
1431 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
1432 target->EpWaitingForBuffers));
1433 target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
1434 target->EpWaitingForBuffers = ENDPOINT_MAX;
1439 UNLOCK_HTC_RX(target);
1441 if (unblockRecv && !HTC_STOPPING(target)) {
1442 /* TODO : implement a buffer threshold count? */
1443 DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1451 /* Makes a buffer available to the HTC module */
1452 int HTCAddReceivePkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
1454 struct htc_packet_queue queue;
1455 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
1456 return HTCAddReceivePktMultiple(HTCHandle, &queue);
1459 void HTCUnblockRecv(HTC_HANDLE HTCHandle)
1461 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1462 bool unblockRecv = false;
1464 LOCK_HTC_RX(target);
1466 /* check if we are blocked waiting for a new buffer */
1467 if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1468 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HTCUnblockRx : receiver was blocked on ep:%d, unblocking.. \n",
1469 target->EpWaitingForBuffers));
1470 target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
1471 target->EpWaitingForBuffers = ENDPOINT_MAX;
1475 UNLOCK_HTC_RX(target);
1477 if (unblockRecv && !HTC_STOPPING(target)) {
1479 DevEnableRecv(&target->Device,DEV_ENABLE_RECV_ASYNC);
1483 static void HTCFlushRxQueue(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet_queue *pQueue)
1485 struct htc_packet *pPacket;
1486 struct htc_packet_queue container;
1488 LOCK_HTC_RX(target);
1491 pPacket = HTC_PACKET_DEQUEUE(pQueue);
1492 if (NULL == pPacket) {
1495 UNLOCK_HTC_RX(target);
1496 pPacket->Status = A_ECANCELED;
1497 pPacket->ActualLength = 0;
1498 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%lX, length:%d, ep:%d \n",
1499 (unsigned long)pPacket, pPacket->BufferLength, pPacket->Endpoint));
1500 INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
1501 /* give the packet back */
1502 DO_RCV_COMPLETION(pEndpoint,&container);
1503 LOCK_HTC_RX(target);
1506 UNLOCK_HTC_RX(target);
1509 static void HTCFlushEndpointRX(struct htc_target *target, struct htc_endpoint *pEndpoint)
1511 /* flush any recv indications not already made */
1512 HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RecvIndicationQueue);
1513 /* flush any rx buffers */
1514 HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RxBuffers);
1517 void HTCFlushRecvBuffers(struct htc_target *target)
1519 struct htc_endpoint *pEndpoint;
1522 for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1523 pEndpoint = &target->EndPoint[i];
1524 if (pEndpoint->ServiceID == 0) {
1528 HTCFlushEndpointRX(target,pEndpoint);
1533 void HTCEnableRecv(HTC_HANDLE HTCHandle)
1535 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1537 if (!HTC_STOPPING(target)) {
1539 DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1543 void HTCDisableRecv(HTC_HANDLE HTCHandle)
1545 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1547 if (!HTC_STOPPING(target)) {
1549 DevStopRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1553 int HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle,
1554 HTC_ENDPOINT_ID Endpoint)
1556 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1557 return HTC_PACKET_QUEUE_DEPTH(&(target->EndPoint[Endpoint].RxBuffers));
1560 int HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,
1562 bool *pbIsRecvPending)
1565 struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1567 status = DevWaitForPendingRecv(&target->Device,