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 #ifdef HTC_EP_STAT_PROFILING
40 #define HTC_RX_STAT_PROFILE(t,ep,numLookAheads)        \
41 {                                                      \
42     INC_HTC_EP_STAT((ep), RxReceived, 1);              \
43     if ((numLookAheads) == 1) {                        \
44         INC_HTC_EP_STAT((ep), RxLookAheads, 1);        \
45     } else if ((numLookAheads) > 1) {                  \
46         INC_HTC_EP_STAT((ep), RxBundleLookAheads, 1);  \
47     }                                                  \
48 }
49 #else
50 #define HTC_RX_STAT_PROFILE(t,ep,lookAhead)
51 #endif
52 
DoRecvCompletion(struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueueToIndicate)53 static void DoRecvCompletion(struct htc_endpoint     *pEndpoint,
54                              struct htc_packet_queue *pQueueToIndicate)
55 {
56 
57     do {
58 
59         if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
60                 /* nothing to indicate */
61             break;
62         }
63 
64         if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) {
65             AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d, recv multiple callback (%d pkts) \n",
66                      pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
67                 /* a recv multiple handler is being used, pass the queue to the handler */
68             pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->EpCallBacks.pContext,
69                                                      pQueueToIndicate);
70             INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
71         } else {
72             struct htc_packet *pPacket;
73             /* using legacy EpRecv */
74             do {
75                 pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
76                 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d recv callback on packet 0x%lX \n", \
77                         pEndpoint->Id, (unsigned long)(pPacket)));
78                 pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket);
79             } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
80         }
81 
82     } while (false);
83 
84 }
85 
HTCProcessTrailer(struct htc_target * target,u8 * pBuffer,int Length,u32 * pNextLookAheads,int * pNumLookAheads,HTC_ENDPOINT_ID FromEndpoint)86 static INLINE int HTCProcessTrailer(struct htc_target *target,
87                                          u8 *pBuffer,
88                                          int         Length,
89                                          u32 *pNextLookAheads,
90                                          int        *pNumLookAheads,
91                                          HTC_ENDPOINT_ID FromEndpoint)
92 {
93     HTC_RECORD_HDR          *pRecord;
94     u8 *pRecordBuf;
95     HTC_LOOKAHEAD_REPORT    *pLookAhead;
96     u8 *pOrigBuffer;
97     int                     origLength;
98     int                status;
99 
100     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
101 
102     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
103         AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
104     }
105 
106     pOrigBuffer = pBuffer;
107     origLength = Length;
108     status = 0;
109 
110     while (Length > 0) {
111 
112         if (Length < sizeof(HTC_RECORD_HDR)) {
113             status = A_EPROTO;
114             break;
115         }
116             /* these are byte aligned structs */
117         pRecord = (HTC_RECORD_HDR *)pBuffer;
118         Length -= sizeof(HTC_RECORD_HDR);
119         pBuffer += sizeof(HTC_RECORD_HDR);
120 
121         if (pRecord->Length > Length) {
122                 /* no room left in buffer for record */
123             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
124                 (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
125                         pRecord->Length, pRecord->RecordID, Length));
126             status = A_EPROTO;
127             break;
128         }
129             /* start of record follows the header */
130         pRecordBuf = pBuffer;
131 
132         switch (pRecord->RecordID) {
133             case HTC_RECORD_CREDITS:
134                 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
135                 HTCProcessCreditRpt(target,
136                                     (HTC_CREDIT_REPORT *)pRecordBuf,
137                                     pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
138                                     FromEndpoint);
139                 break;
140             case HTC_RECORD_LOOKAHEAD:
141                 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
142                 pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
143                 if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
144                     (pNextLookAheads != NULL)) {
145 
146                     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
147                                 (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
148                                 pLookAhead->PreValid,
149                                 pLookAhead->PostValid));
150 
151                         /* look ahead bytes are valid, copy them over */
152                     ((u8 *)(&pNextLookAheads[0]))[0] = pLookAhead->LookAhead[0];
153                     ((u8 *)(&pNextLookAheads[0]))[1] = pLookAhead->LookAhead[1];
154                     ((u8 *)(&pNextLookAheads[0]))[2] = pLookAhead->LookAhead[2];
155                     ((u8 *)(&pNextLookAheads[0]))[3] = pLookAhead->LookAhead[3];
156 
157 #ifdef ATH_DEBUG_MODULE
158                     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
159                         DebugDumpBytes((u8 *)pNextLookAheads,4,"Next Look Ahead");
160                     }
161 #endif
162                         /* just one normal lookahead */
163                     *pNumLookAheads = 1;
164                 }
165                 break;
166             case HTC_RECORD_LOOKAHEAD_BUNDLE:
167                 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
168                 if (pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT) &&
169                     (pNextLookAheads != NULL)) {
170                     HTC_BUNDLED_LOOKAHEAD_REPORT    *pBundledLookAheadRpt;
171                     int                             i;
172 
173                     pBundledLookAheadRpt = (HTC_BUNDLED_LOOKAHEAD_REPORT *)pRecordBuf;
174 
175 #ifdef ATH_DEBUG_MODULE
176                     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
177                         DebugDumpBytes(pRecordBuf,pRecord->Length,"Bundle LookAhead");
178                     }
179 #endif
180 
181                     if ((pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))) >
182                             HTC_HOST_MAX_MSG_PER_BUNDLE) {
183                             /* this should never happen, the target restricts the number
184                              * of messages per bundle configured by the host */
185                         A_ASSERT(false);
186                         status = A_EPROTO;
187                         break;
188                     }
189 
190                     for (i = 0; i < (int)(pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))); i++) {
191                         ((u8 *)(&pNextLookAheads[i]))[0] = pBundledLookAheadRpt->LookAhead[0];
192                         ((u8 *)(&pNextLookAheads[i]))[1] = pBundledLookAheadRpt->LookAhead[1];
193                         ((u8 *)(&pNextLookAheads[i]))[2] = pBundledLookAheadRpt->LookAhead[2];
194                         ((u8 *)(&pNextLookAheads[i]))[3] = pBundledLookAheadRpt->LookAhead[3];
195                         pBundledLookAheadRpt++;
196                     }
197 
198                     *pNumLookAheads = i;
199                 }
200                 break;
201             default:
202                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
203                         pRecord->RecordID, pRecord->Length));
204                 break;
205         }
206 
207         if (status) {
208             break;
209         }
210 
211             /* advance buffer past this record for next time around */
212         pBuffer += pRecord->Length;
213         Length -= pRecord->Length;
214     }
215 
216 #ifdef ATH_DEBUG_MODULE
217     if (status) {
218         DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
219     }
220 #endif
221 
222     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
223     return status;
224 
225 }
226 
227 /* process a received message (i.e. strip off header, process any trailer data)
228  * note : locks must be released when this function is called */
HTCProcessRecvHeader(struct htc_target * target,struct htc_packet * pPacket,u32 * pNextLookAheads,int * pNumLookAheads)229 static int HTCProcessRecvHeader(struct htc_target *target,
230                                      struct htc_packet *pPacket,
231                                      u32 *pNextLookAheads,
232                                      int        *pNumLookAheads)
233 {
234     u8 temp;
235     u8 *pBuf;
236     int  status = 0;
237     u16 payloadLen;
238     u32 lookAhead;
239 
240     pBuf = pPacket->pBuffer;
241 
242     if (pNumLookAheads != NULL) {
243         *pNumLookAheads = 0;
244     }
245 
246     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
247 
248     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
249         AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
250     }
251 
252     do {
253         /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
254          * retrieve 16 bit fields */
255         payloadLen = A_GET_UINT16_FIELD(pBuf, struct htc_frame_hdr, PayloadLen);
256 
257         ((u8 *)&lookAhead)[0] = pBuf[0];
258         ((u8 *)&lookAhead)[1] = pBuf[1];
259         ((u8 *)&lookAhead)[2] = pBuf[2];
260         ((u8 *)&lookAhead)[3] = pBuf[3];
261 
262         if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
263                 /* refresh expected hdr, since this was unknown at the time we grabbed the packets
264                  * as part of a bundle */
265             pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
266                 /* refresh actual length since we now have the real header */
267             pPacket->ActualLength = payloadLen + HTC_HDR_LENGTH;
268 
269                 /* validate the actual header that was refreshed  */
270             if (pPacket->ActualLength > pPacket->BufferLength) {
271                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
272                     ("Refreshed HDR payload length (%d) in bundled RECV is invalid (hdr: 0x%X) \n",
273                     payloadLen, lookAhead));
274                     /* limit this to max buffer just to print out some of the buffer */
275                 pPacket->ActualLength = min(pPacket->ActualLength, pPacket->BufferLength);
276                 status = A_EPROTO;
277                 break;
278             }
279 
280             if (pPacket->Endpoint != A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID)) {
281                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
282                     ("Refreshed HDR endpoint (%d) does not match expected endpoint (%d) \n",
283                     A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID), pPacket->Endpoint));
284                 status = A_EPROTO;
285                 break;
286             }
287         }
288 
289         if (lookAhead != pPacket->PktInfo.AsRx.ExpectedHdr) {
290             /* somehow the lookahead that gave us the full read length did not
291              * reflect the actual header in the pending message */
292              AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
293                     ("HTCProcessRecvHeader, lookahead mismatch! (pPkt:0x%lX flags:0x%X) \n",
294                         (unsigned long)pPacket, pPacket->PktInfo.AsRx.HTCRxFlags));
295 #ifdef ATH_DEBUG_MODULE
296              DebugDumpBytes((u8 *)&pPacket->PktInfo.AsRx.ExpectedHdr,4,"Expected Message LookAhead");
297              DebugDumpBytes(pBuf,sizeof(struct htc_frame_hdr),"Current Frame Header");
298 #ifdef HTC_CAPTURE_LAST_FRAME
299             DebugDumpBytes((u8 *)&target->LastFrameHdr,sizeof(struct htc_frame_hdr),"Last Frame Header");
300             if (target->LastTrailerLength != 0) {
301                 DebugDumpBytes(target->LastTrailer,
302                                target->LastTrailerLength,
303                                "Last trailer");
304             }
305 #endif
306 #endif
307             status = A_EPROTO;
308             break;
309         }
310 
311             /* get flags */
312         temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, Flags);
313 
314         if (temp & HTC_FLAGS_RECV_TRAILER) {
315             /* this packet has a trailer */
316 
317                 /* extract the trailer length in control byte 0 */
318             temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, ControlBytes[0]);
319 
320             if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
321                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
322                     ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
323                         payloadLen, temp));
324                 status = A_EPROTO;
325                 break;
326             }
327 
328             if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
329                     /* this packet was fetched as part of an HTC bundle, the embedded lookahead is
330                      * not valid since the next packet may have already been fetched as part of the
331                      * bundle */
332                 pNextLookAheads = NULL;
333                 pNumLookAheads = NULL;
334             }
335 
336                 /* process trailer data that follows HDR + application payload */
337             status = HTCProcessTrailer(target,
338                                        (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
339                                        temp,
340                                        pNextLookAheads,
341                                        pNumLookAheads,
342                                        pPacket->Endpoint);
343 
344             if (status) {
345                 break;
346             }
347 
348 #ifdef HTC_CAPTURE_LAST_FRAME
349             memcpy(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
350             target->LastTrailerLength = temp;
351 #endif
352                 /* trim length by trailer bytes */
353             pPacket->ActualLength -= temp;
354         }
355 #ifdef HTC_CAPTURE_LAST_FRAME
356          else {
357             target->LastTrailerLength = 0;
358         }
359 #endif
360 
361             /* if we get to this point, the packet is good */
362             /* remove header and adjust length */
363         pPacket->pBuffer += HTC_HDR_LENGTH;
364         pPacket->ActualLength -= HTC_HDR_LENGTH;
365 
366     } while (false);
367 
368     if (status) {
369             /* dump the whole packet */
370 #ifdef ATH_DEBUG_MODULE
371         DebugDumpBytes(pBuf,pPacket->ActualLength < 256 ? pPacket->ActualLength : 256 ,"BAD HTC Recv PKT");
372 #endif
373     } else {
374 #ifdef HTC_CAPTURE_LAST_FRAME
375         memcpy(&target->LastFrameHdr,pBuf,sizeof(struct htc_frame_hdr));
376 #endif
377         if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
378             if (pPacket->ActualLength > 0) {
379                 AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
380             }
381         }
382     }
383 
384     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
385     return status;
386 }
387 
HTCAsyncRecvCheckMorePackets(struct htc_target * target,u32 NextLookAheads[],int NumLookAheads,bool CheckMoreMsgs)388 static INLINE void HTCAsyncRecvCheckMorePackets(struct htc_target  *target,
389                                                 u32 NextLookAheads[],
390                                                 int         NumLookAheads,
391                                                 bool      CheckMoreMsgs)
392 {
393         /* was there a lookahead for the next packet? */
394     if (NumLookAheads > 0) {
395         int nextStatus;
396         int      fetched = 0;
397         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
398                         ("HTCAsyncRecvCheckMorePackets - num lookaheads were non-zero : %d \n",
399                          NumLookAheads));
400             /* force status re-check */
401         REF_IRQ_STATUS_RECHECK(&target->Device);
402             /* we have more packets, get the next packet fetch started */
403         nextStatus = HTCRecvMessagePendingHandler(target, NextLookAheads, NumLookAheads, NULL, &fetched);
404         if (A_EPROTO == nextStatus) {
405             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
406                         ("Next look ahead from recv header was INVALID\n"));
407 #ifdef ATH_DEBUG_MODULE
408             DebugDumpBytes((u8 *)NextLookAheads,
409                             NumLookAheads * (sizeof(u32)),
410                             "BAD lookaheads from lookahead report");
411 #endif
412         }
413         if (!nextStatus && !fetched) {
414                 /* we could not fetch any more packets due to resources */
415             DevAsyncIrqProcessComplete(&target->Device);
416         }
417     } else {
418         if (CheckMoreMsgs) {
419             AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
420                 ("HTCAsyncRecvCheckMorePackets - rechecking for more messages...\n"));
421             /* if we did not get anything on the look-ahead,
422              * call device layer to asynchronously re-check for messages. If we can keep the async
423              * processing going we get better performance.  If there is a pending message we will keep processing
424              * messages asynchronously which should pipeline things nicely */
425             DevCheckPendingRecvMsgsAsync(&target->Device);
426         } else {
427             AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCAsyncRecvCheckMorePackets - no check \n"));
428         }
429     }
430 
431 
432 }
433 
434     /* unload the recv completion queue */
DrainRecvIndicationQueue(struct htc_target * target,struct htc_endpoint * pEndpoint)435 static INLINE void DrainRecvIndicationQueue(struct htc_target *target, struct htc_endpoint *pEndpoint)
436 {
437     struct htc_packet_queue     recvCompletions;
438 
439     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+DrainRecvIndicationQueue \n"));
440 
441     INIT_HTC_PACKET_QUEUE(&recvCompletions);
442 
443     LOCK_HTC_RX(target);
444 
445             /* increment rx processing count on entry */
446     pEndpoint->RxProcessCount++;
447     if (pEndpoint->RxProcessCount > 1) {
448          pEndpoint->RxProcessCount--;
449             /* another thread or task is draining the RX completion queue on this endpoint
450              * that thread will reset the rx processing count when the queue is drained */
451          UNLOCK_HTC_RX(target);
452          return;
453     }
454 
455     /******* at this point only 1 thread may enter ******/
456 
457     while (true) {
458 
459             /* transfer items from main recv queue to the local one so we can release the lock */
460         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&recvCompletions, &pEndpoint->RecvIndicationQueue);
461 
462         if (HTC_QUEUE_EMPTY(&recvCompletions)) {
463                 /* all drained */
464             break;
465         }
466 
467             /* release lock while we do the recv completions
468              * other threads can now queue more recv completions */
469         UNLOCK_HTC_RX(target);
470 
471         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
472                 ("DrainRecvIndicationQueue : completing %d RECV packets \n",
473                                         HTC_PACKET_QUEUE_DEPTH(&recvCompletions)));
474             /* do completion */
475         DO_RCV_COMPLETION(pEndpoint,&recvCompletions);
476 
477             /* re-acquire lock to grab some more completions */
478         LOCK_HTC_RX(target);
479     }
480 
481         /* reset count */
482     pEndpoint->RxProcessCount = 0;
483     UNLOCK_HTC_RX(target);
484 
485     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-DrainRecvIndicationQueue \n"));
486 
487 }
488 
489     /* optimization for recv packets, we can indicate a "hint" that there are more
490      * single-packets to fetch on this endpoint */
491 #define SET_MORE_RX_PACKET_INDICATION_FLAG(L,N,E,P) \
492     if ((N) > 0) { SetRxPacketIndicationFlags((L)[0],(E),(P)); }
493 
494     /* for bundled frames, we can force the flag to indicate there are more packets */
495 #define FORCE_MORE_RX_PACKET_INDICATION_FLAG(P) \
496     (P)->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS;
497 
498    /* note: this function can be called with the RX lock held */
SetRxPacketIndicationFlags(u32 LookAhead,struct htc_endpoint * pEndpoint,struct htc_packet * pPacket)499 static INLINE void SetRxPacketIndicationFlags(u32 LookAhead,
500                                               struct htc_endpoint  *pEndpoint,
501                                               struct htc_packet    *pPacket)
502 {
503     struct htc_frame_hdr *pHdr = (struct htc_frame_hdr *)&LookAhead;
504         /* check to see if the "next" packet is from the same endpoint of the
505            completing packet */
506     if (pHdr->EndpointID == pPacket->Endpoint) {
507             /* check that there is a buffer available to actually fetch it */
508         if (!HTC_QUEUE_EMPTY(&pEndpoint->RxBuffers)) {
509                 /* provide a hint that there are more RX packets to fetch */
510             FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
511         }
512     }
513 }
514 
515 
516 /* asynchronous completion handler for recv packet fetching, when the device layer
517  * completes a read request, it will call this completion handler */
HTCRecvCompleteHandler(void * Context,struct htc_packet * pPacket)518 void HTCRecvCompleteHandler(void *Context, struct htc_packet *pPacket)
519 {
520     struct htc_target      *target = (struct htc_target *)Context;
521     struct htc_endpoint    *pEndpoint;
522     u32 nextLookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
523     int             numLookAheads = 0;
524     int        status;
525     bool          checkMorePkts = true;
526 
527     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (pkt:0x%lX, status:%d, ep:%d) \n",
528                 (unsigned long)pPacket, pPacket->Status, pPacket->Endpoint));
529 
530     A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
531     AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
532     pEndpoint = &target->EndPoint[pPacket->Endpoint];
533     pPacket->Completion = NULL;
534 
535         /* get completion status */
536     status = pPacket->Status;
537 
538     do {
539 
540         if (status) {
541             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
542                 pPacket->Status, pPacket->Endpoint));
543             break;
544         }
545             /* process the header for any trailer data */
546         status = HTCProcessRecvHeader(target,pPacket,nextLookAheads,&numLookAheads);
547 
548         if (status) {
549             break;
550         }
551 
552         if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
553                 /* this packet was part of a bundle that had to be broken up.
554                  * It was fetched one message at a time.  There may be other asynchronous reads queued behind this one.
555                  * Do no issue another check for more packets since the last one in the series of requests
556                  * will handle it */
557             checkMorePkts = false;
558         }
559 
560         DUMP_RECV_PKT_INFO(pPacket);
561         LOCK_HTC_RX(target);
562         SET_MORE_RX_PACKET_INDICATION_FLAG(nextLookAheads,numLookAheads,pEndpoint,pPacket);
563             /* we have a good packet, queue it to the completion queue */
564         HTC_PACKET_ENQUEUE(&pEndpoint->RecvIndicationQueue,pPacket);
565         HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
566         UNLOCK_HTC_RX(target);
567 
568             /* check for more recv packets before indicating */
569         HTCAsyncRecvCheckMorePackets(target,nextLookAheads,numLookAheads,checkMorePkts);
570 
571     } while (false);
572 
573     if (status) {
574          AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
575                          ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
576                          status));
577             /* recycle this packet */
578         HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
579     } else {
580             /* a good packet was queued, drain the queue */
581         DrainRecvIndicationQueue(target,pEndpoint);
582     }
583 
584     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
585 }
586 
587 /* synchronously wait for a control message from the target,
588  * This function is used at initialization time ONLY.  At init messages
589  * on ENDPOINT 0 are expected. */
HTCWaitforControlMessage(struct htc_target * target,struct htc_packet ** ppControlPacket)590 int HTCWaitforControlMessage(struct htc_target *target, struct htc_packet **ppControlPacket)
591 {
592     int        status;
593     u32 lookAhead;
594     struct htc_packet      *pPacket = NULL;
595     struct htc_frame_hdr   *pHdr;
596 
597     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
598 
599     do  {
600 
601         *ppControlPacket = NULL;
602 
603             /* call the polling function to see if we have a message */
604         status = DevPollMboxMsgRecv(&target->Device,
605                                     &lookAhead,
606                                     HTC_TARGET_RESPONSE_TIMEOUT);
607 
608         if (status) {
609             break;
610         }
611 
612         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
613                 ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
614 
615             /* check the lookahead */
616         pHdr = (struct htc_frame_hdr *)&lookAhead;
617 
618         if (pHdr->EndpointID != ENDPOINT_0) {
619                 /* unexpected endpoint number, should be zero */
620             AR_DEBUG_ASSERT(false);
621             status = A_EPROTO;
622             break;
623         }
624 
625         if (status) {
626                 /* bad message */
627             AR_DEBUG_ASSERT(false);
628             status = A_EPROTO;
629             break;
630         }
631 
632         pPacket = HTC_ALLOC_CONTROL_RX(target);
633 
634         if (pPacket == NULL) {
635             AR_DEBUG_ASSERT(false);
636             status = A_NO_MEMORY;
637             break;
638         }
639 
640         pPacket->PktInfo.AsRx.HTCRxFlags = 0;
641         pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
642         pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
643 
644         if (pPacket->ActualLength > pPacket->BufferLength) {
645             AR_DEBUG_ASSERT(false);
646             status = A_EPROTO;
647             break;
648         }
649 
650             /* we want synchronous operation */
651         pPacket->Completion = NULL;
652 
653             /* get the message from the device, this will block */
654         status = HTCIssueRecv(target, pPacket);
655 
656         if (status) {
657             break;
658         }
659 
660             /* process receive header */
661         status = HTCProcessRecvHeader(target,pPacket,NULL,NULL);
662 
663         pPacket->Status = status;
664 
665         if (status) {
666             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
667                     ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
668                      status));
669             break;
670         }
671 
672             /* give the caller this control message packet, they are responsible to free */
673         *ppControlPacket = pPacket;
674 
675     } while (false);
676 
677     if (status) {
678         if (pPacket != NULL) {
679                 /* cleanup buffer on error */
680             HTC_FREE_CONTROL_RX(target,pPacket);
681         }
682     }
683 
684     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
685 
686     return status;
687 }
688 
AllocAndPrepareRxPackets(struct htc_target * target,u32 LookAheads[],int Messages,struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueue)689 static int AllocAndPrepareRxPackets(struct htc_target       *target,
690                                          u32 LookAheads[],
691                                          int              Messages,
692                                          struct htc_endpoint     *pEndpoint,
693                                          struct htc_packet_queue *pQueue)
694 {
695     int         status = 0;
696     struct htc_packet      *pPacket;
697     struct htc_frame_hdr   *pHdr;
698     int              i,j;
699     int              numMessages;
700     int              fullLength;
701     bool           noRecycle;
702 
703         /* lock RX while we assemble the packet buffers */
704     LOCK_HTC_RX(target);
705 
706     for (i = 0; i < Messages; i++) {
707 
708         pHdr = (struct htc_frame_hdr *)&LookAheads[i];
709 
710         if (pHdr->EndpointID >= ENDPOINT_MAX) {
711             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
712                 /* invalid endpoint */
713             status = A_EPROTO;
714             break;
715         }
716 
717         if (pHdr->EndpointID != pEndpoint->Id) {
718             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d should be : %d (index:%d)\n",
719                 pHdr->EndpointID, pEndpoint->Id, i));
720                 /* invalid endpoint */
721             status = A_EPROTO;
722             break;
723         }
724 
725         if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
726             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
727                     pHdr->PayloadLen, (u32)HTC_MAX_PAYLOAD_LENGTH));
728             status = A_EPROTO;
729             break;
730         }
731 
732         if (0 == pEndpoint->ServiceID) {
733             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
734                 /* endpoint isn't even connected */
735             status = A_EPROTO;
736             break;
737         }
738 
739         if ((pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
740                 /* HTC header only indicates 1 message to fetch */
741             numMessages = 1;
742         } else {
743                 /* HTC header indicates that every packet to follow has the same padded length so that it can
744                  * be optimally fetched as a full bundle */
745             numMessages = (pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT;
746                 /* the count doesn't include the starter frame, just a count of frames to follow */
747             numMessages++;
748             A_ASSERT(numMessages <= target->MaxMsgPerBundle);
749             INC_HTC_EP_STAT(pEndpoint, RxBundleIndFromHdr, 1);
750             AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
751                 ("HTC header indicates :%d messages can be fetched as a bundle \n",numMessages));
752         }
753 
754         fullLength = DEV_CALC_RECV_PADDED_LEN(&target->Device,pHdr->PayloadLen + sizeof(struct htc_frame_hdr));
755 
756             /* get packet buffers for each message, if there was a bundle detected in the header,
757              * use pHdr as a template to fetch all packets in the bundle */
758         for (j = 0; j < numMessages; j++) {
759 
760                 /* reset flag, any packets allocated using the RecvAlloc() API cannot be recycled on cleanup,
761                  * they must be explicitly returned */
762             noRecycle = false;
763 
764             if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) {
765                 UNLOCK_HTC_RX(target);
766                 noRecycle = true;
767                     /* user is using a per-packet allocation callback */
768                 pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext,
769                                                              pEndpoint->Id,
770                                                              fullLength);
771                 LOCK_HTC_RX(target);
772 
773             } else if ((pEndpoint->EpCallBacks.EpRecvAllocThresh != NULL) &&
774                        (fullLength > pEndpoint->EpCallBacks.RecvAllocThreshold)) {
775                 INC_HTC_EP_STAT(pEndpoint,RxAllocThreshHit,1);
776                 INC_HTC_EP_STAT(pEndpoint,RxAllocThreshBytes,pHdr->PayloadLen);
777                     /* threshold was hit, call the special recv allocation callback */
778                 UNLOCK_HTC_RX(target);
779                 noRecycle = true;
780                     /* user wants to allocate packets above a certain threshold */
781                 pPacket = pEndpoint->EpCallBacks.EpRecvAllocThresh(pEndpoint->EpCallBacks.pContext,
782                                                                    pEndpoint->Id,
783                                                                    fullLength);
784                 LOCK_HTC_RX(target);
785 
786             } else {
787                     /* user is using a refill handler that can refill multiple HTC buffers */
788 
789                     /* get a packet from the endpoint recv queue */
790                 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
791 
792                 if (NULL == pPacket) {
793                         /* check for refill handler */
794                     if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
795                         UNLOCK_HTC_RX(target);
796                             /* call the re-fill handler */
797                         pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
798                                                             pEndpoint->Id);
799                         LOCK_HTC_RX(target);
800                             /* check if we have more buffers */
801                         pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
802                             /* fall through */
803                     }
804                 }
805             }
806 
807             if (NULL == pPacket) {
808                     /* this is not an error, we simply need to mark that we are waiting for buffers.*/
809                 target->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
810                 target->EpWaitingForBuffers = pEndpoint->Id;
811                 status = A_NO_RESOURCE;
812                 break;
813             }
814 
815             AR_DEBUG_ASSERT(pPacket->Endpoint == pEndpoint->Id);
816                 /* clear flags */
817             pPacket->PktInfo.AsRx.HTCRxFlags = 0;
818             pPacket->PktInfo.AsRx.IndicationFlags = 0;
819             pPacket->Status = 0;
820 
821             if (noRecycle) {
822                     /* flag that these packets cannot be recycled, they have to be returned to the
823                      * user */
824                 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_NO_RECYCLE;
825             }
826                 /* add packet to queue (also incase we need to cleanup down below)  */
827             HTC_PACKET_ENQUEUE(pQueue,pPacket);
828 
829             if (HTC_STOPPING(target)) {
830                 status = A_ECANCELED;
831                 break;
832             }
833 
834                 /* make sure this message can fit in the endpoint buffer */
835             if ((u32)fullLength > pPacket->BufferLength) {
836                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
837                         ("Payload Length Error : header reports payload of: %d (%d) endpoint buffer size: %d \n",
838                         pHdr->PayloadLen, fullLength, pPacket->BufferLength));
839                 status = A_EPROTO;
840                 break;
841             }
842 
843             if (j > 0) {
844                     /* for messages fetched in a bundle the expected lookahead is unknown since we
845                      * are only using the lookahead of the first packet as a template of what to
846                      * expect for lengths */
847                     /* flag that once we get the real HTC header we need to refesh the information */
848                 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_REFRESH_HDR;
849                     /* set it to something invalid */
850                 pPacket->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
851             } else {
852 
853                 pPacket->PktInfo.AsRx.ExpectedHdr = LookAheads[i]; /* set expected look ahead */
854             }
855                 /* set the amount of data to fetch */
856             pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
857         }
858 
859         if (status) {
860             if (A_NO_RESOURCE == status) {
861                     /* this is actually okay */
862                 status = 0;
863             }
864             break;
865         }
866 
867     }
868 
869     UNLOCK_HTC_RX(target);
870 
871     if (status) {
872         while (!HTC_QUEUE_EMPTY(pQueue)) {
873             pPacket = HTC_PACKET_DEQUEUE(pQueue);
874                 /* recycle all allocated packets */
875             HTC_RECYCLE_RX_PKT(target,pPacket,&target->EndPoint[pPacket->Endpoint]);
876         }
877     }
878 
879     return status;
880 }
881 
HTCAsyncRecvScatterCompletion(struct hif_scatter_req * pScatterReq)882 static void HTCAsyncRecvScatterCompletion(struct hif_scatter_req *pScatterReq)
883 {
884     int                 i;
885     struct htc_packet          *pPacket;
886     struct htc_endpoint        *pEndpoint;
887     u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
888     int                 numLookAheads = 0;
889     struct htc_target          *target = (struct htc_target *)pScatterReq->Context;
890     int            status;
891     bool              partialBundle = false;
892     struct htc_packet_queue    localRecvQueue;
893     bool              procError = false;
894 
895     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCAsyncRecvScatterCompletion  TotLen: %d  Entries: %d\n",
896         pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
897 
898     A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
899 
900     if (pScatterReq->CompletionStatus) {
901         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Recv Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
902     }
903 
904     if (pScatterReq->CallerFlags & HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE) {
905         partialBundle = true;
906     }
907 
908     DEV_FINISH_SCATTER_OPERATION(pScatterReq);
909 
910     INIT_HTC_PACKET_QUEUE(&localRecvQueue);
911 
912     pPacket = (struct htc_packet *)pScatterReq->ScatterList[0].pCallerContexts[0];
913         /* note: all packets in a scatter req are for the same endpoint ! */
914     pEndpoint = &target->EndPoint[pPacket->Endpoint];
915 
916         /* walk through the scatter list and process */
917         /* **** NOTE: DO NOT HOLD ANY LOCKS here, HTCProcessRecvHeader can take the TX lock
918          * as it processes credit reports */
919     for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
920         pPacket = (struct htc_packet *)pScatterReq->ScatterList[i].pCallerContexts[0];
921         A_ASSERT(pPacket != NULL);
922             /* reset count, we are only interested in the look ahead in the last packet when we
923              * break out of this loop */
924         numLookAheads = 0;
925 
926         if (!pScatterReq->CompletionStatus) {
927                 /* process header for each of the recv packets */
928             status = HTCProcessRecvHeader(target,pPacket,lookAheads,&numLookAheads);
929         } else {
930             status = A_ERROR;
931         }
932 
933         if (!status) {
934 #ifdef HTC_EP_STAT_PROFILING
935             LOCK_HTC_RX(target);
936             HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
937             INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
938             UNLOCK_HTC_RX(target);
939 #endif
940             if (i == (pScatterReq->ValidScatterEntries - 1)) {
941                     /* last packet's more packets flag is set based on the lookahead */
942                 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,numLookAheads,pEndpoint,pPacket);
943             } else {
944                     /* packets in a bundle automatically have this flag set */
945                 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
946             }
947 
948             DUMP_RECV_PKT_INFO(pPacket);
949                 /* since we can't hold a lock in this loop, we insert into our local recv queue for
950                  * storage until we can transfer them to the recv completion queue */
951             HTC_PACKET_ENQUEUE(&localRecvQueue,pPacket);
952 
953         } else {
954             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Recv packet scatter entry %d failed (out of %d) \n",
955                     i, pScatterReq->ValidScatterEntries));
956                 /* recycle failed recv */
957             HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
958                 /* set flag and continue processing the remaining scatter entries */
959             procError = true;
960         }
961 
962     }
963 
964         /* free scatter request */
965     DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
966 
967     LOCK_HTC_RX(target);
968         /* transfer the packets in the local recv queue to the recv completion queue */
969     HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RecvIndicationQueue, &localRecvQueue);
970 
971     UNLOCK_HTC_RX(target);
972 
973     if (!procError) {
974             /* pipeline the next check (asynchronously) for more packets */
975         HTCAsyncRecvCheckMorePackets(target,
976                                      lookAheads,
977                                      numLookAheads,
978                                      partialBundle ? false : true);
979     }
980 
981         /* now drain the indication queue */
982     DrainRecvIndicationQueue(target,pEndpoint);
983 
984     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCAsyncRecvScatterCompletion \n"));
985 }
986 
HTCIssueRecvPacketBundle(struct htc_target * target,struct htc_packet_queue * pRecvPktQueue,struct htc_packet_queue * pSyncCompletionQueue,int * pNumPacketsFetched,bool PartialBundle)987 static int HTCIssueRecvPacketBundle(struct htc_target        *target,
988                                          struct htc_packet_queue  *pRecvPktQueue,
989                                          struct htc_packet_queue  *pSyncCompletionQueue,
990                                          int               *pNumPacketsFetched,
991                                          bool             PartialBundle)
992 {
993     int        status = 0;
994     struct hif_scatter_req *pScatterReq;
995     int             i, totalLength;
996     int             pktsToScatter;
997     struct htc_packet      *pPacket;
998     bool          asyncMode = (pSyncCompletionQueue == NULL) ? true : false;
999     int             scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device);
1000 
1001     pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue);
1002     pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
1003 
1004     if ((HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue) - pktsToScatter) > 0) {
1005             /* we were forced to split this bundle receive operation
1006              * all packets in this partial bundle must have their lookaheads ignored */
1007         PartialBundle = true;
1008             /* this would only happen if the target ignored our max bundle limit */
1009         AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1010                          ("HTCIssueRecvPacketBundle : partial bundle detected num:%d , %d \n",
1011                          HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
1012     }
1013 
1014     totalLength = 0;
1015 
1016     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCIssueRecvPacketBundle (Numpackets: %d , actual : %d) \n",
1017         HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
1018 
1019     do {
1020 
1021         pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device);
1022 
1023         if (pScatterReq == NULL) {
1024                 /* no scatter resources left, just let caller handle it the legacy way */
1025             break;
1026         }
1027 
1028         pScatterReq->CallerFlags = 0;
1029 
1030         if (PartialBundle) {
1031                 /* mark that this is a partial bundle, this has special ramifications to the
1032                  * scatter completion routine */
1033             pScatterReq->CallerFlags |= HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE;
1034         }
1035 
1036             /* convert HTC packets to scatter list */
1037         for (i = 0; i < pktsToScatter; i++) {
1038             int paddedLength;
1039 
1040             pPacket = HTC_PACKET_DEQUEUE(pRecvPktQueue);
1041             A_ASSERT(pPacket != NULL);
1042 
1043             paddedLength = DEV_CALC_RECV_PADDED_LEN(&target->Device, pPacket->ActualLength);
1044 
1045             if ((scatterSpaceRemaining - paddedLength) < 0) {
1046                     /* exceeds what we can transfer, put the packet back */
1047                 HTC_PACKET_ENQUEUE_TO_HEAD(pRecvPktQueue,pPacket);
1048                 break;
1049             }
1050 
1051             scatterSpaceRemaining -= paddedLength;
1052 
1053             if (PartialBundle || (i < (pktsToScatter - 1))) {
1054                     /* packet 0..n-1 cannot be checked for look-aheads since we are fetching a bundle
1055                      * the last packet however can have it's lookahead used */
1056                 pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
1057             }
1058 
1059             /* note: 1 HTC packet per scatter entry */
1060                 /* setup packet into */
1061             pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
1062             pScatterReq->ScatterList[i].Length = paddedLength;
1063 
1064             pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE;
1065 
1066             if (asyncMode) {
1067                     /* save HTC packet for async completion routine */
1068                 pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
1069             } else {
1070                     /* queue to caller's sync completion queue, caller will unload this when we return */
1071                 HTC_PACKET_ENQUEUE(pSyncCompletionQueue,pPacket);
1072             }
1073 
1074             A_ASSERT(pScatterReq->ScatterList[i].Length);
1075             totalLength += pScatterReq->ScatterList[i].Length;
1076         }
1077 
1078         pScatterReq->TotalLength = totalLength;
1079         pScatterReq->ValidScatterEntries = i;
1080 
1081         if (asyncMode) {
1082             pScatterReq->CompletionRoutine = HTCAsyncRecvScatterCompletion;
1083             pScatterReq->Context = target;
1084         }
1085 
1086         status = DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_READ, asyncMode);
1087 
1088         if (!status) {
1089             *pNumPacketsFetched = i;
1090         }
1091 
1092         if (!asyncMode) {
1093                 /* free scatter request */
1094             DEV_FREE_SCATTER_REQ(&target->Device, pScatterReq);
1095         }
1096 
1097     } while (false);
1098 
1099     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCIssueRecvPacketBundle (status:%d) (fetched:%d) \n",
1100             status,*pNumPacketsFetched));
1101 
1102     return status;
1103 }
1104 
CheckRecvWaterMark(struct htc_endpoint * pEndpoint)1105 static INLINE void CheckRecvWaterMark(struct htc_endpoint    *pEndpoint)
1106 {
1107         /* see if endpoint is using a refill watermark
1108          * ** no need to use a lock here, since we are only inspecting...
1109          * caller may must not hold locks when calling this function */
1110     if (pEndpoint->EpCallBacks.RecvRefillWaterMark > 0) {
1111         if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBuffers) < pEndpoint->EpCallBacks.RecvRefillWaterMark) {
1112                 /* call the re-fill handler before we continue */
1113             pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
1114                                                 pEndpoint->Id);
1115         }
1116     }
1117 }
1118 
1119 /* callback when device layer or lookahead report parsing detects a pending message */
HTCRecvMessagePendingHandler(void * Context,u32 MsgLookAheads[],int NumLookAheads,bool * pAsyncProc,int * pNumPktsFetched)1120 int HTCRecvMessagePendingHandler(void *Context, u32 MsgLookAheads[], int NumLookAheads, bool *pAsyncProc, int *pNumPktsFetched)
1121 {
1122     struct htc_target      *target = (struct htc_target *)Context;
1123     int         status = 0;
1124     struct htc_packet      *pPacket;
1125     struct htc_endpoint    *pEndpoint;
1126     bool          asyncProc = false;
1127     u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
1128     int             pktsFetched;
1129     struct htc_packet_queue recvPktQueue, syncCompletedPktsQueue;
1130     bool          partialBundle;
1131     HTC_ENDPOINT_ID id;
1132     int             totalFetched = 0;
1133 
1134     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler NumLookAheads: %d \n",NumLookAheads));
1135 
1136     if (pNumPktsFetched != NULL) {
1137         *pNumPktsFetched = 0;
1138     }
1139 
1140     if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
1141             /* We use async mode to get the packets if the device layer supports it.
1142              * The device layer interfaces with HIF in which HIF may have restrictions on
1143              * how interrupts are processed */
1144         asyncProc = true;
1145     }
1146 
1147     if (pAsyncProc != NULL) {
1148             /* indicate to caller how we decided to process this */
1149         *pAsyncProc = asyncProc;
1150     }
1151 
1152     if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1153         A_ASSERT(false);
1154         return A_EPROTO;
1155     }
1156 
1157         /* on first entry copy the lookaheads into our temp array for processing */
1158     memcpy(lookAheads, MsgLookAheads, (sizeof(u32)) * NumLookAheads);
1159 
1160     while (true) {
1161 
1162             /* reset packets queues */
1163         INIT_HTC_PACKET_QUEUE(&recvPktQueue);
1164         INIT_HTC_PACKET_QUEUE(&syncCompletedPktsQueue);
1165 
1166         if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
1167             status = A_EPROTO;
1168             A_ASSERT(false);
1169             break;
1170         }
1171 
1172             /* first lookahead sets the expected endpoint IDs for all packets in a bundle */
1173         id = ((struct htc_frame_hdr *)&lookAheads[0])->EndpointID;
1174         pEndpoint = &target->EndPoint[id];
1175 
1176         if (id >= ENDPOINT_MAX) {
1177             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MsgPend, Invalid Endpoint in look-ahead: %d \n",id));
1178             status = A_EPROTO;
1179             break;
1180         }
1181 
1182             /* try to allocate as many HTC RX packets indicated by the lookaheads
1183              * these packets are stored in the recvPkt queue */
1184         status = AllocAndPrepareRxPackets(target,
1185                                           lookAheads,
1186                                           NumLookAheads,
1187                                           pEndpoint,
1188                                           &recvPktQueue);
1189         if (status) {
1190             break;
1191         }
1192 
1193         if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) >= 2) {
1194                 /* a recv bundle was detected, force IRQ status re-check again */
1195             REF_IRQ_STATUS_RECHECK(&target->Device);
1196         }
1197 
1198         totalFetched += HTC_PACKET_QUEUE_DEPTH(&recvPktQueue);
1199 
1200             /* we've got packet buffers for all we can currently fetch,
1201              * this count is not valid anymore  */
1202         NumLookAheads = 0;
1203         partialBundle = false;
1204 
1205             /* now go fetch the list of HTC packets */
1206         while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
1207 
1208             pktsFetched = 0;
1209 
1210             if (target->RecvBundlingEnabled && (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 1)) {
1211                     /* there are enough packets to attempt a bundle transfer and recv bundling is allowed  */
1212                 status = HTCIssueRecvPacketBundle(target,
1213                                                   &recvPktQueue,
1214                                                   asyncProc ? NULL : &syncCompletedPktsQueue,
1215                                                   &pktsFetched,
1216                                                   partialBundle);
1217                 if (status) {
1218                     break;
1219                 }
1220 
1221                 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) != 0) {
1222                         /* we couldn't fetch all packets at one time, this creates a broken
1223                          * bundle  */
1224                     partialBundle = true;
1225                 }
1226             }
1227 
1228                 /* see if the previous operation fetched any packets using bundling */
1229             if (0 == pktsFetched) {
1230                     /* dequeue one packet */
1231                 pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
1232                 A_ASSERT(pPacket != NULL);
1233 
1234                 if (asyncProc) {
1235                         /* we use async mode to get the packet if the device layer supports it
1236                          * set our callback and context */
1237                     pPacket->Completion = HTCRecvCompleteHandler;
1238                     pPacket->pContext = target;
1239                 } else {
1240                         /* fully synchronous */
1241                     pPacket->Completion = NULL;
1242                 }
1243 
1244                 if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 0) {
1245                         /* lookaheads in all packets except the last one in the bundle must be ignored */
1246                     pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
1247                 }
1248 
1249                     /* go fetch the packet */
1250                 status = HTCIssueRecv(target, pPacket);
1251                 if (status) {
1252                     break;
1253                 }
1254 
1255                 if (!asyncProc) {
1256                         /* sent synchronously, queue this packet for synchronous completion */
1257                     HTC_PACKET_ENQUEUE(&syncCompletedPktsQueue,pPacket);
1258                 }
1259 
1260             }
1261 
1262         }
1263 
1264         if (!status) {
1265             CheckRecvWaterMark(pEndpoint);
1266         }
1267 
1268         if (asyncProc) {
1269                 /* we did this asynchronously so we can get out of the loop, the asynch processing
1270                  * creates a chain of requests to continue processing pending messages in the
1271                  * context of callbacks  */
1272             break;
1273         }
1274 
1275             /* synchronous handling */
1276         if (target->Device.DSRCanYield) {
1277                 /* for the SYNC case, increment count that tracks when the DSR should yield */
1278             target->Device.CurrentDSRRecvCount++;
1279         }
1280 
1281             /* in the sync case, all packet buffers are now filled,
1282              * we can process each packet, check lookaheads and then repeat */
1283 
1284              /* unload sync completion queue */
1285         while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1286             struct htc_packet_queue    container;
1287 
1288             pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
1289             A_ASSERT(pPacket != NULL);
1290 
1291             pEndpoint = &target->EndPoint[pPacket->Endpoint];
1292                 /* reset count on each iteration, we are only interested in the last packet's lookahead
1293                  * information when we break out of this loop */
1294             NumLookAheads = 0;
1295                 /* process header for each of the recv packets
1296                  * note: the lookahead of the last packet is useful for us to continue in this loop */
1297             status = HTCProcessRecvHeader(target,pPacket,lookAheads,&NumLookAheads);
1298             if (status) {
1299                 break;
1300             }
1301 
1302             if (HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1303                     /* last packet's more packets flag is set based on the lookahead */
1304                 SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,NumLookAheads,pEndpoint,pPacket);
1305             } else {
1306                     /* packets in a bundle automatically have this flag set */
1307                 FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
1308             }
1309                 /* good packet, indicate it */
1310             HTC_RX_STAT_PROFILE(target,pEndpoint,NumLookAheads);
1311 
1312             if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_PART_OF_BUNDLE) {
1313                 INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
1314             }
1315 
1316             INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
1317             DO_RCV_COMPLETION(pEndpoint,&container);
1318         }
1319 
1320         if (status) {
1321             break;
1322         }
1323 
1324         if (NumLookAheads == 0) {
1325                 /* no more look aheads */
1326             break;
1327         }
1328 
1329             /* when we process recv synchronously we need to check if we should yield and stop
1330              * fetching more packets indicated by the embedded lookaheads */
1331         if (target->Device.DSRCanYield) {
1332             if (DEV_CHECK_RECV_YIELD(&target->Device)) {
1333                     /* break out, don't fetch any more packets */
1334                 break;
1335             }
1336         }
1337 
1338 
1339         /* check whether other OS contexts have queued any WMI command/data for WLAN.
1340          * This check is needed only if WLAN Tx and Rx happens in same thread context */
1341         A_CHECK_DRV_TX();
1342 
1343             /* for SYNCH processing, if we get here, we are running through the loop again due to a detected lookahead.
1344              * Set flag that we should re-check IRQ status registers again before leaving IRQ processing,
1345              * this can net better performance in high throughput situations */
1346         REF_IRQ_STATUS_RECHECK(&target->Device);
1347     }
1348 
1349     if (status) {
1350         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1351                         ("Failed to get pending recv messages (%d) \n",status));
1352             /* cleanup any packets we allocated but didn't use to actually fetch any packets */
1353         while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
1354             pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
1355                 /* clean up packets */
1356             HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
1357         }
1358             /* cleanup any packets in sync completion queue */
1359         while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
1360             pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
1361                 /* clean up packets */
1362             HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
1363         }
1364         if  (HTC_STOPPING(target)) {
1365             AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1366                 (" Host is going to stop. blocking receiver for HTCStop.. \n"));
1367             DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
1368         }
1369     }
1370         /* before leaving, check to see if host ran out of buffers and needs to stop the
1371          * receiver */
1372     if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1373         AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1374                 (" Host has no RX buffers, blocking receiver to prevent overrun.. \n"));
1375             /* try to stop receive at the device layer */
1376         DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
1377     }
1378 
1379     if (pNumPktsFetched != NULL) {
1380         *pNumPktsFetched = totalFetched;
1381     }
1382 
1383     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
1384 
1385     return status;
1386 }
1387 
HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle,struct htc_packet_queue * pPktQueue)1388 int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
1389 {
1390     struct htc_target      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1391     struct htc_endpoint    *pEndpoint;
1392     bool          unblockRecv = false;
1393     int        status = 0;
1394     struct htc_packet      *pFirstPacket;
1395 
1396     pFirstPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
1397 
1398     if (NULL == pFirstPacket) {
1399         A_ASSERT(false);
1400         return A_EINVAL;
1401     }
1402 
1403     AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
1404 
1405     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
1406                     ("+- HTCAddReceivePktMultiple : endPointId: %d, cnt:%d, length: %d\n",
1407                     pFirstPacket->Endpoint,
1408                     HTC_PACKET_QUEUE_DEPTH(pPktQueue),
1409                     pFirstPacket->BufferLength));
1410 
1411     do {
1412 
1413         pEndpoint = &target->EndPoint[pFirstPacket->Endpoint];
1414 
1415         LOCK_HTC_RX(target);
1416 
1417         if (HTC_STOPPING(target)) {
1418             struct htc_packet *pPacket;
1419 
1420             UNLOCK_HTC_RX(target);
1421 
1422                 /* walk through queue and mark each one canceled */
1423             HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
1424                 pPacket->Status = A_ECANCELED;
1425             } HTC_PACKET_QUEUE_ITERATE_END;
1426 
1427             DO_RCV_COMPLETION(pEndpoint,pPktQueue);
1428             break;
1429         }
1430 
1431             /* store receive packets */
1432         HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBuffers, pPktQueue);
1433 
1434             /* check if we are blocked waiting for a new buffer */
1435         if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1436             if (target->EpWaitingForBuffers == pFirstPacket->Endpoint) {
1437                 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
1438                     target->EpWaitingForBuffers));
1439                 target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
1440                 target->EpWaitingForBuffers = ENDPOINT_MAX;
1441                 unblockRecv = true;
1442             }
1443         }
1444 
1445         UNLOCK_HTC_RX(target);
1446 
1447         if (unblockRecv && !HTC_STOPPING(target)) {
1448                 /* TODO : implement a buffer threshold count? */
1449             DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1450         }
1451 
1452     } while (false);
1453 
1454     return status;
1455 }
1456 
1457 /* Makes a buffer available to the HTC module */
HTCAddReceivePkt(HTC_HANDLE HTCHandle,struct htc_packet * pPacket)1458 int HTCAddReceivePkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
1459 {
1460     struct htc_packet_queue queue;
1461     INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
1462     return HTCAddReceivePktMultiple(HTCHandle, &queue);
1463 }
1464 
HTCUnblockRecv(HTC_HANDLE HTCHandle)1465 void HTCUnblockRecv(HTC_HANDLE HTCHandle)
1466 {
1467     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1468     bool      unblockRecv = false;
1469 
1470     LOCK_HTC_RX(target);
1471 
1472         /* check if we are blocked waiting for a new buffer */
1473     if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
1474         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HTCUnblockRx : receiver was blocked on ep:%d, unblocking.. \n",
1475             target->EpWaitingForBuffers));
1476         target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
1477         target->EpWaitingForBuffers = ENDPOINT_MAX;
1478         unblockRecv = true;
1479     }
1480 
1481     UNLOCK_HTC_RX(target);
1482 
1483     if (unblockRecv && !HTC_STOPPING(target)) {
1484             /* re-enable */
1485         DevEnableRecv(&target->Device,DEV_ENABLE_RECV_ASYNC);
1486     }
1487 }
1488 
HTCFlushRxQueue(struct htc_target * target,struct htc_endpoint * pEndpoint,struct htc_packet_queue * pQueue)1489 static void HTCFlushRxQueue(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet_queue *pQueue)
1490 {
1491     struct htc_packet  *pPacket;
1492     struct htc_packet_queue container;
1493 
1494     LOCK_HTC_RX(target);
1495 
1496     while (1) {
1497         pPacket = HTC_PACKET_DEQUEUE(pQueue);
1498         if (NULL == pPacket) {
1499             break;
1500         }
1501         UNLOCK_HTC_RX(target);
1502         pPacket->Status = A_ECANCELED;
1503         pPacket->ActualLength = 0;
1504         AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("  Flushing RX packet:0x%lX, length:%d, ep:%d \n",
1505                 (unsigned long)pPacket, pPacket->BufferLength, pPacket->Endpoint));
1506         INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
1507             /* give the packet back */
1508         DO_RCV_COMPLETION(pEndpoint,&container);
1509         LOCK_HTC_RX(target);
1510     }
1511 
1512     UNLOCK_HTC_RX(target);
1513 }
1514 
HTCFlushEndpointRX(struct htc_target * target,struct htc_endpoint * pEndpoint)1515 static void HTCFlushEndpointRX(struct htc_target *target, struct htc_endpoint *pEndpoint)
1516 {
1517         /* flush any recv indications not already made */
1518     HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RecvIndicationQueue);
1519         /* flush any rx buffers */
1520     HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RxBuffers);
1521 }
1522 
HTCFlushRecvBuffers(struct htc_target * target)1523 void HTCFlushRecvBuffers(struct htc_target *target)
1524 {
1525     struct htc_endpoint    *pEndpoint;
1526     int             i;
1527 
1528     for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
1529         pEndpoint = &target->EndPoint[i];
1530         if (pEndpoint->ServiceID == 0) {
1531                 /* not in use.. */
1532             continue;
1533         }
1534         HTCFlushEndpointRX(target,pEndpoint);
1535     }
1536 }
1537 
1538 
HTCEnableRecv(HTC_HANDLE HTCHandle)1539 void HTCEnableRecv(HTC_HANDLE HTCHandle)
1540 {
1541     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1542 
1543     if (!HTC_STOPPING(target)) {
1544             /* re-enable */
1545         DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1546     }
1547 }
1548 
HTCDisableRecv(HTC_HANDLE HTCHandle)1549 void HTCDisableRecv(HTC_HANDLE HTCHandle)
1550 {
1551     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1552 
1553     if (!HTC_STOPPING(target)) {
1554             /* disable */
1555         DevStopRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
1556     }
1557 }
1558 
HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint)1559 int HTCGetNumRecvBuffers(HTC_HANDLE      HTCHandle,
1560                          HTC_ENDPOINT_ID Endpoint)
1561 {
1562     struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1563     return HTC_PACKET_QUEUE_DEPTH(&(target->EndPoint[Endpoint].RxBuffers));
1564 }
1565 
HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,u32 TimeoutInMs,bool * pbIsRecvPending)1566 int HTCWaitForPendingRecv(HTC_HANDLE   HTCHandle,
1567                                u32 TimeoutInMs,
1568                                bool      *pbIsRecvPending)
1569 {
1570     int    status  = 0;
1571     struct htc_target *target  = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1572 
1573     status = DevWaitForPendingRecv(&target->Device,
1574                                     TimeoutInMs,
1575                                     pbIsRecvPending);
1576 
1577     return status;
1578 }
1579