Root/target/linux/s3c24xx/files-2.6.30/drivers/ar6000/miscdrv/credit_dist.c

1
2/*
3 *
4 * Copyright (c) 2004-2007 Atheros Communications Inc.
5 * All rights reserved.
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation;
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
16 *
17 *
18 *
19 */
20
21#include "a_config.h"
22#include "athdefs.h"
23#include "a_types.h"
24#include "a_osapi.h"
25#include "a_debug.h"
26#include "htc_api.h"
27#include "common_drv.h"
28
29/********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
30
31#define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
32
33#ifdef NO_VO_SERVICE
34#define DATA_SVCS_USED 3
35#else
36#define DATA_SVCS_USED 4
37#endif
38
39static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
40                                HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
41
42static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
43                        HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
44
45/* reduce an ep's credits back to a set limit */
46static INLINE void ReduceCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
47                                HTC_ENDPOINT_CREDIT_DIST *pEpDist,
48                                int Limit)
49{
50    int credits;
51
52        /* set the new limit */
53    pEpDist->TxCreditsAssigned = Limit;
54
55    if (pEpDist->TxCredits <= Limit) {
56        return;
57    }
58
59        /* figure out how much to take away */
60    credits = pEpDist->TxCredits - Limit;
61        /* take them away */
62    pEpDist->TxCredits -= credits;
63    pCredInfo->CurrentFreeCredits += credits;
64}
65
66/* give an endpoint some credits from the free credit pool */
67#define GiveCredits(pCredInfo,pEpDist,credits) \
68{ \
69    (pEpDist)->TxCredits += (credits); \
70    (pEpDist)->TxCreditsAssigned += (credits); \
71    (pCredInfo)->CurrentFreeCredits -= (credits); \
72}
73
74
75/* default credit init callback.
76 * This function is called in the context of HTCStart() to setup initial (application-specific)
77 * credit distributions */
78static void ar6000_credit_init(void *Context,
79                               HTC_ENDPOINT_CREDIT_DIST *pEPList,
80                               int TotalCredits)
81{
82    HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
83    int count;
84    COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
85
86    pCredInfo->CurrentFreeCredits = TotalCredits;
87    pCredInfo->TotalAvailableCredits = TotalCredits;
88
89    pCurEpDist = pEPList;
90
91        /* run through the list and initialize */
92    while (pCurEpDist != NULL) {
93
94            /* set minimums for each endpoint */
95        pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
96
97        if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
98                /* give control service some credits */
99            GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
100                /* control service is always marked active, it never goes inactive EVER */
101            SET_EP_ACTIVE(pCurEpDist);
102        } else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
103                /* this is the lowest priority data endpoint, save this off for easy access */
104            pCredInfo->pLowestPriEpDist = pCurEpDist;
105        }
106
107        /* Streams have to be created (explicit | implicit)for all kinds
108         * of traffic. BE endpoints are also inactive in the beginning.
109         * When BE traffic starts it creates implicit streams that
110         * redistributes credits.
111         */
112
113        /* note, all other endpoints have minimums set but are initially given NO credits.
114         * Credits will be distributed as traffic activity demands */
115        pCurEpDist = pCurEpDist->pNext;
116    }
117
118    if (pCredInfo->CurrentFreeCredits <= 0) {
119        AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
120        A_ASSERT(FALSE);
121        return;
122    }
123
124        /* reset list */
125    pCurEpDist = pEPList;
126        /* now run through the list and set max operating credit limits for everyone */
127    while (pCurEpDist != NULL) {
128        if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
129                /* control service max is just 1 max message */
130            pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
131        } else {
132                /* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
133                 * the same.
134                 * We use a simple calculation here, we take the remaining credits and
135                 * determine how many max messages this can cover and then set each endpoint's
136                 * normal value equal to half this amount.
137                 * */
138            count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
139            count = count >> 1;
140            count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
141                /* set normal */
142            pCurEpDist->TxCreditsNorm = count;
143
144        }
145        pCurEpDist = pCurEpDist->pNext;
146    }
147
148}
149
150
151/* default credit distribution callback
152 * This callback is invoked whenever endpoints require credit distributions.
153 * A lock is held while this function is invoked, this function shall NOT block.
154 * The pEPDistList is a list of distribution structures in prioritized order as
155 * defined by the call to the HTCSetCreditDistribution() api.
156 *
157 */
158static void ar6000_credit_distribute(void *Context,
159                                     HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
160                                     HTC_CREDIT_DIST_REASON Reason)
161{
162    HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
163    COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
164
165    switch (Reason) {
166        case HTC_CREDIT_DIST_SEND_COMPLETE :
167            pCurEpDist = pEPDistList;
168                /* we are given the start of the endpoint distribution list.
169                 * There may be one or more endpoints to service.
170                 * Run through the list and distribute credits */
171            while (pCurEpDist != NULL) {
172
173                if (pCurEpDist->TxCreditsToDist > 0) {
174                        /* return the credits back to the endpoint */
175                    pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
176                        /* always zero out when we are done */
177                    pCurEpDist->TxCreditsToDist = 0;
178
179                    if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
180                            /* reduce to the assigned limit, previous credit reductions
181                             * could have caused the limit to change */
182                        ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
183                    }
184
185                    if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
186                            /* oversubscribed endpoints need to reduce back to normal */
187                        ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
188                    }
189                }
190
191                pCurEpDist = pCurEpDist->pNext;
192            }
193
194            A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
195
196            break;
197
198        case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
199            RedistributeCredits(pCredInfo,pEPDistList);
200            break;
201        case HTC_CREDIT_DIST_SEEK_CREDITS :
202            SeekCredits(pCredInfo,pEPDistList);
203            break;
204        case HTC_DUMP_CREDIT_STATE :
205            AR_DEBUG_PRINTF(ATH_LOG_INF, ("Credit Distribution, total : %d, free : %d\n",
206                                            pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
207            break;
208        default:
209            break;
210
211    }
212
213}
214
215/* redistribute credits based on activity change */
216static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
217                                HTC_ENDPOINT_CREDIT_DIST *pEPDistList)
218{
219    HTC_ENDPOINT_CREDIT_DIST *pCurEpDist = pEPDistList;
220
221        /* walk through the list and remove credits from inactive endpoints */
222    while (pCurEpDist != NULL) {
223
224        if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
225            if (!IS_EP_ACTIVE(pCurEpDist)) {
226                    /* EP is inactive, reduce credits back to zero */
227                ReduceCredits(pCredInfo, pCurEpDist, 0);
228            }
229        }
230
231        /* NOTE in the active case, we do not need to do anything further,
232         * when an EP goes active and needs credits, HTC will call into
233         * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
234
235        pCurEpDist = pCurEpDist->pNext;
236    }
237
238    A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
239
240}
241
242/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
243static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
244                        HTC_ENDPOINT_CREDIT_DIST *pEPDist)
245{
246    HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
247    int credits = 0;
248    int need;
249
250    do {
251
252        if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
253                /* we never oversubscribe on the control service, this is not
254                 * a high performance path and the target never holds onto control
255                 * credits for too long */
256            break;
257        }
258
259        /* for all other services, we follow a simple algorithm of
260         * 1. checking the free pool for credits
261         * 2. checking lower priority endpoints for credits to take */
262
263        if (pCredInfo->CurrentFreeCredits >= 2 * pEPDist->TxCreditsSeek) {
264                /* try to give more credits than it needs */
265            credits = 2 * pEPDist->TxCreditsSeek;
266        } else {
267                /* give what we can */
268            credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
269        }
270
271        if (credits >= pEPDist->TxCreditsSeek) {
272                /* we found some to fullfill the seek request */
273            break;
274        }
275
276        /* we don't have enough in the free pool, try taking away from lower priority services
277         *
278         * The rule for taking away credits:
279         * 1. Only take from lower priority endpoints
280         * 2. Only take what is allocated above the minimum (never starve an endpoint completely)
281         * 3. Only take what you need.
282         *
283         * */
284
285            /* starting at the lowest priority */
286        pCurEpDist = pCredInfo->pLowestPriEpDist;
287
288            /* work backwards until we hit the endpoint again */
289        while (pCurEpDist != pEPDist) {
290                /* calculate how many we need so far */
291            need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
292
293            if ((pCurEpDist->TxCreditsAssigned - need) > pCurEpDist->TxCreditsMin) {
294                    /* the current one has been allocated more than it's minimum and it
295                     * has enough credits assigned above it's minimum to fullfill our need
296                     * try to take away just enough to fullfill our need */
297                ReduceCredits(pCredInfo,
298                              pCurEpDist,
299                              pCurEpDist->TxCreditsAssigned - need);
300
301                if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
302                        /* we have enough */
303                    break;
304                }
305            }
306
307            pCurEpDist = pCurEpDist->pPrev;
308        }
309
310            /* return what we can get */
311        credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
312
313    } while (FALSE);
314
315        /* did we find some credits? */
316    if (credits) {
317            /* give what we can */
318        GiveCredits(pCredInfo, pEPDist, credits);
319    }
320
321}
322
323/* initialize and setup credit distribution */
324A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo)
325{
326    HTC_SERVICE_ID servicepriority[5];
327
328    A_MEMZERO(pCredInfo,sizeof(COMMON_CREDIT_STATE_INFO));
329
330    servicepriority[0] = WMI_CONTROL_SVC; /* highest */
331    servicepriority[1] = WMI_DATA_VO_SVC;
332    servicepriority[2] = WMI_DATA_VI_SVC;
333    servicepriority[3] = WMI_DATA_BE_SVC;
334    servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
335
336        /* set callbacks and priority list */
337    HTCSetCreditDistribution(HTCHandle,
338                             pCredInfo,
339                             ar6000_credit_distribute,
340                             ar6000_credit_init,
341                             servicepriority,
342                             5);
343
344    return A_OK;
345}
346
347

Archive Download this file



interactive