OLD | NEW |
(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 |
OLD | NEW |