staging: ath6kl: s|A_MEMCPY|memcpy|g
[deliverable/linux.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 #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
53 static void DoRecvCompletion(HTC_ENDPOINT *pEndpoint,
54 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 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
86 static INLINE int HTCProcessTrailer(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 */
229 static int HTCProcessRecvHeader(HTC_TARGET *target,
230 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, 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, HTC_FRAME_HDR, EndpointID)) {
281 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
282 ("Refreshed HDR endpoint (%d) does not match expected endpoint (%d) \n",
283 A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, EndpointID), pPacket->Endpoint));
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(HTC_FRAME_HDR),"Current Frame Header");
298 #ifdef HTC_CAPTURE_LAST_FRAME
299 DebugDumpBytes((u8 *)&target->LastFrameHdr,sizeof(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, 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, 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(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
388 static INLINE void HTCAsyncRecvCheckMorePackets(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 */
435 static INLINE void DrainRecvIndicationQueue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
436 {
437 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 */
499 static INLINE void SetRxPacketIndicationFlags(u32 LookAhead,
500 HTC_ENDPOINT *pEndpoint,
501 HTC_PACKET *pPacket)
502 {
503 HTC_FRAME_HDR *pHdr = (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 */
518 void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket)
519 {
520 HTC_TARGET *target = (HTC_TARGET *)Context;
521 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. */
590 int HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket)
591 {
592 int status;
593 u32 lookAhead;
594 HTC_PACKET *pPacket = NULL;
595 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 = (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
689 static int AllocAndPrepareRxPackets(HTC_TARGET *target,
690 u32 LookAheads[],
691 int Messages,
692 HTC_ENDPOINT *pEndpoint,
693 HTC_PACKET_QUEUE *pQueue)
694 {
695 int status = 0;
696 HTC_PACKET *pPacket;
697 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 = (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(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
882 static void HTCAsyncRecvScatterCompletion(HIF_SCATTER_REQ *pScatterReq)
883 {
884 int i;
885 HTC_PACKET *pPacket;
886 HTC_ENDPOINT *pEndpoint;
887 u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
888 int numLookAheads = 0;
889 HTC_TARGET *target = (HTC_TARGET *)pScatterReq->Context;
890 int status;
891 bool partialBundle = false;
892 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 = (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 = (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
987 static int HTCIssueRecvPacketBundle(HTC_TARGET *target,
988 HTC_PACKET_QUEUE *pRecvPktQueue,
989 HTC_PACKET_QUEUE *pSyncCompletionQueue,
990 int *pNumPacketsFetched,
991 bool PartialBundle)
992 {
993 int status = 0;
994 HIF_SCATTER_REQ *pScatterReq;
995 int i, totalLength;
996 int pktsToScatter;
997 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
1105 static INLINE void CheckRecvWaterMark(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 */
1120 int HTCRecvMessagePendingHandler(void *Context, u32 MsgLookAheads[], int NumLookAheads, bool *pAsyncProc, int *pNumPktsFetched)
1121 {
1122 HTC_TARGET *target = (HTC_TARGET *)Context;
1123 int status = 0;
1124 HTC_PACKET *pPacket;
1125 HTC_ENDPOINT *pEndpoint;
1126 bool asyncProc = false;
1127 u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
1128 int pktsFetched;
1129 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 = ((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 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
1388 int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue)
1389 {
1390 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1391 HTC_ENDPOINT *pEndpoint;
1392 bool unblockRecv = false;
1393 int status = 0;
1394 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 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 */
1458 int HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
1459 {
1460 HTC_PACKET_QUEUE queue;
1461 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
1462 return HTCAddReceivePktMultiple(HTCHandle, &queue);
1463 }
1464
1465 void HTCUnblockRecv(HTC_HANDLE HTCHandle)
1466 {
1467 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
1489 static void HTCFlushRxQueue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_PACKET_QUEUE *pQueue)
1490 {
1491 HTC_PACKET *pPacket;
1492 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
1515 static void HTCFlushEndpointRX(HTC_TARGET *target, 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
1523 void HTCFlushRecvBuffers(HTC_TARGET *target)
1524 {
1525 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
1539 void HTCEnableRecv(HTC_HANDLE HTCHandle)
1540 {
1541 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
1549 void HTCDisableRecv(HTC_HANDLE HTCHandle)
1550 {
1551 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
1559 int HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle,
1560 HTC_ENDPOINT_ID Endpoint)
1561 {
1562 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1563 return HTC_PACKET_QUEUE_DEPTH(&(target->EndPoint[Endpoint].RxBuffers));
1564 }
1565
1566 int HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,
1567 u32 TimeoutInMs,
1568 bool *pbIsRecvPending)
1569 {
1570 int status = 0;
1571 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1572
1573 status = DevWaitForPendingRecv(&target->Device,
1574 TimeoutInMs,
1575 pbIsRecvPending);
1576
1577 return status;
1578 }
This page took 0.078151 seconds and 5 git commands to generate.