OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------ |
| 2 // <copyright file="htc_send.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 typedef enum _HTC_SEND_QUEUE_RESULT { |
| 22 HTC_SEND_QUEUE_OK = 0, /* packet was queued */ |
| 23 HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */ |
| 24 } HTC_SEND_QUEUE_RESULT; |
| 25 |
| 26 #define DO_EP_TX_COMPLETION(ep,q) DoSendCompletion(ep,q) |
| 27 |
| 28 /* call the distribute credits callback with the distribution */ |
| 29 #define DO_DISTRIBUTION(t,reason,description,pList) \ |
| 30 { \ |
| 31 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \ |
| 32 (" calling distribute function (%s) (dfn:0x%X, ctxt:0x%X, dist:0x%X) \n
", \ |
| 33 (description), \ |
| 34 (A_UINT32)(t)->DistributeCredits, \ |
| 35 (A_UINT32)(t)->pCredDistContext, \ |
| 36 (A_UINT32)pList)); \ |
| 37 (t)->DistributeCredits((t)->pCredDistContext, \ |
| 38 (pList), \ |
| 39 (reason)); \ |
| 40 } |
| 41 |
| 42 static void DoSendCompletion(HTC_ENDPOINT *pEndpoint, |
| 43 HTC_PACKET_QUEUE *pQueueToIndicate) |
| 44 { |
| 45 do { |
| 46 |
| 47 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { |
| 48 /* nothing to indicate */ |
| 49 break; |
| 50 } |
| 51 |
| 52 if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) { |
| 53 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d, send complete
multiple callback (%d pkts) \n", |
| 54 pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate))); |
| 55 /* a multiple send complete handler is being used, pass the queu
e to the handler */ |
| 56 pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint->EpCallBacks.p
Context, |
| 57 pQueueToIndicate); |
| 58 /* all packets are now owned by the callback, reset queue to be
safe */ |
| 59 INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
|
| 60 } else { |
| 61 HTC_PACKET *pPacket; |
| 62 /* using legacy EpTxComplete */ |
| 63 do { |
| 64 pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate); |
| 65 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d send comple
te callback on packet 0x%X \n", \ |
| 66 pEndpoint->Id, (A_UINT32)(pPacket))); |
| 67 pEndpoint->EpCallBacks.EpTxComplete(pEndpoint->EpCallBacks.pCont
ext, pPacket); |
| 68 } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
|
| 69 } |
| 70 |
| 71 } while (FALSE); |
| 72 |
| 73 } |
| 74 |
| 75 /* do final completion on sent packet */ |
| 76 static INLINE void CompleteSentPacket(HTC_TARGET *target, HTC_ENDPOINT *pEndpoin
t, HTC_PACKET *pPacket) |
| 77 { |
| 78 pPacket->Completion = NULL; |
| 79 |
| 80 if (A_FAILED(pPacket->Status)) { |
| 81 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| 82 ("CompleteSentPacket: request failed (status:%d, ep:%d, length:%d cr
eds:%d) \n", |
| 83 pPacket->Status, pPacket->Endpoint, pPacket->ActualLength, pPack
et->PktInfo.AsTx.CreditsUsed)); |
| 84 /* on failure to submit, reclaim credits for this packet */ |
| 85 LOCK_HTC_TX(target); |
| 86 pEndpoint->CreditDist.TxCreditsToDist += pPacket->PktInfo.AsTx.CreditsUs
ed; |
| 87 pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
TxQueue); |
| 88 DO_DISTRIBUTION(target, |
| 89 HTC_CREDIT_DIST_SEND_COMPLETE, |
| 90 "Send Complete", |
| 91 target->EpCreditDistributionListHead->pNext); |
| 92 UNLOCK_HTC_TX(target); |
| 93 } |
| 94 /* first, fixup the head room we allocated */ |
| 95 pPacket->pBuffer += HTC_HDR_LENGTH; |
| 96 } |
| 97 |
| 98 /* our internal send packet completion handler when packets are submited to the
AR6K device |
| 99 * layer */ |
| 100 static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket) |
| 101 { |
| 102 HTC_TARGET *target = (HTC_TARGET *)Context; |
| 103 HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint]; |
| 104 HTC_PACKET_QUEUE container; |
| 105 |
| 106 CompleteSentPacket(target,pEndpoint,pPacket); |
| 107 INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket); |
| 108 /* do completion */ |
| 109 DO_EP_TX_COMPLETION(pEndpoint,&container); |
| 110 } |
| 111 |
| 112 A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket) |
| 113 { |
| 114 A_STATUS status; |
| 115 A_BOOL sync = FALSE; |
| 116 |
| 117 if (pPacket->Completion == NULL) { |
| 118 /* mark that this request was synchronously issued */ |
| 119 sync = TRUE; |
| 120 } |
| 121 |
| 122 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, |
| 123 ("+-HTCIssueSend: transmit length : %d (%s) \n", |
| 124 pPacket->ActualLength + HTC_HDR_LENGTH, |
| 125 sync ? "SYNC" : "ASYNC" )); |
| 126 |
| 127 /* send message to device */ |
| 128 status = DevSendPacket(&target->Device, |
| 129 pPacket, |
| 130 pPacket->ActualLength + HTC_HDR_LENGTH); |
| 131 |
| 132 if (sync) { |
| 133 /* use local sync variable. If this was issued asynchronously, pPac
ket is no longer |
| 134 * safe to access. */ |
| 135 pPacket->pBuffer += HTC_HDR_LENGTH; |
| 136 } |
| 137 |
| 138 /* if this request was asynchronous, the packet completion routine will be i
nvoked by |
| 139 * the device layer when the HIF layer completes the request */ |
| 140 |
| 141 return status; |
| 142 } |
| 143 |
| 144 /* get HTC send packets from the TX queue on an endpoint */ |
| 145 static INLINE void GetHTCSendPackets(HTC_TARGET *target, |
| 146 HTC_ENDPOINT *pEndpoint, |
| 147 HTC_PACKET_QUEUE *pQueue) |
| 148 { |
| 149 int creditsRequired; |
| 150 int remainder; |
| 151 A_UINT8 sendFlags; |
| 152 HTC_PACKET *pPacket; |
| 153 int transferLength; |
| 154 |
| 155 /****** NOTE : the TX lock is held when this function is called ************
*****/ |
| 156 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+GetHTCSendPackets \n")); |
| 157 |
| 158 /* loop until we can grab as many packets out of the queue as we can */
|
| 159 while (TRUE) { |
| 160 |
| 161 sendFlags = 0; |
| 162 /* get packet at head, but don't remove it */ |
| 163 pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue); |
| 164 if (pPacket == NULL) { |
| 165 break; |
| 166 } |
| 167 |
| 168 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%X , Queue Depth: %d
\n", |
| 169 (A_UINT32)pPacket, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)))
; |
| 170 |
| 171 transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, pPacket->Actu
alLength + HTC_HDR_LENGTH); |
| 172 |
| 173 if (transferLength <= target->TargetCreditSize) { |
| 174 creditsRequired = 1; |
| 175 } else { |
| 176 /* figure out how many credits this message requires */ |
| 177 creditsRequired = transferLength / target->TargetCreditSize; |
| 178 remainder = transferLength % target->TargetCreditSize; |
| 179 |
| 180 if (remainder) { |
| 181 creditsRequired++; |
| 182 } |
| 183 } |
| 184 |
| 185 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n", |
| 186 creditsRequired, pEndpoint->CreditDist.TxCredits)); |
| 187 |
| 188 if (pEndpoint->CreditDist.TxCredits < creditsRequired) { |
| 189 |
| 190 /* not enough credits */ |
| 191 if (pPacket->Endpoint == ENDPOINT_0) { |
| 192 /* leave it in the queue */ |
| 193 break; |
| 194 } |
| 195 /* invoke the registered distribution function only if this is n
ot |
| 196 * endpoint 0, we let the driver layer provide more credits if i
t can. |
| 197 * We pass the credit distribution list starting at the endpoint
in question |
| 198 * */ |
| 199 |
| 200 /* set how many credits we need */ |
| 201 pEndpoint->CreditDist.TxCreditsSeek = |
| 202 creditsRequired - pEndpoint->CreditDist.TxCr
edits; |
| 203 DO_DISTRIBUTION(target, |
| 204 HTC_CREDIT_DIST_SEEK_CREDITS, |
| 205 "Seek Credits", |
| 206 &pEndpoint->CreditDist); |
| 207 pEndpoint->CreditDist.TxCreditsSeek = 0; |
| 208 |
| 209 if (pEndpoint->CreditDist.TxCredits < creditsRequired) { |
| 210 /* still not enough credits to send, leave packet in the que
ue */ |
| 211 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, |
| 212 (" Not enough credits for ep %d leaving packet in queue..\n"
, |
| 213 pPacket->Endpoint)); |
| 214 break; |
| 215 } |
| 216 |
| 217 } |
| 218 |
| 219 pEndpoint->CreditDist.TxCredits -= creditsRequired; |
| 220 INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired); |
| 221 |
| 222 /* check if we need credits back from the target */ |
| 223 if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPer
MaxMsg) { |
| 224 /* we are getting low on credits, see if we can ask for more fro
m the distribution function */ |
| 225 pEndpoint->CreditDist.TxCreditsSeek = |
| 226 pEndpoint->CreditDist.TxCreditsPerMaxMsg - pEndpoint->Cr
editDist.TxCredits; |
| 227 |
| 228 DO_DISTRIBUTION(target, |
| 229 HTC_CREDIT_DIST_SEEK_CREDITS, |
| 230 "Seek Credits", |
| 231 &pEndpoint->CreditDist); |
| 232 |
| 233 pEndpoint->CreditDist.TxCreditsSeek = 0; |
| 234 /* see if we were successful in getting more */ |
| 235 if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCredit
sPerMaxMsg) { |
| 236 /* tell the target we need credits ASAP! */ |
| 237 sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; |
| 238 INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1); |
| 239 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n")); |
| 240 } |
| 241 } |
| 242 |
| 243 /* now we can fully dequeue */ |
| 244 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue); |
| 245 /* save the number of credits this packet consumed */ |
| 246 pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; |
| 247 /* all TX packets are handled asynchronously */ |
| 248 pPacket->Completion = HTCSendPktCompletionHandler; |
| 249 pPacket->pContext = target; |
| 250 INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); |
| 251 /* save send flags */ |
| 252 pPacket->PktInfo.AsTx.SendFlags = sendFlags; |
| 253 pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; |
| 254 pEndpoint->SeqNo++; |
| 255 /* queue this packet into the caller's queue */ |
| 256 HTC_PACKET_ENQUEUE(pQueue,pPacket); |
| 257 } |
| 258 |
| 259 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-GetHTCSendPackets \n")); |
| 260 |
| 261 } |
| 262 |
| 263 static void HTCAsyncSendScatterCompletion(HIF_SCATTER_REQ *pScatterReq) |
| 264 { |
| 265 int i; |
| 266 HTC_PACKET *pPacket; |
| 267 HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *)pScatterReq->Context; |
| 268 HTC_TARGET *target = (HTC_TARGET *)pEndpoint->target; |
| 269 A_STATUS status = A_OK; |
| 270 HTC_PACKET_QUEUE sendCompletes; |
| 271 |
| 272 INIT_HTC_PACKET_QUEUE(&sendCompletes); |
| 273 |
| 274 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCAsyncSendScatterCompletion TotLen: %d
Entries: %d\n", |
| 275 pScatterReq->TotalLength, pScatterReq->ValidScatterEntries)); |
| 276 |
| 277 DEV_FINISH_SCATTER_OPERATION(pScatterReq); |
| 278 |
| 279 if (A_FAILED(pScatterReq->CompletionStatus)) { |
| 280 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Send Scatter Request Failed: %d \n",p
ScatterReq->CompletionStatus)); |
| 281 status = A_ERROR; |
| 282 } |
| 283 |
| 284 /* walk through the scatter list and process */ |
| 285 for (i = 0; i < pScatterReq->ValidScatterEntries; i++) { |
| 286 pPacket = (HTC_PACKET *)(pScatterReq->ScatterList[i].pCallerContexts[0])
; |
| 287 A_ASSERT(pPacket != NULL); |
| 288 pPacket->Status = status; |
| 289 CompleteSentPacket(target,pEndpoint,pPacket); |
| 290 /* add it to the completion queue */ |
| 291 HTC_PACKET_ENQUEUE(&sendCompletes, pPacket); |
| 292 } |
| 293 |
| 294 /* free scatter request */ |
| 295 DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq); |
| 296 /* complete all packets */ |
| 297 DO_EP_TX_COMPLETION(pEndpoint,&sendCompletes); |
| 298 |
| 299 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCAsyncSendScatterCompletion \n")); |
| 300 } |
| 301 |
| 302 /* drain a queue and send as bundles |
| 303 * this function may return without fully draining the queue under the follo
wing conditions : |
| 304 * - scatter resources are exhausted |
| 305 * - a message that will consume a partial credit will stop the bundling
process early |
| 306 * - we drop below the minimum number of messages for a bundle |
| 307 * */ |
| 308 static void HTCIssueSendBundle(HTC_ENDPOINT *pEndpoint, |
| 309 HTC_PACKET_QUEUE *pQueue, |
| 310 int *pBundlesSent, |
| 311 int *pTotalBundlesPkts) |
| 312 { |
| 313 int pktsToScatter; |
| 314 int scatterSpaceRemaining; |
| 315 HIF_SCATTER_REQ *pScatterReq = NULL; |
| 316 int i, packetsInScatterReq; |
| 317 int transferLength; |
| 318 HTC_PACKET *pPacket; |
| 319 A_BOOL done = FALSE; |
| 320 int bundlesSent = 0; |
| 321 int totalPktsInBundle = 0; |
| 322 HTC_TARGET *target = pEndpoint->target; |
| 323 int creditRemainder = 0; |
| 324 int creditPad; |
| 325 |
| 326 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCIssueSendBundle \n")); |
| 327 |
| 328 while (!done) { |
| 329 |
| 330 pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pQueue); |
| 331 pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle); |
| 332 |
| 333 if (pktsToScatter < HTC_MIN_HTC_MSGS_TO_BUNDLE) { |
| 334 /* not enough to bundle */ |
| 335 break; |
| 336 } |
| 337 |
| 338 pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device); |
| 339 |
| 340 if (pScatterReq == NULL) { |
| 341 /* no scatter resources */ |
| 342 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" No more scatter resources \n")); |
| 343 break; |
| 344 } |
| 345 |
| 346 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" pkts to scatter: %d \n", pktsToScatt
er)); |
| 347 |
| 348 pScatterReq->TotalLength = 0; |
| 349 pScatterReq->ValidScatterEntries = 0; |
| 350 |
| 351 packetsInScatterReq = 0; |
| 352 scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device); |
| 353 |
| 354 for (i = 0; i < pktsToScatter; i++) { |
| 355 |
| 356 pScatterReq->ScatterList[i].pCallerContexts[0] = NULL; |
| 357 |
| 358 pPacket = HTC_GET_PKT_AT_HEAD(pQueue); |
| 359 if (pPacket == NULL) { |
| 360 A_ASSERT(FALSE); |
| 361 break; |
| 362 } |
| 363 |
| 364 creditPad = 0; |
| 365 transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, |
| 366 pPacket->ActualLength + HT
C_HDR_LENGTH); |
| 367 /* see if the padded transfer length falls on a credit boundary
*/ |
| 368 creditRemainder = transferLength % target->TargetCreditSize; |
| 369 |
| 370 if (creditRemainder != 0) { |
| 371 /* the transfer consumes a "partial" credit, this packet can
not be bundled unless |
| 372 * we add additional "dummy" padding (max 255 bytes) to cons
ume the entire credit |
| 373 *** NOTE: only allow the send padding if the endpoint is al
lowed to */ |
| 374 if (pEndpoint->LocalConnectionFlags & HTC_LOCAL_CONN_FLAGS_ENABL
E_SEND_BUNDLE_PADDING) { |
| 375 if (transferLength < target->TargetCreditSize) { |
| 376 /* special case where the transfer is less than a cr
edit */ |
| 377 creditPad = target->TargetCreditSize - transferLength;
|
| 378 } else { |
| 379 creditPad = creditRemainder; |
| 380 } |
| 381 |
| 382 /* now check to see if we can indicate padding in the HT
C header */ |
| 383 if ((creditPad > 0) && (creditPad <= 255)) { |
| 384 /* adjust the transferlength of this packet with the
new credit padding */ |
| 385 transferLength += creditPad; |
| 386 } else { |
| 387 /* the amount to pad is too large, bail on this pack
et, we have to |
| 388 * send it using the non-bundled method */ |
| 389 pPacket = NULL; |
| 390 } |
| 391 } else { |
| 392 /* bail on this packet, user does not want padding appli
ed */ |
| 393 pPacket = NULL; |
| 394 } |
| 395 } |
| 396 |
| 397 if (NULL == pPacket) { |
| 398 /* can't bundle */ |
| 399 done = TRUE; |
| 400 break; |
| 401 } |
| 402 |
| 403 if ((scatterSpaceRemaining - transferLength) < 0) { |
| 404 /* exceeds what we can transfer */ |
| 405 break; |
| 406 } |
| 407 |
| 408 scatterSpaceRemaining -= transferLength; |
| 409 /* now remove it from the queue */ |
| 410 pPacket = HTC_PACKET_DEQUEUE(pQueue); |
| 411 /* save it in the scatter list */ |
| 412 pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
|
| 413 /* prepare packet and flag message as part of a send bundle */
|
| 414 HTC_PREPARE_SEND_PKT(pPacket, |
| 415 pPacket->PktInfo.AsTx.SendFlags | HTC_FLAGS_SEN
D_BUNDLE, |
| 416 creditPad, |
| 417 pPacket->PktInfo.AsTx.SeqNo); |
| 418 pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer; |
| 419 pScatterReq->ScatterList[i].Length = transferLength; |
| 420 A_ASSERT(transferLength); |
| 421 pScatterReq->TotalLength += transferLength; |
| 422 pScatterReq->ValidScatterEntries++; |
| 423 packetsInScatterReq++; |
| 424 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" %d, Adding packet : 0x%X, len:%d
(remaining space:%d) \n", |
| 425 i, (A_UINT32)pPacket,transferLength,scatterSpaceRemaining));
|
| 426 } |
| 427 |
| 428 if (packetsInScatterReq >= HTC_MIN_HTC_MSGS_TO_BUNDLE) { |
| 429 /* send path is always asynchronous */ |
| 430 pScatterReq->CompletionRoutine = HTCAsyncSendScatterCompletion; |
| 431 pScatterReq->Context = pEndpoint; |
| 432 bundlesSent++; |
| 433 totalPktsInBundle += packetsInScatterReq; |
| 434 packetsInScatterReq = 0; |
| 435 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Send Scatter total bytes: %d , ent
ries: %d\n", |
| 436 pScatterReq->TotalLength,pScatterReq->ValidScatt
erEntries)); |
| 437 DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_WR
ITE, DEV_SCATTER_ASYNC); |
| 438 /* we don't own this anymore */ |
| 439 pScatterReq = NULL; |
| 440 /* try to send some more */ |
| 441 continue; |
| 442 } |
| 443 |
| 444 /* not enough packets to use the scatter request, cleanup */ |
| 445 if (pScatterReq != NULL) { |
| 446 if (packetsInScatterReq > 0) { |
| 447 /* work backwards to requeue requests */ |
| 448 for (i = (packetsInScatterReq - 1); i >= 0; i--) { |
| 449 pPacket = (HTC_PACKET *)(pScatterReq->ScatterList[i].pCaller
Contexts[0]); |
| 450 if (pPacket != NULL) { |
| 451 /* undo any prep */ |
| 452 HTC_UNPREPARE_SEND_PKT(pPacket); |
| 453 /* queue back to the head */ |
| 454 HTC_PACKET_ENQUEUE_TO_HEAD(pQueue,pPacket); |
| 455 } |
| 456 } |
| 457 } |
| 458 DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq); |
| 459 } |
| 460 |
| 461 /* if we get here, we sent all that we could, get out */ |
| 462 break; |
| 463 |
| 464 } |
| 465 |
| 466 *pBundlesSent = bundlesSent; |
| 467 *pTotalBundlesPkts = totalPktsInBundle; |
| 468 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCIssueSendBundle (sent:%d) \n",bundlesSe
nt)); |
| 469 |
| 470 return; |
| 471 } |
| 472 |
| 473 /* |
| 474 * if there are no credits, the packet(s) remains in the queue. |
| 475 * this function returns the result of the attempt to send a queue of HTC packet
s */ |
| 476 static HTC_SEND_QUEUE_RESULT HTCTrySend(HTC_TARGET *target, |
| 477 HTC_ENDPOINT *pEndpoint, |
| 478 HTC_PACKET_QUEUE *pCallersSendQueue) |
| 479 { |
| 480 HTC_PACKET_QUEUE sendQueue; /* temp queue to hold packets at various st
ages */ |
| 481 HTC_PACKET *pPacket; |
| 482 int bundlesSent; |
| 483 int pktsInBundles; |
| 484 int overflow; |
| 485 HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; |
| 486 |
| 487 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (Queue:0x%X Depth:%d)\n", |
| 488 (A_UINT32)pCallersSendQueue, |
| 489 (pCallersSendQueue == NULL) ? 0 : HTC_PACKET_QUEUE_DEPTH(pCallersSen
dQueue))); |
| 490 |
| 491 /* init the local send queue */ |
| 492 INIT_HTC_PACKET_QUEUE(&sendQueue); |
| 493 |
| 494 do { |
| 495 |
| 496 if (NULL == pCallersSendQueue) { |
| 497 /* caller didn't provide a queue, just wants us to check queues
and send */ |
| 498 break; |
| 499 } |
| 500 |
| 501 if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { |
| 502 /* empty queue */ |
| 503 result = HTC_SEND_QUEUE_DROP; |
| 504 break; |
| 505 } |
| 506 |
| 507 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= pEndpoint->MaxTxQueue
Depth) { |
| 508 /* we've already overflowed */ |
| 509 overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); |
| 510 } else { |
| 511 /* figure out how much we will overflow by */ |
| 512 overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); |
| 513 overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); |
| 514 /* figure out how much we will overflow the TX queue by */ |
| 515 overflow -= pEndpoint->MaxTxQueueDepth; |
| 516 } |
| 517 |
| 518 /* if overflow is negative or zero, we are okay */ |
| 519 if (overflow > 0) { |
| 520 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, |
| 521 (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d
\n", |
| 522 pEndpoint->Id, overflow, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQu
eue), pEndpoint->MaxTxQueueDepth)); |
| 523 } |
| 524 if ((overflow <= 0) || (pEndpoint->EpCallBacks.EpSendFull == NULL)) { |
| 525 /* all packets will fit or caller did not provide send full indi
cation handler |
| 526 * -- just move all of them to the local sendQueue object */ |
| 527 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, pCallersSendQueue);
|
| 528 } else { |
| 529 int i; |
| 530 int goodPkts = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueu
e) - overflow; |
| 531 |
| 532 A_ASSERT(goodPkts >= 0); |
| 533 /* we have overflowed, and a callback is provided */ |
| 534 /* dequeue all non-overflow packets into the sendqueue */ |
| 535 for (i = 0; i < goodPkts; i++) { |
| 536 /* pop off caller's queue*/ |
| 537 pPacket = HTC_PACKET_DEQUEUE(pCallersSendQueue); |
| 538 A_ASSERT(pPacket != NULL); |
| 539 /* insert into local queue */ |
| 540 HTC_PACKET_ENQUEUE(&sendQueue,pPacket); |
| 541 } |
| 542 |
| 543 /* the caller's queue has all the packets that won't fit*/
|
| 544 /* walk through the caller's queue and indicate each one to the
send full handler */ |
| 545 ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->QueueHead, pPacke
t, HTC_PACKET, ListLink) { |
| 546 |
| 547 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Indicating overflowed TX pack
et: 0x%X \n", |
| 548 (A_UINT32)pPacket)); |
| 549 if (pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pCo
ntext, |
| 550 pPacket) == HTC_SEND_FULL_
DROP) { |
| 551 /* callback wants the packet dropped */ |
| 552 INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); |
| 553 /* leave this one in the caller's queue for cleanup */ |
| 554 } else { |
| 555 /* callback wants to keep this packet, remove from calle
r's queue */ |
| 556 HTC_PACKET_REMOVE(pCallersSendQueue, pPacket); |
| 557 /* put it in the send queue */ |
| 558 HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
|
| 559 } |
| 560 |
| 561 } ITERATE_END; |
| 562 |
| 563 if (HTC_QUEUE_EMPTY(&sendQueue)) { |
| 564 /* no packets made it in, caller will cleanup */ |
| 565 result = HTC_SEND_QUEUE_DROP; |
| 566 break; |
| 567 } |
| 568 } |
| 569 |
| 570 } while (FALSE); |
| 571 |
| 572 if (result != HTC_SEND_QUEUE_OK) { |
| 573 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n")); |
| 574 return result; |
| 575 } |
| 576 |
| 577 LOCK_HTC_TX(target); |
| 578 |
| 579 if (!HTC_QUEUE_EMPTY(&sendQueue)) { |
| 580 /* transfer packets */ |
| 581 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,&sendQueue); |
| 582 A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); |
| 583 INIT_HTC_PACKET_QUEUE(&sendQueue); |
| 584 } |
| 585 |
| 586 /* increment tx processing count on entry */ |
| 587 pEndpoint->TxProcessCount++; |
| 588 if (pEndpoint->TxProcessCount > 1) { |
| 589 /* another thread or task is draining the TX queues on this endpoint |
| 590 * that thread will reset the tx processing count when the queue is
drained */ |
| 591 pEndpoint->TxProcessCount--; |
| 592 UNLOCK_HTC_TX(target); |
| 593 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend (busy) \n")); |
| 594 return HTC_SEND_QUEUE_OK; |
| 595 } |
| 596 |
| 597 /***** beyond this point only 1 thread may enter ******/ |
| 598 |
| 599 /* now drain the endpoint TX queue for transmission as long as we have e
nough |
| 600 * credits */ |
| 601 while (TRUE) { |
| 602 |
| 603 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) { |
| 604 break; |
| 605 } |
| 606 |
| 607 /* get all the packets for this endpoint that we can for this pass *
/ |
| 608 GetHTCSendPackets(target, pEndpoint, &sendQueue); |
| 609 |
| 610 if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { |
| 611 /* didn't get any packets due to a lack of credits */ |
| 612 break; |
| 613 } |
| 614 |
| 615 UNLOCK_HTC_TX(target); |
| 616 |
| 617 /* any packets to send are now in our local send queue */ |
| 618 |
| 619 bundlesSent = 0; |
| 620 pktsInBundles = 0; |
| 621 |
| 622 while (TRUE) { |
| 623 |
| 624 /* try to send a bundle on each pass */ |
| 625 if ((target->SendBundlingEnabled) && |
| 626 (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= HTC_MIN_HTC_MSGS_TO_B
UNDLE)) { |
| 627 int temp1,temp2; |
| 628 /* bundling is enabled and there is at least a minimum numbe
r of packets in the send queue |
| 629 * send what we can in this pass */ |
| 630 HTCIssueSendBundle(pEndpoint, &sendQueue, &temp1, &temp2); |
| 631 bundlesSent += temp1; |
| 632 pktsInBundles += temp2; |
| 633 } |
| 634 |
| 635 /* if not bundling or there was a packet that could not be place
d in a bundle, pull it out |
| 636 * and send it the normal way */ |
| 637 pPacket = HTC_PACKET_DEQUEUE(&sendQueue); |
| 638 if (NULL == pPacket) { |
| 639 /* local queue is fully drained */ |
| 640 break; |
| 641 } |
| 642 HTC_PREPARE_SEND_PKT(pPacket, |
| 643 pPacket->PktInfo.AsTx.SendFlags, |
| 644 0, |
| 645 pPacket->PktInfo.AsTx.SeqNo); |
| 646 HTCIssueSend(target, pPacket); |
| 647 |
| 648 /* go back and see if we can bundle some more */ |
| 649 } |
| 650 |
| 651 LOCK_HTC_TX(target); |
| 652 |
| 653 INC_HTC_EP_STAT(pEndpoint, TxBundles, bundlesSent); |
| 654 INC_HTC_EP_STAT(pEndpoint, TxPacketsBundled, pktsInBundles); |
| 655 |
| 656 } |
| 657 |
| 658 /* done with this endpoint, we can clear the count */ |
| 659 pEndpoint->TxProcessCount = 0; |
| 660 UNLOCK_HTC_TX(target); |
| 661 |
| 662 AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n")); |
| 663 |
| 664 return HTC_SEND_QUEUE_OK; |
| 665 } |
| 666 |
| 667 A_STATUS HTCSendPktsMultiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue) |
| 668 { |
| 669 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 670 HTC_ENDPOINT *pEndpoint; |
| 671 HTC_PACKET *pPacket; |
| 672 |
| 673 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCSendPktsMultiple: Queue: 0x%X, Pkts %d
\n", |
| 674 (A_UINT32)pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue))); |
| 675 |
| 676 /* get packet at head to figure out which endpoint these packets will go
into */ |
| 677 pPacket = HTC_GET_PKT_AT_HEAD(pPktQueue); |
| 678 if (NULL == pPacket) { |
| 679 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n")); |
| 680 return A_EINVAL; |
| 681 } |
| 682 |
| 683 AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); |
| 684 pEndpoint = &target->EndPoint[pPacket->Endpoint]; |
| 685 |
| 686 HTCTrySend(target, pEndpoint, pPktQueue); |
| 687 |
| 688 /* do completion on any packets that couldn't get in */ |
| 689 if (!HTC_QUEUE_EMPTY(pPktQueue)) { |
| 690 |
| 691 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) { |
| 692 if (HTC_STOPPING(target)) { |
| 693 pPacket->Status = A_ECANCELED; |
| 694 } else { |
| 695 pPacket->Status = A_NO_RESOURCE; |
| 696 } |
| 697 } HTC_PACKET_QUEUE_ITERATE_END; |
| 698 |
| 699 DO_EP_TX_COMPLETION(pEndpoint,pPktQueue); |
| 700 } |
| 701 |
| 702 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n")); |
| 703 |
| 704 return A_OK; |
| 705 } |
| 706 |
| 707 /* HTC API - HTCSendPkt */ |
| 708 A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) |
| 709 { |
| 710 HTC_PACKET_QUEUE queue; |
| 711 |
| 712 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, |
| 713 ("+-HTCSendPkt: Enter endPointId: %d, buffer: 0x%X, length:
%d \n", |
| 714 pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->Actu
alLength)); |
| 715 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket); |
| 716 return HTCSendPktsMultiple(HTCHandle, &queue); |
| 717 } |
| 718 |
| 719 /* check TX queues to drain because of credit distribution update */ |
| 720 static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target) |
| 721 { |
| 722 HTC_ENDPOINT *pEndpoint; |
| 723 HTC_ENDPOINT_CREDIT_DIST *pDistItem; |
| 724 |
| 725 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n")); |
| 726 pDistItem = target->EpCreditDistributionListHead; |
| 727 |
| 728 /* run through the credit distribution list to see |
| 729 * if there are packets queued |
| 730 * NOTE: no locks need to be taken since the distribution list |
| 731 * is not dynamic (cannot be re-ordered) and we are not modifying any st
ate */ |
| 732 while (pDistItem != NULL) { |
| 733 pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved; |
| 734 |
| 735 if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) > 0) { |
| 736 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packe
ts in TX Queue \n", |
| 737 pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, HTC_PA
CKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); |
| 738 /* try to start the stalled queue, this list is ordered by prior
ity. |
| 739 * Highest priority queue get's processed first, if there are cr
edits available the |
| 740 * highest priority queue will get a chance to reclaim credits f
rom lower priority |
| 741 * ones */ |
| 742 HTCTrySend(target, pEndpoint, NULL); |
| 743 } |
| 744 |
| 745 pDistItem = pDistItem->pNext; |
| 746 } |
| 747 |
| 748 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n")); |
| 749 } |
| 750 |
| 751 /* process credit reports and call distribution function */ |
| 752 void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEnt
ries, HTC_ENDPOINT_ID FromEndpoint) |
| 753 { |
| 754 int i; |
| 755 HTC_ENDPOINT *pEndpoint; |
| 756 int totalCredits = 0; |
| 757 A_BOOL doDist = FALSE; |
| 758 |
| 759 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entrie
s:%d \n", NumEntries)); |
| 760 |
| 761 /* lock out TX while we update credits */ |
| 762 LOCK_HTC_TX(target); |
| 763 |
| 764 for (i = 0; i < NumEntries; i++, pRpt++) { |
| 765 if (pRpt->EndpointID >= ENDPOINT_MAX) { |
| 766 AR_DEBUG_ASSERT(FALSE); |
| 767 break; |
| 768 } |
| 769 |
| 770 pEndpoint = &target->EndPoint[pRpt->EndpointID]; |
| 771 |
| 772 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n", |
| 773 pRpt->EndpointID, pRpt->Credits)); |
| 774 |
| 775 |
| 776 #ifdef HTC_EP_STAT_PROFILING |
| 777 |
| 778 INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1); |
| 779 INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits); |
| 780 |
| 781 if (FromEndpoint == pRpt->EndpointID) { |
| 782 /* this credit report arrived on the same endpoint indicating it
arrived in an RX |
| 783 * packet */ |
| 784 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits); |
| 785 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1); |
| 786 } else if (FromEndpoint == ENDPOINT_0) { |
| 787 /* this credit arrived on endpoint 0 as a NULL message */ |
| 788 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits); |
| 789 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1); |
| 790 } else { |
| 791 /* arrived on another endpoint */ |
| 792 INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits); |
| 793 INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1); |
| 794 } |
| 795 |
| 796 #endif |
| 797 |
| 798 if (ENDPOINT_0 == pRpt->EndpointID) { |
| 799 /* always give endpoint 0 credits back */ |
| 800 pEndpoint->CreditDist.TxCredits += pRpt->Credits; |
| 801 } else { |
| 802 /* for all other endpoints, update credits to distribute, the di
stribution function |
| 803 * will handle giving out credits back to the endpoints */ |
| 804 pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits; |
| 805 /* flag that we have to do the distribution */ |
| 806 doDist = TRUE; |
| 807 } |
| 808 |
| 809 /* refresh tx depth for distribution function that will recover thes
e credits |
| 810 * NOTE: this is only valid when there are credits to recover! */ |
| 811 pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
TxQueue); |
| 812 |
| 813 totalCredits += pRpt->Credits; |
| 814 } |
| 815 |
| 816 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribut
e \n", totalCredits)); |
| 817 |
| 818 if (doDist) { |
| 819 /* this was a credit return based on a completed send operations |
| 820 * note, this is done with the lock held */ |
| 821 DO_DISTRIBUTION(target, |
| 822 HTC_CREDIT_DIST_SEND_COMPLETE, |
| 823 "Send Complete", |
| 824 target->EpCreditDistributionListHead->pNext); |
| 825 } |
| 826 |
| 827 UNLOCK_HTC_TX(target); |
| 828 |
| 829 if (totalCredits) { |
| 830 HTCCheckEndpointTxQueues(target); |
| 831 } |
| 832 |
| 833 AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n")); |
| 834 } |
| 835 |
| 836 /* flush endpoint TX queue */ |
| 837 static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_
TX_TAG Tag) |
| 838 { |
| 839 HTC_PACKET *pPacket; |
| 840 HTC_PACKET_QUEUE discardQueue; |
| 841 HTC_PACKET_QUEUE container; |
| 842 |
| 843 /* initialize the discard queue */ |
| 844 INIT_HTC_PACKET_QUEUE(&discardQueue); |
| 845 |
| 846 LOCK_HTC_TX(target); |
| 847 |
| 848 /* interate from the front of the TX queue and flush out packets */ |
| 849 ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue.QueueHead, pPacket, HTC_P
ACKET, ListLink) { |
| 850 |
| 851 /* check for removal */ |
| 852 if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)
) { |
| 853 /* remove from queue */ |
| 854 HTC_PACKET_REMOVE(&pEndpoint->TxQueue, pPacket); |
| 855 /* add it to the discard pile */ |
| 856 HTC_PACKET_ENQUEUE(&discardQueue, pPacket); |
| 857 } |
| 858 |
| 859 } ITERATE_END; |
| 860 |
| 861 UNLOCK_HTC_TX(target); |
| 862 |
| 863 /* empty the discard queue */ |
| 864 while (1) { |
| 865 pPacket = HTC_PACKET_DEQUEUE(&discardQueue); |
| 866 if (NULL == pPacket) { |
| 867 break; |
| 868 } |
| 869 pPacket->Status = A_ECANCELED; |
| 870 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%X, length:%d, e
p:%d tag:0x%X \n", |
| 871 (A_UINT32)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPa
cket->PktInfo.AsTx.Tag)); |
| 872 INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket); |
| 873 DO_EP_TX_COMPLETION(pEndpoint,&container); |
| 874 } |
| 875 |
| 876 } |
| 877 |
| 878 void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist) |
| 879 { |
| 880 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X -----------
---\n", |
| 881 pEPDist->Endpoint, pEPDist->ServiceID)); |
| 882 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%X next:0x%X prev:0x%X\n", |
| 883 (A_UINT32)pEPDist, (A_UINT32)pEPDist->pNext, (A_UINT32)pEPDist->
pPrev)); |
| 884 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->Di
stFlags)); |
| 885 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCr
editsNorm)); |
| 886 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCr
editsMin)); |
| 887 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCr
edits)); |
| 888 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCr
editsAssigned)); |
| 889 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCr
editsSeek)); |
| 890 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCr
editSize)); |
| 891 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCr
editsPerMaxMsg)); |
| 892 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCr
editsToDist)); |
| 893 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n", |
| 894 HTC_PACKET_QUEUE_DEPTH(&((HTC_ENDPOINT *)pEPDist->pHTCReserv
ed)->TxQueue))); |
| 895 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-------------------------------------------
---------\n")); |
| 896 } |
| 897 |
| 898 void DumpCreditDistStates(HTC_TARGET *target) |
| 899 { |
| 900 HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead; |
| 901 |
| 902 while (pEPList != NULL) { |
| 903 DumpCreditDist(pEPList); |
| 904 pEPList = pEPList->pNext; |
| 905 } |
| 906 |
| 907 if (target->DistributeCredits != NULL) { |
| 908 DO_DISTRIBUTION(target, |
| 909 HTC_DUMP_CREDIT_STATE, |
| 910 "Dump State", |
| 911 NULL); |
| 912 } |
| 913 } |
| 914 |
| 915 /* flush all send packets from all endpoint queues */ |
| 916 void HTCFlushSendPkts(HTC_TARGET *target) |
| 917 { |
| 918 HTC_ENDPOINT *pEndpoint; |
| 919 int i; |
| 920 |
| 921 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) { |
| 922 DumpCreditDistStates(target); |
| 923 } |
| 924 |
| 925 for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { |
| 926 pEndpoint = &target->EndPoint[i]; |
| 927 if (pEndpoint->ServiceID == 0) { |
| 928 /* not in use.. */ |
| 929 continue; |
| 930 } |
| 931 HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL); |
| 932 } |
| 933 |
| 934 |
| 935 } |
| 936 |
| 937 /* HTC API to flush an endpoint's TX queue*/ |
| 938 void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG
Tag) |
| 939 { |
| 940 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 941 HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint]; |
| 942 |
| 943 if (pEndpoint->ServiceID == 0) { |
| 944 AR_DEBUG_ASSERT(FALSE); |
| 945 /* not in use.. */ |
| 946 return; |
| 947 } |
| 948 |
| 949 HTCFlushEndpointTX(target, pEndpoint, Tag); |
| 950 } |
| 951 |
| 952 /* HTC API to indicate activity to the credit distribution function */ |
| 953 void HTCIndicateActivityChange(HTC_HANDLE HTCHandle, |
| 954 HTC_ENDPOINT_ID Endpoint, |
| 955 A_BOOL Active) |
| 956 { |
| 957 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 958 HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint]; |
| 959 A_BOOL doDist = FALSE; |
| 960 |
| 961 if (pEndpoint->ServiceID == 0) { |
| 962 AR_DEBUG_ASSERT(FALSE); |
| 963 /* not in use.. */ |
| 964 return; |
| 965 } |
| 966 |
| 967 LOCK_HTC_TX(target); |
| 968 |
| 969 if (Active) { |
| 970 if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) { |
| 971 /* mark active now */ |
| 972 pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE; |
| 973 doDist = TRUE; |
| 974 } |
| 975 } else { |
| 976 if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) { |
| 977 /* mark inactive now */ |
| 978 pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE; |
| 979 doDist = TRUE; |
| 980 } |
| 981 } |
| 982 |
| 983 if (doDist) { |
| 984 /* indicate current Tx Queue depth to the credit distribution functi
on */ |
| 985 pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
TxQueue); |
| 986 /* do distribution again based on activity change |
| 987 * note, this is done with the lock held */ |
| 988 DO_DISTRIBUTION(target, |
| 989 HTC_CREDIT_DIST_ACTIVITY_CHANGE, |
| 990 "Activity Change", |
| 991 target->EpCreditDistributionListHead->pNext); |
| 992 } |
| 993 |
| 994 UNLOCK_HTC_TX(target); |
| 995 |
| 996 if (doDist && !Active) { |
| 997 /* if a stream went inactive and this resulted in a credit distribution
change, |
| 998 * some credits may now be available for HTC packets that are stuck in |
| 999 * HTC queues */ |
| 1000 HTCCheckEndpointTxQueues(target); |
| 1001 } |
| 1002 } |
| 1003 |
| 1004 A_BOOL HTCIsEndpointActive(HTC_HANDLE HTCHandle, |
| 1005 HTC_ENDPOINT_ID Endpoint) |
| 1006 { |
| 1007 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 1008 HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint]; |
| 1009 |
| 1010 if (pEndpoint->ServiceID == 0) { |
| 1011 return FALSE; |
| 1012 } |
| 1013 |
| 1014 if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) { |
| 1015 return TRUE; |
| 1016 } |
| 1017 |
| 1018 return FALSE; |
| 1019 } |
OLD | NEW |