Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Name: skdim.c | |
4 | * Project: GEnesis, PCI Gigabit Ethernet Adapter | |
5 | * Version: $Revision: 1.5 $ | |
6 | * Date: $Date: 2003/11/28 12:55:40 $ | |
7 | * Purpose: All functions to maintain interrupt moderation | |
8 | * | |
9 | ******************************************************************************/ | |
10 | ||
11 | /****************************************************************************** | |
12 | * | |
13 | * (C)Copyright 1998-2002 SysKonnect GmbH. | |
14 | * (C)Copyright 2002-2003 Marvell. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * The information in this file is provided "AS IS" without warranty. | |
22 | * | |
23 | ******************************************************************************/ | |
24 | ||
25 | /****************************************************************************** | |
26 | * | |
27 | * Description: | |
28 | * | |
29 | * This module is intended to manage the dynamic interrupt moderation on both | |
30 | * GEnesis and Yukon adapters. | |
31 | * | |
32 | * Include File Hierarchy: | |
33 | * | |
34 | * "skdrv1st.h" | |
35 | * "skdrv2nd.h" | |
36 | * | |
37 | ******************************************************************************/ | |
38 | ||
39 | #ifndef lint | |
40 | static const char SysKonnectFileId[] = | |
41 | "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect."; | |
42 | #endif | |
43 | ||
44 | #define __SKADDR_C | |
45 | ||
46 | #ifdef __cplusplus | |
47 | #error C++ is not yet supported. | |
48 | extern "C" { | |
49 | #endif | |
50 | ||
51 | /******************************************************************************* | |
52 | ** | |
53 | ** Includes | |
54 | ** | |
55 | *******************************************************************************/ | |
56 | ||
57 | #ifndef __INC_SKDRV1ST_H | |
58 | #include "h/skdrv1st.h" | |
59 | #endif | |
60 | ||
61 | #ifndef __INC_SKDRV2ND_H | |
62 | #include "h/skdrv2nd.h" | |
63 | #endif | |
64 | ||
65 | #include <linux/kernel_stat.h> | |
66 | ||
67 | /******************************************************************************* | |
68 | ** | |
69 | ** Defines | |
70 | ** | |
71 | *******************************************************************************/ | |
72 | ||
73 | /******************************************************************************* | |
74 | ** | |
75 | ** Typedefs | |
76 | ** | |
77 | *******************************************************************************/ | |
78 | ||
79 | /******************************************************************************* | |
80 | ** | |
81 | ** Local function prototypes | |
82 | ** | |
83 | *******************************************************************************/ | |
84 | ||
85 | static unsigned int GetCurrentSystemLoad(SK_AC *pAC); | |
86 | static SK_U64 GetIsrCalls(SK_AC *pAC); | |
87 | static SK_BOOL IsIntModEnabled(SK_AC *pAC); | |
88 | static void SetCurrIntCtr(SK_AC *pAC); | |
89 | static void EnableIntMod(SK_AC *pAC); | |
90 | static void DisableIntMod(SK_AC *pAC); | |
91 | static void ResizeDimTimerDuration(SK_AC *pAC); | |
92 | static void DisplaySelectedModerationType(SK_AC *pAC); | |
93 | static void DisplaySelectedModerationMask(SK_AC *pAC); | |
94 | static void DisplayDescrRatio(SK_AC *pAC); | |
95 | ||
96 | /******************************************************************************* | |
97 | ** | |
98 | ** Global variables | |
99 | ** | |
100 | *******************************************************************************/ | |
101 | ||
102 | /******************************************************************************* | |
103 | ** | |
104 | ** Local variables | |
105 | ** | |
106 | *******************************************************************************/ | |
107 | ||
108 | /******************************************************************************* | |
109 | ** | |
110 | ** Global functions | |
111 | ** | |
112 | *******************************************************************************/ | |
113 | ||
114 | /******************************************************************************* | |
115 | ** Function : SkDimModerate | |
116 | ** Description : Called in every ISR to check if moderation is to be applied | |
117 | ** or not for the current number of interrupts | |
118 | ** Programmer : Ralph Roesler | |
119 | ** Last Modified: 22-mar-03 | |
120 | ** Returns : void (!) | |
121 | ** Notes : - | |
122 | *******************************************************************************/ | |
123 | ||
124 | void | |
125 | SkDimModerate(SK_AC *pAC) { | |
126 | unsigned int CurrSysLoad = 0; /* expressed in percent */ | |
127 | unsigned int LoadIncrease = 0; /* expressed in percent */ | |
128 | SK_U64 ThresholdInts = 0; | |
129 | SK_U64 IsrCallsPerSec = 0; | |
130 | ||
131 | #define M_DIMINFO pAC->DynIrqModInfo | |
132 | ||
133 | if (!IsIntModEnabled(pAC)) { | |
134 | if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { | |
135 | CurrSysLoad = GetCurrentSystemLoad(pAC); | |
136 | if (CurrSysLoad > 75) { | |
137 | /* | |
138 | ** More than 75% total system load! Enable the moderation | |
139 | ** to shield the system against too many interrupts. | |
140 | */ | |
141 | EnableIntMod(pAC); | |
142 | } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) { | |
143 | LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad); | |
144 | if (LoadIncrease > ((M_DIMINFO.PrevSysLoad * | |
145 | C_INT_MOD_ENABLE_PERCENTAGE) / 100)) { | |
146 | if (CurrSysLoad > 10) { | |
147 | /* | |
148 | ** More than 50% increase with respect to the | |
149 | ** previous load of the system. Most likely this | |
150 | ** is due to our ISR-proc... | |
151 | */ | |
152 | EnableIntMod(pAC); | |
153 | } | |
154 | } | |
155 | } else { | |
156 | /* | |
157 | ** Neither too much system load at all nor too much increase | |
158 | ** with respect to the previous system load. Hence, we can leave | |
159 | ** the ISR-handling like it is without enabling moderation. | |
160 | */ | |
161 | } | |
162 | M_DIMINFO.PrevSysLoad = CurrSysLoad; | |
163 | } | |
164 | } else { | |
165 | if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { | |
166 | ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec * | |
167 | C_INT_MOD_DISABLE_PERCENTAGE) / 100); | |
168 | IsrCallsPerSec = GetIsrCalls(pAC); | |
169 | if (IsrCallsPerSec <= ThresholdInts) { | |
170 | /* | |
171 | ** The number of interrupts within the last second is | |
172 | ** lower than the disable_percentage of the desried | |
173 | ** maxrate. Therefore we can disable the moderation. | |
174 | */ | |
175 | DisableIntMod(pAC); | |
176 | M_DIMINFO.MaxModIntsPerSec = | |
177 | (M_DIMINFO.MaxModIntsPerSecUpperLimit + | |
178 | M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2; | |
179 | } else { | |
180 | /* | |
181 | ** The number of interrupts per sec is the same as expected. | |
182 | ** Evalulate the descriptor-ratio. If it has changed, a resize | |
a58a414f | 183 | ** in the moderation timer might be useful |
1da177e4 LT |
184 | */ |
185 | if (M_DIMINFO.AutoSizing) { | |
186 | ResizeDimTimerDuration(pAC); | |
187 | } | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
192 | /* | |
193 | ** Some information to the log... | |
194 | */ | |
195 | if (M_DIMINFO.DisplayStats) { | |
196 | DisplaySelectedModerationType(pAC); | |
197 | DisplaySelectedModerationMask(pAC); | |
198 | DisplayDescrRatio(pAC); | |
199 | } | |
200 | ||
201 | M_DIMINFO.NbrProcessedDescr = 0; | |
202 | SetCurrIntCtr(pAC); | |
203 | } | |
204 | ||
205 | /******************************************************************************* | |
206 | ** Function : SkDimStartModerationTimer | |
207 | ** Description : Starts the audit-timer for the dynamic interrupt moderation | |
208 | ** Programmer : Ralph Roesler | |
209 | ** Last Modified: 22-mar-03 | |
210 | ** Returns : void (!) | |
211 | ** Notes : - | |
212 | *******************************************************************************/ | |
213 | ||
214 | void | |
215 | SkDimStartModerationTimer(SK_AC *pAC) { | |
216 | SK_EVPARA EventParam; /* Event struct for timer event */ | |
217 | ||
218 | SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam)); | |
219 | EventParam.Para32[0] = SK_DRV_MODERATION_TIMER; | |
220 | SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer, | |
221 | SK_DRV_MODERATION_TIMER_LENGTH, | |
222 | SKGE_DRV, SK_DRV_TIMER, EventParam); | |
223 | } | |
224 | ||
225 | /******************************************************************************* | |
226 | ** Function : SkDimEnableModerationIfNeeded | |
227 | ** Description : Either enables or disables moderation | |
228 | ** Programmer : Ralph Roesler | |
229 | ** Last Modified: 22-mar-03 | |
230 | ** Returns : void (!) | |
231 | ** Notes : This function is called when a particular adapter is opened | |
232 | ** There is no Disable function, because when all interrupts | |
233 | ** might be disable, the moderation timer has no meaning at all | |
234 | ******************************************************************************/ | |
235 | ||
236 | void | |
237 | SkDimEnableModerationIfNeeded(SK_AC *pAC) { | |
238 | ||
239 | if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) { | |
240 | EnableIntMod(pAC); /* notification print in this function */ | |
241 | } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { | |
242 | SkDimStartModerationTimer(pAC); | |
243 | if (M_DIMINFO.DisplayStats) { | |
244 | printk("Dynamic moderation has been enabled\n"); | |
245 | } | |
246 | } else { | |
247 | if (M_DIMINFO.DisplayStats) { | |
248 | printk("No moderation has been enabled\n"); | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | /******************************************************************************* | |
254 | ** Function : SkDimDisplayModerationSettings | |
255 | ** Description : Displays the current settings regaring interrupt moderation | |
256 | ** Programmer : Ralph Roesler | |
257 | ** Last Modified: 22-mar-03 | |
258 | ** Returns : void (!) | |
259 | ** Notes : - | |
260 | *******************************************************************************/ | |
261 | ||
262 | void | |
263 | SkDimDisplayModerationSettings(SK_AC *pAC) { | |
264 | DisplaySelectedModerationType(pAC); | |
265 | DisplaySelectedModerationMask(pAC); | |
266 | } | |
267 | ||
268 | /******************************************************************************* | |
269 | ** | |
270 | ** Local functions | |
271 | ** | |
272 | *******************************************************************************/ | |
273 | ||
274 | /******************************************************************************* | |
275 | ** Function : GetCurrentSystemLoad | |
276 | ** Description : Retrieves the current system load of the system. This load | |
277 | ** is evaluated for all processors within the system. | |
278 | ** Programmer : Ralph Roesler | |
279 | ** Last Modified: 22-mar-03 | |
280 | ** Returns : unsigned int: load expressed in percentage | |
281 | ** Notes : The possible range being returned is from 0 up to 100. | |
282 | ** Whereas 0 means 'no load at all' and 100 'system fully loaded' | |
283 | ** It is impossible to determine what actually causes the system | |
284 | ** to be in 100%, but maybe that is due to too much interrupts. | |
285 | *******************************************************************************/ | |
286 | ||
287 | static unsigned int | |
288 | GetCurrentSystemLoad(SK_AC *pAC) { | |
289 | unsigned long jif = jiffies; | |
290 | unsigned int UserTime = 0; | |
291 | unsigned int SystemTime = 0; | |
292 | unsigned int NiceTime = 0; | |
293 | unsigned int IdleTime = 0; | |
294 | unsigned int TotalTime = 0; | |
295 | unsigned int UsedTime = 0; | |
296 | unsigned int SystemLoad = 0; | |
297 | ||
298 | /* unsigned int NbrCpu = 0; */ | |
299 | ||
300 | /* | |
301 | ** The following lines have been commented out, because | |
302 | ** from kernel 2.5.44 onwards, the kernel-owned structure | |
303 | ** | |
304 | ** struct kernel_stat kstat | |
305 | ** | |
306 | ** is not marked as an exported symbol in the file | |
307 | ** | |
308 | ** kernel/ksyms.c | |
309 | ** | |
310 | ** As a consequence, using this driver as KLM is not possible | |
311 | ** and any access of the structure kernel_stat via the | |
312 | ** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided. | |
313 | ** | |
314 | ** The kstat-information might be added again in future | |
315 | ** versions of the 2.5.xx kernel, but for the time being, | |
316 | ** number of interrupts will serve as indication how much | |
317 | ** load we currently have... | |
318 | ** | |
319 | ** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) { | |
320 | ** UserTime = UserTime + kstat_cpu(NbrCpu).cpustat.user; | |
321 | ** NiceTime = NiceTime + kstat_cpu(NbrCpu).cpustat.nice; | |
322 | ** SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system; | |
323 | ** } | |
324 | */ | |
325 | SK_U64 ThresholdInts = 0; | |
326 | SK_U64 IsrCallsPerSec = 0; | |
327 | ||
328 | ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec * | |
329 | C_INT_MOD_ENABLE_PERCENTAGE) + 100); | |
330 | IsrCallsPerSec = GetIsrCalls(pAC); | |
331 | if (IsrCallsPerSec >= ThresholdInts) { | |
332 | /* | |
333 | ** We do not know how much the real CPU-load is! | |
334 | ** Return 80% as a default in order to activate DIM | |
335 | */ | |
336 | SystemLoad = 80; | |
337 | return (SystemLoad); | |
338 | } | |
339 | ||
340 | UsedTime = UserTime + NiceTime + SystemTime; | |
341 | ||
342 | IdleTime = jif * num_online_cpus() - UsedTime; | |
343 | TotalTime = UsedTime + IdleTime; | |
344 | ||
345 | SystemLoad = ( 100 * (UsedTime - M_DIMINFO.PrevUsedTime) ) / | |
346 | (TotalTime - M_DIMINFO.PrevTotalTime); | |
347 | ||
348 | if (M_DIMINFO.DisplayStats) { | |
349 | printk("Current system load is: %u\n", SystemLoad); | |
350 | } | |
351 | ||
352 | M_DIMINFO.PrevTotalTime = TotalTime; | |
353 | M_DIMINFO.PrevUsedTime = UsedTime; | |
354 | ||
355 | return (SystemLoad); | |
356 | } | |
357 | ||
358 | /******************************************************************************* | |
359 | ** Function : GetIsrCalls | |
360 | ** Description : Depending on the selected moderation mask, this function will | |
361 | ** return the number of interrupts handled in the previous time- | |
362 | ** frame. This evaluated number is based on the current number | |
363 | ** of interrupts stored in PNMI-context and the previous stored | |
364 | ** interrupts. | |
365 | ** Programmer : Ralph Roesler | |
366 | ** Last Modified: 23-mar-03 | |
367 | ** Returns : int: the number of interrupts being executed in the last | |
368 | ** timeframe | |
369 | ** Notes : It makes only sense to call this function, when dynamic | |
370 | ** interrupt moderation is applied | |
371 | *******************************************************************************/ | |
372 | ||
373 | static SK_U64 | |
374 | GetIsrCalls(SK_AC *pAC) { | |
375 | SK_U64 RxPort0IntDiff = 0; | |
376 | SK_U64 RxPort1IntDiff = 0; | |
377 | SK_U64 TxPort0IntDiff = 0; | |
378 | SK_U64 TxPort1IntDiff = 0; | |
379 | ||
380 | if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) { | |
381 | if (pAC->GIni.GIMacsFound == 2) { | |
382 | TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - | |
383 | pAC->DynIrqModInfo.PrevPort1TxIntrCts; | |
384 | } | |
385 | TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - | |
386 | pAC->DynIrqModInfo.PrevPort0TxIntrCts; | |
387 | } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) { | |
388 | if (pAC->GIni.GIMacsFound == 2) { | |
389 | RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - | |
390 | pAC->DynIrqModInfo.PrevPort1RxIntrCts; | |
391 | } | |
392 | RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - | |
393 | pAC->DynIrqModInfo.PrevPort0RxIntrCts; | |
394 | } else { | |
395 | if (pAC->GIni.GIMacsFound == 2) { | |
396 | RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - | |
397 | pAC->DynIrqModInfo.PrevPort1RxIntrCts; | |
398 | TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - | |
399 | pAC->DynIrqModInfo.PrevPort1TxIntrCts; | |
400 | } | |
401 | RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - | |
402 | pAC->DynIrqModInfo.PrevPort0RxIntrCts; | |
403 | TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - | |
404 | pAC->DynIrqModInfo.PrevPort0TxIntrCts; | |
405 | } | |
406 | ||
407 | return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff); | |
408 | } | |
409 | ||
410 | /******************************************************************************* | |
411 | ** Function : GetRxCalls | |
412 | ** Description : This function will return the number of times a receive inter- | |
413 | ** rupt was processed. This is needed to evaluate any resizing | |
414 | ** factor. | |
415 | ** Programmer : Ralph Roesler | |
416 | ** Last Modified: 23-mar-03 | |
417 | ** Returns : SK_U64: the number of RX-ints being processed | |
418 | ** Notes : It makes only sense to call this function, when dynamic | |
419 | ** interrupt moderation is applied | |
420 | *******************************************************************************/ | |
421 | ||
422 | static SK_U64 | |
423 | GetRxCalls(SK_AC *pAC) { | |
424 | SK_U64 RxPort0IntDiff = 0; | |
425 | SK_U64 RxPort1IntDiff = 0; | |
426 | ||
427 | if (pAC->GIni.GIMacsFound == 2) { | |
428 | RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - | |
429 | pAC->DynIrqModInfo.PrevPort1RxIntrCts; | |
430 | } | |
431 | RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - | |
432 | pAC->DynIrqModInfo.PrevPort0RxIntrCts; | |
433 | ||
434 | return (RxPort0IntDiff + RxPort1IntDiff); | |
435 | } | |
436 | ||
437 | /******************************************************************************* | |
438 | ** Function : SetCurrIntCtr | |
439 | ** Description : Will store the current number orf occured interrupts in the | |
440 | ** adapter context. This is needed to evaluated the number of | |
441 | ** interrupts within a current timeframe. | |
442 | ** Programmer : Ralph Roesler | |
443 | ** Last Modified: 23-mar-03 | |
444 | ** Returns : void (!) | |
445 | ** Notes : - | |
446 | *******************************************************************************/ | |
447 | ||
448 | static void | |
449 | SetCurrIntCtr(SK_AC *pAC) { | |
450 | if (pAC->GIni.GIMacsFound == 2) { | |
451 | pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts; | |
452 | pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts; | |
453 | } | |
454 | pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts; | |
455 | pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts; | |
456 | } | |
457 | ||
458 | /******************************************************************************* | |
459 | ** Function : IsIntModEnabled() | |
460 | ** Description : Retrieves the current value of the interrupts moderation | |
461 | ** command register. Its content determines whether any | |
462 | ** moderation is running or not. | |
463 | ** Programmer : Ralph Roesler | |
464 | ** Last Modified: 23-mar-03 | |
465 | ** Returns : SK_TRUE : if mod timer running | |
466 | ** SK_FALSE : if no moderation is being performed | |
467 | ** Notes : - | |
468 | *******************************************************************************/ | |
469 | ||
470 | static SK_BOOL | |
471 | IsIntModEnabled(SK_AC *pAC) { | |
472 | unsigned long CtrCmd; | |
473 | ||
474 | SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd); | |
475 | if ((CtrCmd & TIM_START) == TIM_START) { | |
476 | return SK_TRUE; | |
477 | } else { | |
478 | return SK_FALSE; | |
479 | } | |
480 | } | |
481 | ||
482 | /******************************************************************************* | |
483 | ** Function : EnableIntMod() | |
484 | ** Description : Enables the interrupt moderation using the values stored in | |
485 | ** in the pAC->DynIntMod data structure | |
486 | ** Programmer : Ralph Roesler | |
487 | ** Last Modified: 22-mar-03 | |
488 | ** Returns : - | |
489 | ** Notes : - | |
490 | *******************************************************************************/ | |
491 | ||
492 | static void | |
493 | EnableIntMod(SK_AC *pAC) { | |
494 | unsigned long ModBase; | |
495 | ||
496 | if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { | |
497 | ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec; | |
498 | } else { | |
499 | ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec; | |
500 | } | |
501 | ||
502 | SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); | |
503 | SK_OUT32(pAC->IoBase, B2_IRQM_MSK, pAC->DynIrqModInfo.MaskIrqModeration); | |
504 | SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START); | |
505 | if (M_DIMINFO.DisplayStats) { | |
506 | printk("Enabled interrupt moderation (%i ints/sec)\n", | |
507 | M_DIMINFO.MaxModIntsPerSec); | |
508 | } | |
509 | } | |
510 | ||
511 | /******************************************************************************* | |
512 | ** Function : DisableIntMod() | |
513 | ** Description : Disbles the interrupt moderation independent of what inter- | |
514 | ** rupts are running or not | |
515 | ** Programmer : Ralph Roesler | |
516 | ** Last Modified: 23-mar-03 | |
517 | ** Returns : - | |
518 | ** Notes : - | |
519 | *******************************************************************************/ | |
520 | ||
521 | static void | |
522 | DisableIntMod(SK_AC *pAC) { | |
523 | ||
524 | SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP); | |
525 | if (M_DIMINFO.DisplayStats) { | |
526 | printk("Disabled interrupt moderation\n"); | |
527 | } | |
528 | } | |
529 | ||
530 | /******************************************************************************* | |
531 | ** Function : ResizeDimTimerDuration(); | |
532 | ** Description : Checks the current used descriptor ratio and resizes the | |
533 | ** duration timer (longer/smaller) if possible. | |
534 | ** Programmer : Ralph Roesler | |
535 | ** Last Modified: 23-mar-03 | |
536 | ** Returns : - | |
537 | ** Notes : There are both maximum and minimum timer duration value. | |
538 | ** This function assumes that interrupt moderation is already | |
539 | ** enabled! | |
540 | *******************************************************************************/ | |
541 | ||
542 | static void | |
543 | ResizeDimTimerDuration(SK_AC *pAC) { | |
544 | SK_BOOL IncreaseTimerDuration; | |
545 | int TotalMaxNbrDescr; | |
546 | int UsedDescrRatio; | |
547 | int RatioDiffAbs; | |
548 | int RatioDiffRel; | |
549 | int NewMaxModIntsPerSec; | |
550 | int ModAdjValue; | |
551 | long ModBase; | |
552 | ||
553 | /* | |
554 | ** Check first if we are allowed to perform any modification | |
555 | */ | |
556 | if (IsIntModEnabled(pAC)) { | |
557 | if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) { | |
558 | return; | |
559 | } else { | |
560 | if (M_DIMINFO.ModJustEnabled) { | |
561 | M_DIMINFO.ModJustEnabled = SK_FALSE; | |
562 | return; | |
563 | } | |
564 | } | |
565 | } | |
566 | ||
567 | /* | |
568 | ** If we got until here, we have to evaluate the amount of the | |
569 | ** descriptor ratio change... | |
570 | */ | |
571 | TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC); | |
572 | UsedDescrRatio = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr; | |
573 | ||
574 | if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) { | |
575 | RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio); | |
576 | RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio; | |
577 | M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; | |
578 | IncreaseTimerDuration = SK_FALSE; /* in other words: DECREASE */ | |
579 | } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) { | |
580 | RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio); | |
581 | RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio; | |
582 | M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; | |
583 | IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */ | |
584 | } else { | |
585 | RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio); | |
586 | RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio; | |
587 | M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio; | |
588 | IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */ | |
589 | } | |
590 | ||
591 | /* | |
592 | ** Now we can determine the change in percent | |
593 | */ | |
594 | if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) { | |
595 | ModAdjValue = 1; /* 1% change - maybe some other value in future */ | |
596 | } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) { | |
597 | ModAdjValue = 1; /* 1% change - maybe some other value in future */ | |
598 | } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) { | |
599 | ModAdjValue = 1; /* 1% change - maybe some other value in future */ | |
600 | } else { | |
601 | ModAdjValue = 1; /* 1% change - maybe some other value in future */ | |
602 | } | |
603 | ||
604 | if (IncreaseTimerDuration) { | |
605 | NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec + | |
606 | (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100; | |
607 | } else { | |
608 | NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec - | |
609 | (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100; | |
610 | } | |
611 | ||
612 | /* | |
613 | ** Check if we exceed boundaries... | |
614 | */ | |
615 | if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) || | |
616 | (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) { | |
617 | if (M_DIMINFO.DisplayStats) { | |
618 | printk("Cannot change ModTim from %i to %i ints/sec\n", | |
619 | M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec); | |
620 | } | |
621 | return; | |
622 | } else { | |
623 | if (M_DIMINFO.DisplayStats) { | |
624 | printk("Resized ModTim from %i to %i ints/sec\n", | |
625 | M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec); | |
626 | } | |
627 | } | |
628 | ||
629 | M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec; | |
630 | ||
631 | if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { | |
632 | ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec; | |
633 | } else { | |
634 | ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec; | |
635 | } | |
636 | ||
637 | /* | |
638 | ** We do not need to touch any other registers | |
639 | */ | |
640 | SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); | |
641 | } | |
642 | ||
643 | /******************************************************************************* | |
644 | ** Function : DisplaySelectedModerationType() | |
645 | ** Description : Displays what type of moderation we have | |
646 | ** Programmer : Ralph Roesler | |
647 | ** Last Modified: 23-mar-03 | |
648 | ** Returns : void! | |
649 | ** Notes : - | |
650 | *******************************************************************************/ | |
651 | ||
652 | static void | |
653 | DisplaySelectedModerationType(SK_AC *pAC) { | |
654 | ||
655 | if (pAC->DynIrqModInfo.DisplayStats) { | |
656 | if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) { | |
657 | printk("Static int moderation runs with %i INTS/sec\n", | |
658 | pAC->DynIrqModInfo.MaxModIntsPerSec); | |
659 | } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) { | |
660 | if (IsIntModEnabled(pAC)) { | |
661 | printk("Dynamic int moderation runs with %i INTS/sec\n", | |
662 | pAC->DynIrqModInfo.MaxModIntsPerSec); | |
663 | } else { | |
664 | printk("Dynamic int moderation currently not applied\n"); | |
665 | } | |
666 | } else { | |
667 | printk("No interrupt moderation selected!\n"); | |
668 | } | |
669 | } | |
670 | } | |
671 | ||
672 | /******************************************************************************* | |
673 | ** Function : DisplaySelectedModerationMask() | |
674 | ** Description : Displays what interrupts are moderated | |
675 | ** Programmer : Ralph Roesler | |
676 | ** Last Modified: 23-mar-03 | |
677 | ** Returns : void! | |
678 | ** Notes : - | |
679 | *******************************************************************************/ | |
680 | ||
681 | static void | |
682 | DisplaySelectedModerationMask(SK_AC *pAC) { | |
683 | ||
684 | if (pAC->DynIrqModInfo.DisplayStats) { | |
685 | if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) { | |
686 | switch (pAC->DynIrqModInfo.MaskIrqModeration) { | |
687 | case IRQ_MASK_TX_ONLY: | |
688 | printk("Only Tx-interrupts are moderated\n"); | |
689 | break; | |
690 | case IRQ_MASK_RX_ONLY: | |
691 | printk("Only Rx-interrupts are moderated\n"); | |
692 | break; | |
693 | case IRQ_MASK_SP_ONLY: | |
694 | printk("Only special-interrupts are moderated\n"); | |
695 | break; | |
696 | case IRQ_MASK_TX_RX: | |
697 | printk("Tx- and Rx-interrupts are moderated\n"); | |
698 | break; | |
699 | case IRQ_MASK_SP_RX: | |
700 | printk("Special- and Rx-interrupts are moderated\n"); | |
701 | break; | |
702 | case IRQ_MASK_SP_TX: | |
703 | printk("Special- and Tx-interrupts are moderated\n"); | |
704 | break; | |
705 | case IRQ_MASK_RX_TX_SP: | |
706 | printk("All Rx-, Tx and special-interrupts are moderated\n"); | |
707 | break; | |
708 | default: | |
709 | printk("Don't know what is moderated\n"); | |
710 | break; | |
711 | } | |
712 | } else { | |
713 | printk("No specific interrupts masked for moderation\n"); | |
714 | } | |
715 | } | |
716 | } | |
717 | ||
718 | /******************************************************************************* | |
719 | ** Function : DisplayDescrRatio | |
720 | ** Description : Like the name states... | |
721 | ** Programmer : Ralph Roesler | |
722 | ** Last Modified: 23-mar-03 | |
723 | ** Returns : void! | |
724 | ** Notes : - | |
725 | *******************************************************************************/ | |
726 | ||
727 | static void | |
728 | DisplayDescrRatio(SK_AC *pAC) { | |
729 | int TotalMaxNbrDescr = 0; | |
730 | ||
731 | if (pAC->DynIrqModInfo.DisplayStats) { | |
732 | TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC); | |
733 | printk("Ratio descriptors: %i/%i\n", | |
734 | M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr); | |
735 | } | |
736 | } | |
737 | ||
738 | /******************************************************************************* | |
739 | ** | |
740 | ** End of file | |
741 | ** | |
742 | *******************************************************************************/ |