ath6kl: remove-typedef HTC_ENDPOINT_CREDIT_DIST
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / ath6kl / miscdrv / credit_dist.c
1 //------------------------------------------------------------------------------
2 // <copyright file="credit_dist.c" company="Atheros">
3 // Copyright (c) 2004-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
24 #include "a_config.h"
25 #include "athdefs.h"
26 #include "a_types.h"
27 #include "a_osapi.h"
28 #define ATH_MODULE_NAME misc
29 #include "a_debug.h"
30 #include "htc_api.h"
31 #include "common_drv.h"
32
33 /********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
34
35 #define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
36 #define CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS 1
37
38 #ifdef NO_VO_SERVICE
39 #define DATA_SVCS_USED 3
40 #else
41 #define DATA_SVCS_USED 4
42 #endif
43
44 static void RedistributeCredits(struct common_credit_state_info *pCredInfo,
45 struct htc_endpoint_credit_dist *pEPDistList);
46
47 static void SeekCredits(struct common_credit_state_info *pCredInfo,
48 struct htc_endpoint_credit_dist *pEPDistList);
49
50 /* reduce an ep's credits back to a set limit */
51 static INLINE void ReduceCredits(struct common_credit_state_info *pCredInfo,
52 struct htc_endpoint_credit_dist *pEpDist,
53 int Limit)
54 {
55 int credits;
56
57 /* set the new limit */
58 pEpDist->TxCreditsAssigned = Limit;
59
60 if (pEpDist->TxCredits <= Limit) {
61 return;
62 }
63
64 /* figure out how much to take away */
65 credits = pEpDist->TxCredits - Limit;
66 /* take them away */
67 pEpDist->TxCredits -= credits;
68 pCredInfo->CurrentFreeCredits += credits;
69 }
70
71 /* give an endpoint some credits from the free credit pool */
72 #define GiveCredits(pCredInfo,pEpDist,credits) \
73 { \
74 (pEpDist)->TxCredits += (credits); \
75 (pEpDist)->TxCreditsAssigned += (credits); \
76 (pCredInfo)->CurrentFreeCredits -= (credits); \
77 }
78
79
80 /* default credit init callback.
81 * This function is called in the context of HTCStart() to setup initial (application-specific)
82 * credit distributions */
83 static void ar6000_credit_init(void *Context,
84 struct htc_endpoint_credit_dist *pEPList,
85 int TotalCredits)
86 {
87 struct htc_endpoint_credit_dist *pCurEpDist;
88 int count;
89 struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context;
90
91 pCredInfo->CurrentFreeCredits = TotalCredits;
92 pCredInfo->TotalAvailableCredits = TotalCredits;
93
94 pCurEpDist = pEPList;
95
96 /* run through the list and initialize */
97 while (pCurEpDist != NULL) {
98
99 /* set minimums for each endpoint */
100 pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
101
102 #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
103
104 if (TotalCredits > 4)
105 {
106 if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)){
107 /* assign at least min credits to lower than VO priority services */
108 GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
109 /* force active */
110 SET_EP_ACTIVE(pCurEpDist);
111 }
112 }
113
114 #endif
115
116 if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
117 /* give control service some credits */
118 GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
119 /* control service is always marked active, it never goes inactive EVER */
120 SET_EP_ACTIVE(pCurEpDist);
121 } else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
122 /* this is the lowest priority data endpoint, save this off for easy access */
123 pCredInfo->pLowestPriEpDist = pCurEpDist;
124 }
125
126 /* Streams have to be created (explicit | implicit)for all kinds
127 * of traffic. BE endpoints are also inactive in the beginning.
128 * When BE traffic starts it creates implicit streams that
129 * redistributes credits.
130 */
131
132 /* note, all other endpoints have minimums set but are initially given NO credits.
133 * Credits will be distributed as traffic activity demands */
134 pCurEpDist = pCurEpDist->pNext;
135 }
136
137 if (pCredInfo->CurrentFreeCredits <= 0) {
138 AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
139 A_ASSERT(false);
140 return;
141 }
142
143 /* reset list */
144 pCurEpDist = pEPList;
145 /* now run through the list and set max operating credit limits for everyone */
146 while (pCurEpDist != NULL) {
147 if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
148 /* control service max is just 1 max message */
149 pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
150 } else {
151 /* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
152 * the same.
153 * We use a simple calculation here, we take the remaining credits and
154 * determine how many max messages this can cover and then set each endpoint's
155 * normal value equal to 3/4 this amount.
156 * */
157 count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
158 count = (count * 3) >> 2;
159 count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
160 /* set normal */
161 pCurEpDist->TxCreditsNorm = count;
162
163 }
164 pCurEpDist = pCurEpDist->pNext;
165 }
166
167 }
168
169
170 /* default credit distribution callback
171 * This callback is invoked whenever endpoints require credit distributions.
172 * A lock is held while this function is invoked, this function shall NOT block.
173 * The pEPDistList is a list of distribution structures in prioritized order as
174 * defined by the call to the HTCSetCreditDistribution() api.
175 *
176 */
177 static void ar6000_credit_distribute(void *Context,
178 struct htc_endpoint_credit_dist *pEPDistList,
179 HTC_CREDIT_DIST_REASON Reason)
180 {
181 struct htc_endpoint_credit_dist *pCurEpDist;
182 struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context;
183
184 switch (Reason) {
185 case HTC_CREDIT_DIST_SEND_COMPLETE :
186 pCurEpDist = pEPDistList;
187 /* we are given the start of the endpoint distribution list.
188 * There may be one or more endpoints to service.
189 * Run through the list and distribute credits */
190 while (pCurEpDist != NULL) {
191
192 if (pCurEpDist->TxCreditsToDist > 0) {
193 /* return the credits back to the endpoint */
194 pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
195 /* always zero out when we are done */
196 pCurEpDist->TxCreditsToDist = 0;
197
198 if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
199 /* reduce to the assigned limit, previous credit reductions
200 * could have caused the limit to change */
201 ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
202 }
203
204 if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
205 /* oversubscribed endpoints need to reduce back to normal */
206 ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
207 }
208
209 if (!IS_EP_ACTIVE(pCurEpDist)) {
210 /* endpoint is inactive, now check for messages waiting for credits */
211 if (pCurEpDist->TxQueueDepth == 0) {
212 /* EP is inactive and there are no pending messages,
213 * reduce credits back to zero to recover credits */
214 ReduceCredits(pCredInfo, pCurEpDist, 0);
215 }
216 }
217 }
218
219 pCurEpDist = pCurEpDist->pNext;
220 }
221
222 break;
223
224 case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
225 RedistributeCredits(pCredInfo,pEPDistList);
226 break;
227 case HTC_CREDIT_DIST_SEEK_CREDITS :
228 SeekCredits(pCredInfo,pEPDistList);
229 break;
230 case HTC_DUMP_CREDIT_STATE :
231 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Credit Distribution, total : %d, free : %d\n",
232 pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
233 break;
234 default:
235 break;
236
237 }
238
239 /* sanity checks done after each distribution action */
240 A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
241 A_ASSERT(pCredInfo->CurrentFreeCredits >= 0);
242
243 }
244
245 /* redistribute credits based on activity change */
246 static void RedistributeCredits(struct common_credit_state_info *pCredInfo,
247 struct htc_endpoint_credit_dist *pEPDistList)
248 {
249 struct htc_endpoint_credit_dist *pCurEpDist = pEPDistList;
250
251 /* walk through the list and remove credits from inactive endpoints */
252 while (pCurEpDist != NULL) {
253
254 #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
255
256 if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)) {
257 /* force low priority streams to always be active to retain their minimum credit distribution */
258 SET_EP_ACTIVE(pCurEpDist);
259 }
260 #endif
261
262 if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
263 if (!IS_EP_ACTIVE(pCurEpDist)) {
264 if (pCurEpDist->TxQueueDepth == 0) {
265 /* EP is inactive and there are no pending messages, reduce credits back to zero */
266 ReduceCredits(pCredInfo, pCurEpDist, 0);
267 } else {
268 /* we cannot zero the credits assigned to this EP, but to keep
269 * the credits available for these leftover packets, reduce to
270 * a minimum */
271 ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin);
272 }
273 }
274 }
275
276 /* NOTE in the active case, we do not need to do anything further,
277 * when an EP goes active and needs credits, HTC will call into
278 * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
279
280 pCurEpDist = pCurEpDist->pNext;
281 }
282
283 }
284
285 /* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
286 static void SeekCredits(struct common_credit_state_info *pCredInfo,
287 struct htc_endpoint_credit_dist *pEPDist)
288 {
289 struct htc_endpoint_credit_dist *pCurEpDist;
290 int credits = 0;
291 int need;
292
293 do {
294
295 if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
296 /* we never oversubscribe on the control service, this is not
297 * a high performance path and the target never holds onto control
298 * credits for too long */
299 break;
300 }
301
302 #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
303 if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
304 if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
305 /* limit VI service from oversubscribing */
306 break;
307 }
308 }
309
310 if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
311 if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
312 /* limit VO service from oversubscribing */
313 break;
314 }
315 }
316 #else
317 if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
318 if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
319 (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
320 /* limit VI service from oversubscribing */
321 /* at least one free credit will not be used by VI */
322 break;
323 }
324 }
325
326 if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
327 if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
328 (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
329 /* limit VO service from oversubscribing */
330 /* at least one free credit will not be used by VO */
331 break;
332 }
333 }
334 #endif
335
336 /* for all other services, we follow a simple algorithm of
337 * 1. checking the free pool for credits
338 * 2. checking lower priority endpoints for credits to take */
339
340 /* give what we can */
341 credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
342
343 if (credits >= pEPDist->TxCreditsSeek) {
344 /* we found some to fullfill the seek request */
345 break;
346 }
347
348 /* we don't have enough in the free pool, try taking away from lower priority services
349 *
350 * The rule for taking away credits:
351 * 1. Only take from lower priority endpoints
352 * 2. Only take what is allocated above the minimum (never starve an endpoint completely)
353 * 3. Only take what you need.
354 *
355 * */
356
357 /* starting at the lowest priority */
358 pCurEpDist = pCredInfo->pLowestPriEpDist;
359
360 /* work backwards until we hit the endpoint again */
361 while (pCurEpDist != pEPDist) {
362 /* calculate how many we need so far */
363 need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
364
365 if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) {
366 /* the current one has been allocated more than it's minimum and it
367 * has enough credits assigned above it's minimum to fullfill our need
368 * try to take away just enough to fullfill our need */
369 ReduceCredits(pCredInfo,
370 pCurEpDist,
371 pCurEpDist->TxCreditsAssigned - need);
372
373 if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
374 /* we have enough */
375 break;
376 }
377 }
378
379 pCurEpDist = pCurEpDist->pPrev;
380 }
381
382 /* return what we can get */
383 credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
384
385 } while (false);
386
387 /* did we find some credits? */
388 if (credits) {
389 /* give what we can */
390 GiveCredits(pCredInfo, pEPDist, credits);
391 }
392
393 }
394
395 /* initialize and setup credit distribution */
396 int ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, struct common_credit_state_info *pCredInfo)
397 {
398 HTC_SERVICE_ID servicepriority[5];
399
400 A_MEMZERO(pCredInfo,sizeof(struct common_credit_state_info));
401
402 servicepriority[0] = WMI_CONTROL_SVC; /* highest */
403 servicepriority[1] = WMI_DATA_VO_SVC;
404 servicepriority[2] = WMI_DATA_VI_SVC;
405 servicepriority[3] = WMI_DATA_BE_SVC;
406 servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
407
408 /* set callbacks and priority list */
409 HTCSetCreditDistribution(HTCHandle,
410 pCredInfo,
411 ar6000_credit_distribute,
412 ar6000_credit_init,
413 servicepriority,
414 5);
415
416 return 0;
417 }
418