Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / drivers / net / sk98lin / skdim.c
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 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 *******************************************************************************/