/* redistribute credits based on activity change */ static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo, HTC_ENDPOINT_CREDIT_DIST *pEPDistList) { HTC_ENDPOINT_CREDIT_DIST *pCurEpDist = pEPDistList; /* walk through the list and remove credits from inactive endpoints */ while (pCurEpDist != NULL) { if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) { if (!IS_EP_ACTIVE(pCurEpDist)) { if (pCurEpDist->TxQueueDepth == 0) { /* EP is inactive and there are no pending messages, reduce credits back to zero */ ReduceCredits(pCredInfo, pCurEpDist, 0); } else { /* we cannot zero the credits assigned to this EP, but to keep * the credits available for these leftover packets, reduce to * a minimum */ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin); } } } /* NOTE in the active case, we do not need to do anything further, * when an EP goes active and needs credits, HTC will call into * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */ pCurEpDist = pCurEpDist->pNext; } }
/* redistribute credits based on activity change */ static void RedistributeCredits(struct common_credit_state_info *pCredInfo, struct htc_endpoint_credit_dist *pEPDistList) { struct htc_endpoint_credit_dist *pCurEpDist = pEPDistList; /* walk through the list and remove credits from inactive endpoints */ while (pCurEpDist != NULL) { #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)) { /* force low priority streams to always be active to retain their minimum credit distribution */ SET_EP_ACTIVE(pCurEpDist); } #endif if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) { if (!IS_EP_ACTIVE(pCurEpDist)) { if (pCurEpDist->TxQueueDepth == 0) { /* EP is inactive and there are no pending messages, reduce credits back to zero */ ReduceCredits(pCredInfo, pCurEpDist, 0); } else { /* we cannot zero the credits assigned to this EP, but to keep * the credits available for these leftover packets, reduce to * a minimum */ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin); } } } /* NOTE in the active case, we do not need to do anything further, * when an EP goes active and needs credits, HTC will call into * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */ pCurEpDist = pCurEpDist->pNext; } }
/* default credit distribution callback * This callback is invoked whenever endpoints require credit distributions. * A lock is held while this function is invoked, this function shall NOT block. * The pEPDistList is a list of distribution structures in prioritized order as * defined by the call to the HTCSetCreditDistribution() api. * */ static void ar6000_credit_distribute(void *Context, HTC_ENDPOINT_CREDIT_DIST *pEPDistList, HTC_CREDIT_DIST_REASON Reason) { HTC_ENDPOINT_CREDIT_DIST *pCurEpDist; COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context; switch (Reason) { case HTC_CREDIT_DIST_SEND_COMPLETE : pCurEpDist = pEPDistList; /* we are given the start of the endpoint distribution list. * There may be one or more endpoints to service. * Run through the list and distribute credits */ while (pCurEpDist != NULL) { if (pCurEpDist->TxCreditsToDist > 0) { /* return the credits back to the endpoint */ pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist; /* always zero out when we are done */ pCurEpDist->TxCreditsToDist = 0; if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) { /* reduce to the assigned limit, previous credit reductions * could have caused the limit to change */ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned); } if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) { /* oversubscribed endpoints need to reduce back to normal */ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm); } if (!IS_EP_ACTIVE(pCurEpDist)) { /* endpoint is inactive, now check for messages waiting for credits */ if (pCurEpDist->TxQueueDepth == 0) { /* EP is inactive and there are no pending messages, * reduce credits back to zero to recover credits */ ReduceCredits(pCredInfo, pCurEpDist, 0); } } } pCurEpDist = pCurEpDist->pNext; } break; case HTC_CREDIT_DIST_ACTIVITY_CHANGE : RedistributeCredits(pCredInfo,pEPDistList); break; case HTC_CREDIT_DIST_SEEK_CREDITS : SeekCredits(pCredInfo,pEPDistList); break; case HTC_DUMP_CREDIT_STATE : AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Credit Distribution, total : %d, free : %d\n", pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits)); break; default: break; } /* sanity checks done after each distribution action */ A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits); A_ASSERT(pCredInfo->CurrentFreeCredits >= 0); }