mirror of https://github.com/hak5/openwrt.git
539 lines
19 KiB
C
539 lines
19 KiB
C
/*
|
|
*
|
|
* Copyright (c) 2007 Atheros Communications Inc.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include "htc_internal.h"
|
|
|
|
#define DO_EP_TX_COMPLETION(ep,p) \
|
|
{ \
|
|
(p)->Completion = NULL; \
|
|
(ep)->EpCallBacks.EpTxComplete((ep)->EpCallBacks.pContext,(p)); \
|
|
}
|
|
|
|
|
|
/* call the distribute credits callback with the distribution */
|
|
#define DO_DISTRIBUTION(t,reason,description,pList) \
|
|
{ \
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
|
|
(" calling distribute function (%s) (dfn:0x%X, ctxt:0x%X, dist:0x%X) \n", \
|
|
(description), \
|
|
(A_UINT32)(t)->DistributeCredits, \
|
|
(A_UINT32)(t)->pCredDistContext, \
|
|
(A_UINT32)pList)); \
|
|
(t)->DistributeCredits((t)->pCredDistContext, \
|
|
(pList), \
|
|
(reason)); \
|
|
}
|
|
|
|
/* our internal send packet completion handler when packets are submited to the AR6K device
|
|
* layer */
|
|
static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
|
|
{
|
|
HTC_TARGET *target = (HTC_TARGET *)Context;
|
|
HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint];
|
|
|
|
|
|
if (A_FAILED(pPacket->Status)) {
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
|
|
("HTCSendPktCompletionHandler: request failed (status:%d, ep:%d) \n",
|
|
pPacket->Status, pPacket->Endpoint));
|
|
}
|
|
/* first, fixup the head room we allocated */
|
|
pPacket->pBuffer += HTC_HDR_LENGTH;
|
|
/* do completion */
|
|
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
|
}
|
|
|
|
A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 SendFlags)
|
|
{
|
|
A_STATUS status;
|
|
A_UINT8 *pHdrBuf;
|
|
A_BOOL sync = FALSE;
|
|
|
|
/* caller always provides headrooom */
|
|
pPacket->pBuffer -= HTC_HDR_LENGTH;
|
|
pHdrBuf = pPacket->pBuffer;
|
|
/* setup frame header */
|
|
A_SET_UINT16_FIELD(pHdrBuf,HTC_FRAME_HDR,PayloadLen,(A_UINT16)pPacket->ActualLength);
|
|
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,Flags,SendFlags);
|
|
A_SET_UINT8_FIELD(pHdrBuf,HTC_FRAME_HDR,EndpointID, (A_UINT8)pPacket->Endpoint);
|
|
|
|
if (pPacket->Completion == NULL) {
|
|
/* mark that this request was synchronously issued */
|
|
sync = TRUE;
|
|
}
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
|
("+-HTCIssueSend: transmit length : %d (%s) \n",
|
|
pPacket->ActualLength + HTC_HDR_LENGTH,
|
|
sync ? "SYNC" : "ASYNC" ));
|
|
|
|
/* send message to device */
|
|
status = DevSendPacket(&target->Device,
|
|
pPacket,
|
|
pPacket->ActualLength + HTC_HDR_LENGTH);
|
|
|
|
if (sync) {
|
|
/* use local sync variable. If this was issued asynchronously, pPacket is no longer
|
|
* safe to access. */
|
|
pPacket->pBuffer += HTC_HDR_LENGTH;
|
|
}
|
|
|
|
/* if this request was asynchronous, the packet completion routine will be invoked by
|
|
* the device layer when the HIF layer completes the request */
|
|
|
|
return status;
|
|
}
|
|
|
|
/* try to send the current packet or a packet at the head of the TX queue,
|
|
* if there are no credits, the packet remains in the queue. */
|
|
static void HTCTrySend(HTC_TARGET *target,
|
|
HTC_PACKET *pPacketToSend,
|
|
HTC_ENDPOINT_ID ep)
|
|
{
|
|
HTC_PACKET *pPacket;
|
|
HTC_ENDPOINT *pEndpoint;
|
|
int creditsRequired;
|
|
A_UINT8 sendFlags;
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (pPkt:0x%X)\n",(A_UINT32)pPacketToSend));
|
|
|
|
pEndpoint = &target->EndPoint[ep];
|
|
|
|
LOCK_HTC_TX(target);
|
|
|
|
if (pPacketToSend != NULL) {
|
|
/* caller supplied us a packet to queue to the tail of the HTC TX queue before
|
|
* we check the tx queue */
|
|
HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue,pPacketToSend);
|
|
pEndpoint->CurrentTxQueueDepth++;
|
|
}
|
|
|
|
/* now drain the TX queue for transmission as long as we have enough
|
|
* credits */
|
|
|
|
while (1) {
|
|
|
|
if (HTC_QUEUE_EMPTY(&pEndpoint->TxQueue)) {
|
|
/* nothing in the queue */
|
|
break;
|
|
}
|
|
|
|
sendFlags = 0;
|
|
|
|
/* get packet at head, but don't remove it */
|
|
pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%X , Queue Depth: %d\n",
|
|
(A_UINT32)pPacket, pEndpoint->CurrentTxQueueDepth));
|
|
|
|
/* figure out how many credits this message requires */
|
|
creditsRequired = pPacket->ActualLength + HTC_HDR_LENGTH;
|
|
creditsRequired += target->TargetCreditSize - 1;
|
|
creditsRequired /= target->TargetCreditSize;
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n",
|
|
creditsRequired, pEndpoint->CreditDist.TxCredits));
|
|
|
|
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
|
|
|
|
/* not enough credits */
|
|
|
|
if (pPacket->Endpoint == ENDPOINT_0) {
|
|
/* leave it in the queue */
|
|
break;
|
|
}
|
|
/* invoke the registered distribution function only if this is not
|
|
* endpoint 0, we let the driver layer provide more credits if it can.
|
|
* We pass the credit distribution list starting at the endpoint in question
|
|
* */
|
|
|
|
/* set how many credits we need */
|
|
pEndpoint->CreditDist.TxCreditsSeek =
|
|
creditsRequired - pEndpoint->CreditDist.TxCredits;
|
|
DO_DISTRIBUTION(target,
|
|
HTC_CREDIT_DIST_SEEK_CREDITS,
|
|
"Seek Credits",
|
|
&pEndpoint->CreditDist);
|
|
|
|
pEndpoint->CreditDist.TxCreditsSeek = 0;
|
|
|
|
if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
|
|
/* still not enough credits to send, leave packet in the queue */
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
|
(" Not enough credits for ep %d leaving packet in queue..\n",
|
|
pPacket->Endpoint));
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
pEndpoint->CreditDist.TxCredits -= creditsRequired;
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
|
|
|
|
/* check if we need credits */
|
|
if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
|
|
sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n"));
|
|
}
|
|
|
|
/* now we can fully dequeue */
|
|
pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
|
|
pEndpoint->CurrentTxQueueDepth--;
|
|
|
|
INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
|
|
|
|
UNLOCK_HTC_TX(target);
|
|
|
|
HTCIssueSend(target, pPacket, sendFlags);
|
|
|
|
LOCK_HTC_TX(target);
|
|
|
|
/* go back and check for more messages */
|
|
}
|
|
|
|
if (pEndpoint->CurrentTxQueueDepth >= pEndpoint->MaxTxQueueDepth) {
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n",
|
|
ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth));
|
|
UNLOCK_HTC_TX(target);
|
|
/* queue is now full, let caller know */
|
|
if (pEndpoint->EpCallBacks.EpSendFull != NULL) {
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n"));
|
|
pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, ep);
|
|
}
|
|
} else {
|
|
UNLOCK_HTC_TX(target);
|
|
/* queue is now available for new packet, let caller know */
|
|
if (pEndpoint->EpCallBacks.EpSendAvail)
|
|
pEndpoint->EpCallBacks.EpSendAvail(pEndpoint->EpCallBacks.pContext, ep);
|
|
}
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
|
|
}
|
|
|
|
/* HTC API - HTCSendPkt */
|
|
A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
|
|
{
|
|
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
|
HTC_ENDPOINT *pEndpoint;
|
|
HTC_ENDPOINT_ID ep;
|
|
A_STATUS status = A_OK;
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
|
|
("+HTCSendPkt: Enter endPointId: %d, buffer: 0x%X, length: %d \n",
|
|
pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->ActualLength));
|
|
|
|
ep = pPacket->Endpoint;
|
|
AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
|
|
pEndpoint = &target->EndPoint[ep];
|
|
|
|
do {
|
|
|
|
if (HTC_STOPPING(target)) {
|
|
status = A_ECANCELED;
|
|
pPacket->Status = status;
|
|
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
|
break;
|
|
}
|
|
/* everything sent through this interface is asynchronous */
|
|
/* fill in HTC completion routines */
|
|
pPacket->Completion = HTCSendPktCompletionHandler;
|
|
pPacket->pContext = target;
|
|
|
|
HTCTrySend(target, pPacket, ep);
|
|
|
|
} while (FALSE);
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/* check TX queues to drain because of credit distribution update */
|
|
static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target)
|
|
{
|
|
HTC_ENDPOINT *pEndpoint;
|
|
HTC_ENDPOINT_CREDIT_DIST *pDistItem;
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
|
|
pDistItem = target->EpCreditDistributionListHead;
|
|
|
|
/* run through the credit distribution list to see
|
|
* if there are packets queued
|
|
* NOTE: no locks need to be taken since the distribution list
|
|
* is not dynamic (cannot be re-ordered) and we are not modifying any state */
|
|
while (pDistItem != NULL) {
|
|
pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved;
|
|
|
|
if (pEndpoint->CurrentTxQueueDepth > 0) {
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
|
|
pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, pEndpoint->CurrentTxQueueDepth));
|
|
/* try to start the stalled queue, this list is ordered by priority.
|
|
* Highest priority queue get's processed first, if there are credits available the
|
|
* highest priority queue will get a chance to reclaim credits from lower priority
|
|
* ones */
|
|
HTCTrySend(target, NULL, pDistItem->Endpoint);
|
|
}
|
|
|
|
pDistItem = pDistItem->pNext;
|
|
}
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
|
|
}
|
|
|
|
/* process credit reports and call distribution function */
|
|
void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
|
|
{
|
|
int i;
|
|
HTC_ENDPOINT *pEndpoint;
|
|
int totalCredits = 0;
|
|
A_BOOL doDist = FALSE;
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
|
|
|
|
/* lock out TX while we update credits */
|
|
LOCK_HTC_TX(target);
|
|
|
|
for (i = 0; i < NumEntries; i++, pRpt++) {
|
|
if (pRpt->EndpointID >= ENDPOINT_MAX) {
|
|
AR_DEBUG_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
pEndpoint = &target->EndPoint[pRpt->EndpointID];
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n",
|
|
pRpt->EndpointID, pRpt->Credits));
|
|
|
|
|
|
#ifdef HTC_EP_STAT_PROFILING
|
|
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
|
|
|
|
if (FromEndpoint == pRpt->EndpointID) {
|
|
/* this credit report arrived on the same endpoint indicating it arrived in an RX
|
|
* packet */
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
|
|
} else if (FromEndpoint == ENDPOINT_0) {
|
|
/* this credit arrived on endpoint 0 as a NULL message */
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
|
|
} else {
|
|
/* arrived on another endpoint */
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
|
|
INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
|
|
}
|
|
|
|
#endif
|
|
|
|
if (ENDPOINT_0 == pRpt->EndpointID) {
|
|
/* always give endpoint 0 credits back */
|
|
pEndpoint->CreditDist.TxCredits += pRpt->Credits;
|
|
} else {
|
|
/* for all other endpoints, update credits to distribute, the distribution function
|
|
* will handle giving out credits back to the endpoints */
|
|
pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
|
|
/* flag that we have to do the distribution */
|
|
doDist = TRUE;
|
|
}
|
|
|
|
totalCredits += pRpt->Credits;
|
|
}
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribute \n", totalCredits));
|
|
|
|
if (doDist) {
|
|
/* this was a credit return based on a completed send operations
|
|
* note, this is done with the lock held */
|
|
DO_DISTRIBUTION(target,
|
|
HTC_CREDIT_DIST_SEND_COMPLETE,
|
|
"Send Complete",
|
|
target->EpCreditDistributionListHead->pNext);
|
|
}
|
|
|
|
UNLOCK_HTC_TX(target);
|
|
|
|
if (totalCredits) {
|
|
HTCCheckEndpointTxQueues(target);
|
|
}
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
|
|
}
|
|
|
|
/* flush endpoint TX queue */
|
|
static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_TX_TAG Tag)
|
|
{
|
|
HTC_PACKET *pPacket;
|
|
HTC_PACKET_QUEUE discardQueue;
|
|
|
|
/* initialize the discard queue */
|
|
INIT_HTC_PACKET_QUEUE(&discardQueue);
|
|
|
|
LOCK_HTC_TX(target);
|
|
|
|
/* interate from the front of the TX queue and flush out packets */
|
|
ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue, pPacket, HTC_PACKET, ListLink) {
|
|
|
|
/* check for removal */
|
|
if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
|
|
/* remove from queue */
|
|
HTC_PACKET_REMOVE(pPacket);
|
|
/* add it to the discard pile */
|
|
HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
|
|
pEndpoint->CurrentTxQueueDepth--;
|
|
}
|
|
|
|
} ITERATE_END;
|
|
|
|
UNLOCK_HTC_TX(target);
|
|
|
|
/* empty the discard queue */
|
|
while (1) {
|
|
pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
|
|
if (NULL == pPacket) {
|
|
break;
|
|
}
|
|
pPacket->Status = A_ECANCELED;
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%X, length:%d, ep:%d tag:0x%X \n",
|
|
(A_UINT32)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
|
|
DO_EP_TX_COMPLETION(pEndpoint,pPacket);
|
|
}
|
|
|
|
}
|
|
|
|
void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist)
|
|
{
|
|
#ifdef DEBUG
|
|
HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *)pEPDist->pHTCReserved;
|
|
#endif
|
|
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X --------------\n",
|
|
pEPDist->Endpoint, pEPDist->ServiceID));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%X next:0x%X prev:0x%X\n",
|
|
(A_UINT32)pEPDist, (A_UINT32)pEPDist->pNext, (A_UINT32)pEPDist->pPrev));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->DistFlags));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCreditsNorm));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCreditsMin));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCredits));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCreditsAssigned));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCreditsSeek));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCreditSize));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCreditsToDist));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n", pEndpoint->CurrentTxQueueDepth));
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
|
|
}
|
|
|
|
void DumpCreditDistStates(HTC_TARGET *target)
|
|
{
|
|
HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead;
|
|
|
|
while (pEPList != NULL) {
|
|
DumpCreditDist(pEPList);
|
|
pEPList = pEPList->pNext;
|
|
}
|
|
|
|
if (target->DistributeCredits != NULL) {
|
|
DO_DISTRIBUTION(target,
|
|
HTC_DUMP_CREDIT_STATE,
|
|
"Dump State",
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
/* flush all send packets from all endpoint queues */
|
|
void HTCFlushSendPkts(HTC_TARGET *target)
|
|
{
|
|
HTC_ENDPOINT *pEndpoint;
|
|
int i;
|
|
|
|
DumpCreditDistStates(target);
|
|
|
|
for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
|
|
pEndpoint = &target->EndPoint[i];
|
|
if (pEndpoint->ServiceID == 0) {
|
|
/* not in use.. */
|
|
continue;
|
|
}
|
|
HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
|
|
}
|
|
|
|
}
|
|
|
|
/* HTC API to flush an endpoint's TX queue*/
|
|
void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
|
|
{
|
|
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
|
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
|
|
|
|
if (pEndpoint->ServiceID == 0) {
|
|
AR_DEBUG_ASSERT(FALSE);
|
|
/* not in use.. */
|
|
return;
|
|
}
|
|
|
|
HTCFlushEndpointTX(target, pEndpoint, Tag);
|
|
}
|
|
|
|
/* HTC API to indicate activity to the credit distribution function */
|
|
void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
|
|
HTC_ENDPOINT_ID Endpoint,
|
|
A_BOOL Active)
|
|
{
|
|
HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
|
|
HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint];
|
|
A_BOOL doDist = FALSE;
|
|
|
|
if (pEndpoint->ServiceID == 0) {
|
|
AR_DEBUG_ASSERT(FALSE);
|
|
/* not in use.. */
|
|
return;
|
|
}
|
|
|
|
LOCK_HTC_TX(target);
|
|
|
|
if (Active) {
|
|
if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
|
|
/* mark active now */
|
|
pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
|
|
doDist = TRUE;
|
|
}
|
|
} else {
|
|
if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
|
|
/* mark inactive now */
|
|
pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
|
|
doDist = TRUE;
|
|
}
|
|
}
|
|
|
|
if (doDist) {
|
|
/* do distribution again based on activity change
|
|
* note, this is done with the lock held */
|
|
DO_DISTRIBUTION(target,
|
|
HTC_CREDIT_DIST_ACTIVITY_CHANGE,
|
|
"Activity Change",
|
|
target->EpCreditDistributionListHead->pNext);
|
|
}
|
|
|
|
UNLOCK_HTC_TX(target);
|
|
|
|
}
|