Merge branch 'sh-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / staging / ath6kl / htc2 / htc_recv.c
1 //------------------------------------------------------------------------------
2 // <copyright file="htc_recv.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 #define HTCIssueRecv(t, p) \
26     DevRecvPacket(&(t)->Device,  \
27                   (p),          \
28                   (p)->ActualLength)
29
30 #define DO_RCV_COMPLETION(e,q)  DoRecvCompletion(e,q)
31
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),                   \
35                         (pP)->ActualLength,                    \
36                         (pP)->PktInfo.AsRx.ExpectedHdr,        \
37                         (pP)->Endpoint))                         
38                         
39 #define HTC_RX_STAT_PROFILE(t,ep,numLookAheads)        \
40 {                                                      \
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);  \
46     }                                                  \
47 }
48
49 static void DoRecvCompletion(struct htc_endpoint     *pEndpoint,
50                              struct htc_packet_queue *pQueueToIndicate)
51 {           
52     
53     do {
54         
55         if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
56                 /* nothing to indicate */
57             break;    
58         }
59  
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,
65                                                      pQueueToIndicate);
66             INIT_HTC_PACKET_QUEUE(pQueueToIndicate);        
67         } else {
68             struct htc_packet *pPacket;  
69             /* using legacy EpRecv */         
70             do {
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));                                              
76         }
77         
78     } while (false);
79
80 }
81
82 static INLINE int HTCProcessTrailer(struct htc_target *target,
83                                          u8 *pBuffer,
84                                          int         Length,
85                                          u32 *pNextLookAheads,
86                                          int        *pNumLookAheads,
87                                          HTC_ENDPOINT_ID FromEndpoint)
88 {
89     HTC_RECORD_HDR          *pRecord;
90     u8 *pRecordBuf;
91     HTC_LOOKAHEAD_REPORT    *pLookAhead;
92     u8 *pOrigBuffer;
93     int                     origLength;
94     int                status;
95
96     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
97
98     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
99         AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
100     }
101
102     pOrigBuffer = pBuffer;
103     origLength = Length;
104     status = 0;
105     
106     while (Length > 0) {
107
108         if (Length < sizeof(HTC_RECORD_HDR)) {
109             status = A_EPROTO;
110             break;
111         }
112             /* these are byte aligned structs */
113         pRecord = (HTC_RECORD_HDR *)pBuffer;
114         Length -= sizeof(HTC_RECORD_HDR);
115         pBuffer += sizeof(HTC_RECORD_HDR);
116
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));
122             status = A_EPROTO;
123             break;
124         }
125             /* start of record follows the header */
126         pRecordBuf = pBuffer;
127
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)),
134                                     FromEndpoint);
135                 break;
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)) {
141
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));
146
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];
152
153 #ifdef ATH_DEBUG_MODULE
154                     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
155                         DebugDumpBytes((u8 *)pNextLookAheads,4,"Next Look Ahead");
156                     }
157 #endif
158                         /* just one normal lookahead */
159                     *pNumLookAheads = 1;
160                 }
161                 break;
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;
167                     int                             i;
168                     
169                     pBundledLookAheadRpt = (HTC_BUNDLED_LOOKAHEAD_REPORT *)pRecordBuf;
170                     
171 #ifdef ATH_DEBUG_MODULE
172                     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
173                         DebugDumpBytes(pRecordBuf,pRecord->Length,"Bundle LookAhead");
174                     }
175 #endif
176                     
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 */        
181                         A_ASSERT(false);
182                         status = A_EPROTO;
183                         break;        
184                     }
185                                          
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++;
192                     }
193                     
194                     *pNumLookAheads = i;
195                 }               
196                 break;
197             default:
198                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
199                         pRecord->RecordID, pRecord->Length));
200                 break;
201         }
202
203         if (status) {
204             break;
205         }
206
207             /* advance buffer past this record for next time around */
208         pBuffer += pRecord->Length;
209         Length -= pRecord->Length;
210     }
211
212 #ifdef ATH_DEBUG_MODULE
213     if (status) {
214         DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
215     }
216 #endif
217
218     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
219     return status;
220
221 }
222
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,
228                                      int        *pNumLookAheads)
229 {
230     u8 temp;
231     u8 *pBuf;
232     int  status = 0;
233     u16 payloadLen;
234     u32 lookAhead;
235
236     pBuf = pPacket->pBuffer;
237     
238     if (pNumLookAheads != NULL) {
239         *pNumLookAheads = 0;
240     }
241     
242     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
243
244     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
245         AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
246     }
247
248     do {
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);
252         
253         ((u8 *)&lookAhead)[0] = pBuf[0];
254         ((u8 *)&lookAhead)[1] = pBuf[1];
255         ((u8 *)&lookAhead)[2] = pBuf[2];
256         ((u8 *)&lookAhead)[3] = pBuf[3];
257
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;
264             
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);
272                 status = A_EPROTO;
273                 break;    
274             }
275             
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));
280                 status = A_EPROTO;
281                 break;      
282             }   
283         }
284                 
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,
299                                "Last trailer");
300             }
301 #endif
302 #endif
303             status = A_EPROTO;
304             break;
305         }
306
307             /* get flags */
308         temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, Flags);
309
310         if (temp & HTC_FLAGS_RECV_TRAILER) {
311             /* this packet has a trailer */
312
313                 /* extract the trailer length in control byte 0 */
314             temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, ControlBytes[0]);
315
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",
319                         payloadLen, temp));
320                 status = A_EPROTO;
321                 break;
322             }
323
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
327                      * bundle */
328                 pNextLookAheads = NULL;   
329                 pNumLookAheads = NULL;     
330             }
331             
332                 /* process trailer data that follows HDR + application payload */
333             status = HTCProcessTrailer(target,
334                                        (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
335                                        temp,
336                                        pNextLookAheads,
337                                        pNumLookAheads,
338                                        pPacket->Endpoint);
339
340             if (status) {
341                 break;
342             }
343
344 #ifdef HTC_CAPTURE_LAST_FRAME
345             memcpy(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
346             target->LastTrailerLength = temp;
347 #endif
348                 /* trim length by trailer bytes */
349             pPacket->ActualLength -= temp;
350         }
351 #ifdef HTC_CAPTURE_LAST_FRAME
352          else {
353             target->LastTrailerLength = 0;
354         }
355 #endif
356
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;
361
362     } while (false);
363
364     if (status) {
365             /* dump the whole packet */
366 #ifdef ATH_DEBUG_MODULE
367         DebugDumpBytes(pBuf,pPacket->ActualLength < 256 ? pPacket->ActualLength : 256 ,"BAD HTC Recv PKT");
368 #endif
369     } else {
370 #ifdef HTC_CAPTURE_LAST_FRAME
371         memcpy(&target->LastFrameHdr,pBuf,sizeof(struct htc_frame_hdr));
372 #endif
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");
376             }
377         }
378     }
379
380     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
381     return status;
382 }
383
384 static INLINE void HTCAsyncRecvCheckMorePackets(struct htc_target  *target, 
385                                                 u32 NextLookAheads[],
386                                                 int         NumLookAheads,
387                                                 bool      CheckMoreMsgs)
388 {
389         /* was there a lookahead for the next packet? */
390     if (NumLookAheads > 0) {
391         int nextStatus;
392         int      fetched = 0;
393         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
394                         ("HTCAsyncRecvCheckMorePackets - num lookaheads were non-zero : %d \n",
395                          NumLookAheads));
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");
407 #endif
408         }
409         if (!nextStatus && !fetched) {
410                 /* we could not fetch any more packets due to resources */
411             DevAsyncIrqProcessComplete(&target->Device);        
412         }
413     } else {
414         if (CheckMoreMsgs) {
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);
422         } else {
423             AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCAsyncRecvCheckMorePackets - no check \n"));    
424         }
425     }
426     
427      
428 }      
429
430     /* unload the recv completion queue */
431 static INLINE void DrainRecvIndicationQueue(struct htc_target *target, struct htc_endpoint *pEndpoint)
432 {
433     struct htc_packet_queue     recvCompletions;
434     
435     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+DrainRecvIndicationQueue \n"));
436                 
437     INIT_HTC_PACKET_QUEUE(&recvCompletions);
438     
439     LOCK_HTC_RX(target);
440     
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);
448          return;
449     }
450     
451     /******* at this point only 1 thread may enter ******/
452      
453     while (true) {
454                 
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);
457             
458         if (HTC_QUEUE_EMPTY(&recvCompletions)) {
459                 /* all drained */
460             break;    
461         }
462         
463             /* release lock while we do the recv completions 
464              * other threads can now queue more recv completions */
465         UNLOCK_HTC_RX(target);
466         
467         AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 
468                 ("DrainRecvIndicationQueue : completing %d RECV packets \n",
469                                         HTC_PACKET_QUEUE_DEPTH(&recvCompletions)));
470             /* do completion */
471         DO_RCV_COMPLETION(pEndpoint,&recvCompletions);     
472               
473             /* re-acquire lock to grab some more completions */
474         LOCK_HTC_RX(target);    
475     }
476     
477         /* reset count */
478     pEndpoint->RxProcessCount = 0;       
479     UNLOCK_HTC_RX(target);
480     
481     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-DrainRecvIndicationQueue \n"));
482   
483 }
484
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)); }
489
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; 
493    
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)
498 {
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
501            completing packet */
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);        
507         }             
508     }                  
509 }
510
511      
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)
515 {
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;
520     int        status;
521     bool          checkMorePkts = true;
522
523     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (pkt:0x%lX, status:%d, ep:%d) \n",
524                 (unsigned long)pPacket, pPacket->Status, pPacket->Endpoint));
525
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;
530
531         /* get completion status */
532     status = pPacket->Status;
533
534     do {
535         
536         if (status) {
537             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
538                 pPacket->Status, pPacket->Endpoint));
539             break;
540         }
541             /* process the header for any trailer data */
542         status = HTCProcessRecvHeader(target,pPacket,nextLookAheads,&numLookAheads);
543
544         if (status) {
545             break;
546         }
547         
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
552                  * will handle it */
553             checkMorePkts = false;
554         }
555           
556         DUMP_RECV_PKT_INFO(pPacket);    
557         LOCK_HTC_RX(target);
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);     
563        
564             /* check for more recv packets before indicating */
565         HTCAsyncRecvCheckMorePackets(target,nextLookAheads,numLookAheads,checkMorePkts);
566
567     } while (false);
568
569     if (status) {
570          AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
571                          ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
572                          status));
573             /* recycle this packet */
574         HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
575     } else {
576             /* a good packet was queued, drain the queue */
577         DrainRecvIndicationQueue(target,pEndpoint);     
578     }
579
580     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
581 }
582
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)
587 {
588     int        status;
589     u32 lookAhead;
590     struct htc_packet      *pPacket = NULL;
591     struct htc_frame_hdr   *pHdr;
592
593     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
594
595     do  {
596
597         *ppControlPacket = NULL;
598
599             /* call the polling function to see if we have a message */
600         status = DevPollMboxMsgRecv(&target->Device,
601                                     &lookAhead,
602                                     HTC_TARGET_RESPONSE_TIMEOUT);
603
604         if (status) {
605             break;
606         }
607
608         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
609                 ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
610
611             /* check the lookahead */
612         pHdr = (struct htc_frame_hdr *)&lookAhead;
613
614         if (pHdr->EndpointID != ENDPOINT_0) {
615                 /* unexpected endpoint number, should be zero */
616             AR_DEBUG_ASSERT(false);
617             status = A_EPROTO;
618             break;
619         }
620
621         if (status) {
622                 /* bad message */
623             AR_DEBUG_ASSERT(false);
624             status = A_EPROTO;
625             break;
626         }
627
628         pPacket = HTC_ALLOC_CONTROL_RX(target);
629
630         if (pPacket == NULL) {
631             AR_DEBUG_ASSERT(false);
632             status = A_NO_MEMORY;
633             break;
634         }
635         
636         pPacket->PktInfo.AsRx.HTCRxFlags = 0;
637         pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
638         pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
639
640         if (pPacket->ActualLength > pPacket->BufferLength) {
641             AR_DEBUG_ASSERT(false);
642             status = A_EPROTO;
643             break;
644         }
645
646             /* we want synchronous operation */
647         pPacket->Completion = NULL;
648
649             /* get the message from the device, this will block */
650         status = HTCIssueRecv(target, pPacket);
651
652         if (status) {
653             break;
654         }
655
656             /* process receive header */
657         status = HTCProcessRecvHeader(target,pPacket,NULL,NULL);
658
659         pPacket->Status = status;
660
661         if (status) {
662             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
663                     ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
664                      status));
665             break;
666         }
667
668             /* give the caller this control message packet, they are responsible to free */
669         *ppControlPacket = pPacket;
670
671     } while (false);
672
673     if (status) {
674         if (pPacket != NULL) {
675                 /* cleanup buffer on error */
676             HTC_FREE_CONTROL_RX(target,pPacket);
677         }
678     }
679
680     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
681
682     return status;
683 }
684
685 static int AllocAndPrepareRxPackets(struct htc_target       *target,
686                                          u32 LookAheads[],
687                                          int              Messages,                                        
688                                          struct htc_endpoint     *pEndpoint, 
689                                          struct htc_packet_queue *pQueue)
690 {
691     int         status = 0;
692     struct htc_packet      *pPacket;
693     struct htc_frame_hdr   *pHdr;
694     int              i,j;
695     int              numMessages;
696     int              fullLength;
697     bool           noRecycle;
698             
699         /* lock RX while we assemble the packet buffers */
700     LOCK_HTC_RX(target);
701                         
702     for (i = 0; i < Messages; i++) {   
703          
704         pHdr = (struct htc_frame_hdr *)&LookAheads[i];
705
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 */
709             status = A_EPROTO;
710             break;
711         }
712
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 */
717             status = A_EPROTO;
718             break;    
719         }    
720        
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));
724             status = A_EPROTO;
725             break;
726         }
727
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 */
731             status = A_EPROTO;
732             break;
733         }
734
735         if ((pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
736                 /* HTC header only indicates 1 message to fetch */
737             numMessages = 1;
738         } else {
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 */
743             numMessages++;
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));           
748         }
749      
750         fullLength = DEV_CALC_RECV_PADDED_LEN(&target->Device,pHdr->PayloadLen + sizeof(struct htc_frame_hdr));
751             
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++) {  
755             
756                 /* reset flag, any packets allocated using the RecvAlloc() API cannot be recycled on cleanup,
757                  * they must be explicitly returned */
758             noRecycle = false;
759                                                                                    
760             if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) {
761                 UNLOCK_HTC_RX(target);
762                 noRecycle = true;
763                     /* user is using a per-packet allocation callback */
764                 pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext,
765                                                              pEndpoint->Id,
766                                                              fullLength);
767                 LOCK_HTC_RX(target);
768     
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);
775                 noRecycle = true;
776                     /* user wants to allocate packets above a certain threshold */
777                 pPacket = pEndpoint->EpCallBacks.EpRecvAllocThresh(pEndpoint->EpCallBacks.pContext,
778                                                                    pEndpoint->Id,
779                                                                    fullLength);
780                 LOCK_HTC_RX(target);        
781                         
782             } else {
783                     /* user is using a refill handler that can refill multiple HTC buffers */
784                     
785                     /* get a packet from the endpoint recv queue */
786                 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
787     
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,
794                                                             pEndpoint->Id);
795                         LOCK_HTC_RX(target);
796                             /* check if we have more buffers */
797                         pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
798                             /* fall through */
799                     }
800                 }
801             }
802     
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;
808                 break;
809             }
810                              
811             AR_DEBUG_ASSERT(pPacket->Endpoint == pEndpoint->Id);
812                 /* clear flags */
813             pPacket->PktInfo.AsRx.HTCRxFlags = 0;
814             pPacket->PktInfo.AsRx.IndicationFlags = 0;
815             pPacket->Status = 0;
816             
817             if (noRecycle) {
818                     /* flag that these packets cannot be recycled, they have to be returned to the 
819                      * user */
820                 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_NO_RECYCLE; 
821             }
822                 /* add packet to queue (also incase we need to cleanup down below)  */
823             HTC_PACKET_ENQUEUE(pQueue,pPacket);
824             
825             if (HTC_STOPPING(target)) {
826                 status = A_ECANCELED;
827                 break;
828             }
829     
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));
835                 status = A_EPROTO;
836                 break;
837             }
838             
839             if (j > 0) {
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;    
847             } else {
848             
849                 pPacket->PktInfo.AsRx.ExpectedHdr = LookAheads[i]; /* set expected look ahead */
850             }
851                 /* set the amount of data to fetch */
852             pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
853         }
854         
855         if (status) {
856             if (A_NO_RESOURCE == status) {
857                     /* this is actually okay */
858                 status = 0;
859             }
860             break;    
861         }
862                 
863     }
864     
865     UNLOCK_HTC_RX(target);
866     
867     if (status) {
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]);
872         }        
873     }
874         
875     return status; 
876 }
877
878 static void HTCAsyncRecvScatterCompletion(struct hif_scatter_req *pScatterReq)
879 {
880     int                 i;    
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;
886     int            status;
887     bool              partialBundle = false;
888     struct htc_packet_queue    localRecvQueue;
889     bool              procError = false;
890            
891     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCAsyncRecvScatterCompletion  TotLen: %d  Entries: %d\n",
892         pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
893     
894     A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
895            
896     if (pScatterReq->CompletionStatus) {
897         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Recv Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));            
898     }
899     
900     if (pScatterReq->CallerFlags & HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE) {
901         partialBundle = true;
902     }
903     
904     DEV_FINISH_SCATTER_OPERATION(pScatterReq);
905     
906     INIT_HTC_PACKET_QUEUE(&localRecvQueue);
907         
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];
911          
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 */
920         numLookAheads = 0;
921         
922         if (!pScatterReq->CompletionStatus) {
923                 /* process header for each of the recv packets */            
924             status = HTCProcessRecvHeader(target,pPacket,lookAheads,&numLookAheads);
925         } else {
926             status = A_ERROR;    
927         }
928         
929         if (!status) {
930             LOCK_HTC_RX(target);              
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);
937             } else {
938                     /* packets in a bundle automatically have this flag set */
939                 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
940             }
941              
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);
946             
947         } else {
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 */
953             procError = true;
954         }   
955     
956     }
957   
958         /* free scatter request */
959     DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
960    
961     LOCK_HTC_RX(target);   
962         /* transfer the packets in the local recv queue to the recv completion queue */
963     HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RecvIndicationQueue, &localRecvQueue);  
964     
965     UNLOCK_HTC_RX(target);
966     
967     if (!procError) {  
968             /* pipeline the next check (asynchronously) for more packets */           
969         HTCAsyncRecvCheckMorePackets(target,
970                                      lookAheads,
971                                      numLookAheads,
972                                      partialBundle ? false : true);
973     }
974     
975         /* now drain the indication queue */
976     DrainRecvIndicationQueue(target,pEndpoint);
977           
978     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCAsyncRecvScatterCompletion \n"));
979 }
980
981 static int HTCIssueRecvPacketBundle(struct htc_target        *target,
982                                          struct htc_packet_queue  *pRecvPktQueue, 
983                                          struct htc_packet_queue  *pSyncCompletionQueue,
984                                          int               *pNumPacketsFetched,
985                                          bool             PartialBundle)
986 {
987     int        status = 0;
988     struct hif_scatter_req *pScatterReq;
989     int             i, totalLength;
990     int             pktsToScatter;
991     struct htc_packet      *pPacket;
992     bool          asyncMode = (pSyncCompletionQueue == NULL) ? true : false;
993     int             scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device);
994         
995     pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue);
996     pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
997         
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));       
1006     }
1007     
1008     totalLength = 0;
1009
1010     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCIssueRecvPacketBundle (Numpackets: %d , actual : %d) \n", 
1011         HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
1012     
1013     do {
1014         
1015         pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device); 
1016         
1017         if (pScatterReq == NULL) {
1018                 /* no scatter resources left, just let caller handle it the legacy way */
1019             break;    
1020         }        
1021     
1022         pScatterReq->CallerFlags = 0;
1023              
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;
1028         }
1029                    
1030             /* convert HTC packets to scatter list */                   
1031         for (i = 0; i < pktsToScatter; i++) {
1032             int paddedLength;
1033             
1034             pPacket = HTC_PACKET_DEQUEUE(pRecvPktQueue);
1035             A_ASSERT(pPacket != NULL);
1036             
1037             paddedLength = DEV_CALC_RECV_PADDED_LEN(&target->Device, pPacket->ActualLength);
1038      
1039             if ((scatterSpaceRemaining - paddedLength) < 0) {
1040                     /* exceeds what we can transfer, put the packet back */  
1041                 HTC_PACKET_ENQUEUE_TO_HEAD(pRecvPktQueue,pPacket);
1042                 break;    
1043             }
1044                         
1045             scatterSpaceRemaining -= paddedLength;
1046                        
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;
1051             }
1052             
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;
1057             
1058             pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE;
1059             
1060             if (asyncMode) {
1061                     /* save HTC packet for async completion routine */
1062                 pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
1063             } else {
1064                     /* queue to caller's sync completion queue, caller will unload this when we return */
1065                 HTC_PACKET_ENQUEUE(pSyncCompletionQueue,pPacket);    
1066             }             
1067                    
1068             A_ASSERT(pScatterReq->ScatterList[i].Length);
1069             totalLength += pScatterReq->ScatterList[i].Length;
1070         }            
1071         
1072         pScatterReq->TotalLength = totalLength;
1073         pScatterReq->ValidScatterEntries = i;
1074         
1075         if (asyncMode) {
1076             pScatterReq->CompletionRoutine = HTCAsyncRecvScatterCompletion;
1077             pScatterReq->Context = target;
1078         }
1079         
1080         status = DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_READ, asyncMode);
1081         
1082         if (!status) {
1083             *pNumPacketsFetched = i;    
1084         }
1085         
1086         if (!asyncMode) {
1087                 /* free scatter request */
1088             DEV_FREE_SCATTER_REQ(&target->Device, pScatterReq);   
1089         }
1090         
1091     } while (false);
1092    
1093     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCIssueRecvPacketBundle (status:%d) (fetched:%d) \n",
1094             status,*pNumPacketsFetched));
1095         
1096     return status;
1097 }
1098
1099 static INLINE void CheckRecvWaterMark(struct htc_endpoint    *pEndpoint)
1100 {  
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,
1108                                                 pEndpoint->Id);
1109         }
1110     }  
1111 }
1112
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)
1115 {
1116     struct htc_target      *target = (struct htc_target *)Context;
1117     int         status = 0;
1118     struct htc_packet      *pPacket;
1119     struct htc_endpoint    *pEndpoint;
1120     bool          asyncProc = false;
1121     u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
1122     int             pktsFetched;
1123     struct htc_packet_queue recvPktQueue, syncCompletedPktsQueue;
1124     bool          partialBundle;
1125     HTC_ENDPOINT_ID id;
1126     int             totalFetched = 0;
1127     
1128     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler NumLookAheads: %d \n",NumLookAheads));
1129     
1130     if (pNumPktsFetched != NULL) {
1131         *pNumPktsFetched = 0;    
1132     }
1133     
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 */
1138         asyncProc = true;
1139     }
1140
1141     if (pAsyncProc != NULL) {
1142             /* indicate to caller how we decided to process this */
1143         *pAsyncProc = asyncProc;
1144     }
1145     
1146     if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1147         A_ASSERT(false);
1148         return A_EPROTO; 
1149     }
1150         
1151         /* on first entry copy the lookaheads into our temp array for processing */
1152     memcpy(lookAheads, MsgLookAheads, (sizeof(u32)) * NumLookAheads);
1153             
1154     while (true) {
1155         
1156             /* reset packets queues */
1157         INIT_HTC_PACKET_QUEUE(&recvPktQueue);
1158         INIT_HTC_PACKET_QUEUE(&syncCompletedPktsQueue);
1159         
1160         if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1161             status = A_EPROTO;
1162             A_ASSERT(false);
1163             break;    
1164         }
1165    
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];
1169         
1170         if (id >= ENDPOINT_MAX) {
1171             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MsgPend, Invalid Endpoint in look-ahead: %d \n",id));
1172             status = A_EPROTO;
1173             break;
1174         }
1175         
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, 
1179                                           lookAheads, 
1180                                           NumLookAheads,
1181                                           pEndpoint, 
1182                                           &recvPktQueue);        
1183         if (status) {
1184             break;    
1185         }
1186  
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);
1190         }
1191         
1192         totalFetched += HTC_PACKET_QUEUE_DEPTH(&recvPktQueue);
1193                
1194             /* we've got packet buffers for all we can currently fetch, 
1195              * this count is not valid anymore  */
1196         NumLookAheads = 0;
1197         partialBundle = false;
1198        
1199             /* now go fetch the list of HTC packets */
1200         while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {   
1201             
1202             pktsFetched = 0;
1203                        
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,
1207                                                   &recvPktQueue,
1208                                                   asyncProc ? NULL : &syncCompletedPktsQueue,
1209                                                   &pktsFetched,
1210                                                   partialBundle);                                                   
1211                 if (status) {
1212                     break;
1213                 }
1214                 
1215                 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) != 0) {
1216                         /* we couldn't fetch all packets at one time, this creates a broken
1217                          * bundle  */
1218                     partialBundle = true;
1219                 }                                                                     
1220             }
1221             
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);                 
1227                                      
1228                 if (asyncProc) {
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;
1233                 } else {
1234                         /* fully synchronous */
1235                     pPacket->Completion = NULL;
1236                 }
1237                 
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;
1241                 }
1242                                     
1243                     /* go fetch the packet */
1244                 status = HTCIssueRecv(target, pPacket);              
1245                 if (status) {
1246                     break;
1247                 }  
1248                                
1249                 if (!asyncProc) {               
1250                         /* sent synchronously, queue this packet for synchronous completion */
1251                     HTC_PACKET_ENQUEUE(&syncCompletedPktsQueue,pPacket);
1252                 } 
1253                                
1254             }
1255             
1256         }
1257
1258         if (!status) {
1259             CheckRecvWaterMark(pEndpoint);
1260         }
1261             
1262         if (asyncProc) {
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  */
1266             break;
1267         }
1268
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++;    
1273         }
1274             
1275             /* in the sync case, all packet buffers are now filled, 
1276              * we can process each packet, check lookaheads and then repeat */ 
1277              
1278              /* unload sync completion queue */      
1279         while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1280             struct htc_packet_queue    container;
1281            
1282             pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
1283             A_ASSERT(pPacket != NULL);
1284             
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 */
1288             NumLookAheads = 0;
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);
1292             if (status) {
1293                 break;
1294             }
1295             
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);
1299             } else {
1300                     /* packets in a bundle automatically have this flag set */
1301                 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
1302             }
1303                 /* good packet, indicate it */
1304             HTC_RX_STAT_PROFILE(target,pEndpoint,NumLookAheads);
1305             
1306             if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_PART_OF_BUNDLE) {
1307                 INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
1308             }
1309             
1310             INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
1311             DO_RCV_COMPLETION(pEndpoint,&container);
1312         }
1313
1314         if (status) {
1315             break;
1316         }
1317             
1318         if (NumLookAheads == 0) {
1319                 /* no more look aheads */
1320             break;    
1321         }
1322
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 */
1328                 break;  
1329             }  
1330         }
1331             
1332
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 */
1335         A_CHECK_DRV_TX();
1336         
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);
1341     }
1342     
1343     if (status) {
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]);
1351         }
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]);
1357         }
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);
1362         }
1363     }
1364         /* before leaving, check to see if host ran out of buffers and needs to stop the
1365          * receiver */
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);
1371     }
1372     
1373     if (pNumPktsFetched != NULL) {
1374         *pNumPktsFetched = totalFetched;    
1375     }
1376     
1377     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
1378
1379     return status;
1380 }
1381
1382 int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
1383 {
1384     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1385     struct htc_endpoint    *pEndpoint;
1386     bool          unblockRecv = false;
1387     int        status = 0;
1388     struct htc_packet      *pFirstPacket;
1389
1390     pFirstPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
1391     
1392     if (NULL == pFirstPacket) {
1393         A_ASSERT(false);
1394         return A_EINVAL;    
1395     }
1396     
1397     AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
1398     
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));
1404
1405     do {
1406
1407         pEndpoint = &target->EndPoint[pFirstPacket->Endpoint];
1408
1409         LOCK_HTC_RX(target);
1410
1411         if (HTC_STOPPING(target)) {
1412             struct htc_packet *pPacket;
1413             
1414             UNLOCK_HTC_RX(target);
1415             
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;
1420             
1421             DO_RCV_COMPLETION(pEndpoint,pPktQueue);
1422             break;
1423         }
1424
1425             /* store receive packets */
1426         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBuffers, pPktQueue);
1427
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;
1435                 unblockRecv = true;
1436             }
1437         }
1438
1439         UNLOCK_HTC_RX(target);
1440
1441         if (unblockRecv && !HTC_STOPPING(target)) {
1442                 /* TODO : implement a buffer threshold count? */
1443             DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1444         }
1445
1446     } while (false);
1447
1448     return status;
1449 }
1450
1451 /* Makes a buffer available to the HTC module */
1452 int HTCAddReceivePkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
1453 {
1454     struct htc_packet_queue queue;
1455     INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket); 
1456     return HTCAddReceivePktMultiple(HTCHandle, &queue);       
1457 }
1458
1459 void HTCUnblockRecv(HTC_HANDLE HTCHandle)
1460 {
1461     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1462     bool      unblockRecv = false;
1463
1464     LOCK_HTC_RX(target);
1465
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;
1472         unblockRecv = true;
1473     }
1474
1475     UNLOCK_HTC_RX(target);
1476
1477     if (unblockRecv && !HTC_STOPPING(target)) {
1478             /* re-enable */
1479         DevEnableRecv(&target->Device,DEV_ENABLE_RECV_ASYNC);
1480     }
1481 }
1482
1483 static void HTCFlushRxQueue(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet_queue *pQueue)
1484 {
1485     struct htc_packet  *pPacket;
1486     struct htc_packet_queue container;
1487     
1488     LOCK_HTC_RX(target);
1489
1490     while (1) {
1491         pPacket = HTC_PACKET_DEQUEUE(pQueue);
1492         if (NULL == pPacket) {
1493             break;
1494         }
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);
1504     }
1505     
1506     UNLOCK_HTC_RX(target);
1507 }
1508
1509 static void HTCFlushEndpointRX(struct htc_target *target, struct htc_endpoint *pEndpoint)
1510 {
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);
1515 }
1516
1517 void HTCFlushRecvBuffers(struct htc_target *target)
1518 {
1519     struct htc_endpoint    *pEndpoint;
1520     int             i;
1521
1522     for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1523         pEndpoint = &target->EndPoint[i];
1524         if (pEndpoint->ServiceID == 0) {
1525                 /* not in use.. */
1526             continue;
1527         }
1528         HTCFlushEndpointRX(target,pEndpoint);
1529     }
1530 }
1531
1532
1533 void HTCEnableRecv(HTC_HANDLE HTCHandle)
1534 {
1535     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1536
1537     if (!HTC_STOPPING(target)) {
1538             /* re-enable */
1539         DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1540     }
1541 }
1542
1543 void HTCDisableRecv(HTC_HANDLE HTCHandle)
1544 {
1545     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1546
1547     if (!HTC_STOPPING(target)) {
1548             /* disable */
1549         DevStopRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1550     }
1551 }
1552
1553 int HTCGetNumRecvBuffers(HTC_HANDLE      HTCHandle,
1554                          HTC_ENDPOINT_ID Endpoint)
1555 {
1556     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);    
1557     return HTC_PACKET_QUEUE_DEPTH(&(target->EndPoint[Endpoint].RxBuffers));
1558 }
1559
1560 int HTCWaitForPendingRecv(HTC_HANDLE   HTCHandle,
1561                                u32 TimeoutInMs,
1562                                bool      *pbIsRecvPending)
1563 {
1564     int    status  = 0;
1565     struct htc_target *target  = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1566
1567     status = DevWaitForPendingRecv(&target->Device,
1568                                     TimeoutInMs,
1569                                     pbIsRecvPending);
1570
1571     return status;
1572 }