diff options
Diffstat (limited to 'drivers/net/sk98lin/skdim.c')
-rw-r--r-- | drivers/net/sk98lin/skdim.c | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c new file mode 100644 index 000000000000..37ce03fb8de3 --- /dev/null +++ b/drivers/net/sk98lin/skdim.c | |||
@@ -0,0 +1,742 @@ | |||
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 | ||
183 | ** in the moderation timer might be useful | ||
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 regarding 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 : Disables 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 | *******************************************************************************/ | ||