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