Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: chromeos/drivers/ath6kl/htc2/htc_recv.c

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

Powered by Google App Engine
This is Rietveld 408576698