Example #1
0
/* 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;
    }

}
Example #2
0
/* 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;
    }

}
Example #3
0
/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
                        HTC_ENDPOINT_CREDIT_DIST *pEPDist)
{
    HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
    int                      credits = 0;
    int                      need;

    do {

        if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
                /* we never oversubscribe on the control service, this is not
                 * a high performance path and the target never holds onto control
                 * credits for too long */
            break;
        }

#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
        if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
            if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
                 /* limit VI service from oversubscribing */
                 break;
            }
        }

        if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
            if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
                 /* limit VO service from oversubscribing */
                break;
            }
        }
#else
        if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
            if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
                (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
                 /* limit VI service from oversubscribing */
                 /* at least one free credit will not be used by VI */
                 break;
            }
        }

        if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
            if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
                (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
                 /* limit VO service from oversubscribing */
                 /* at least one free credit will not be used by VO */
                break;
            }
        }
#endif

        /* for all other services, we follow a simple algorithm of
         * 1. checking the free pool for credits
         * 2. checking lower priority endpoints for credits to take */

            /* give what we can */
        credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);

        if (credits >= pEPDist->TxCreditsSeek) {
                /* we found some to fullfill the seek request */
            break;
        }

        /* we don't have enough in the free pool, try taking away from lower priority services
         *
         * The rule for taking away credits:
         *   1. Only take from lower priority endpoints
         *   2. Only take what is allocated above the minimum (never starve an endpoint completely)
         *   3. Only take what you need.
         *
         * */

            /* starting at the lowest priority */
        pCurEpDist = pCredInfo->pLowestPriEpDist;

            /* work backwards until we hit the endpoint again */
        while (pCurEpDist != pEPDist) {
                /* calculate how many we need so far */
            need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;

            if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) {
                    /* the current one has been allocated more than it's minimum and it
                     * has enough credits assigned above it's minimum to fullfill our need
                     * try to take away just enough to fullfill our need */
                ReduceCredits(pCredInfo,
                              pCurEpDist,
                              pCurEpDist->TxCreditsAssigned - need);

                if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
                        /* we have enough */
                    break;
                }
            }

            pCurEpDist = pCurEpDist->pPrev;
        }


        if ((pCredInfo->CurrentFreeCredits < pEPDist->TxCreditsSeek) &&
            (pEPDist->TxCreditsAssigned < pEPDist->TxCreditsNorm)) {
            /* we don't have enough in the free pool, try taking away some unused credits from high priority services
             *
             * The rule for taking away credits:
             *   1. It's ok to take away from higher priority service as long as you take only part of what is unused.
             *   2. Only take what is allocated above the minimum (never starve an endpoint completely)
             *   3. Only take what you need.
             *
             * */
             /* Go towards higher  priority */
            pCurEpDist = pEPDist->pPrev;

            /* work backwards until we hit the top priority */
            while (pCurEpDist != NULL) {
                /* calculate how many we need so far */
                need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
                /* try to take away half of what is not being used by the EP */
                need = min(pCurEpDist->TxCredits/2, need);
                if ((need > 0) && ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin)) {
                    /* the current one has been allocated more than it's minimum and it
                     * has enough credits assigned above it's minimum to fullfill our need
                     * try to take away just enough to fullfill our need */
 
                    ReduceCredits(pCredInfo,
                                  pCurEpDist,
                                  pCurEpDist->TxCreditsAssigned - need);
 
                    if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
                        /* we have enough */
                        break;
                    }
                }
                pCurEpDist = pCurEpDist->pPrev;
            }
        }

        /* return what we can get */
        credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);

    } while (FALSE);

        /* did we find some credits? */
    if (credits) {
            /* give what we can */
        GiveCredits(pCredInfo, pEPDist, credits);
    }

}
Example #4
0
/* 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);

}