patch-2.4.23 linux-2.4.23/drivers/net/sk98lin/skdim.c

Next file: linux-2.4.23/drivers/net/sk98lin/skge.c
Previous file: linux-2.4.23/drivers/net/sk98lin/skcsum.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/net/sk98lin/skdim.c linux-2.4.23/drivers/net/sk98lin/skdim.c
@@ -0,0 +1,737 @@
+/******************************************************************************
+ *
+ * Name:	skdim.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.2 $
+ * Date:	$Date: 2003/08/21 12:35:05 $
+ * Purpose:	All functions to maintain interrupt moderation
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	
+ *	$Log: skdim.c,v $
+ *	Revision 1.2  2003/08/21 12:35:05  mlindner
+ *	Fix: Corrected CPU detection and compile errors on single CPU machines
+ *	
+ *	Revision 1.1  2003/07/18 13:39:55  rroesler
+ *	Fix: Re-enter after CVS crash
+ *	
+ *	Revision 1.4  2003/07/07 09:45:47  rroesler
+ *	Fix: Compiler warnings corrected
+ *	
+ *	Revision 1.3  2003/06/10 09:16:40  rroesler
+ *	Adapt GetCurrentSystemLoad() to NOT access the kernels
+ *	kstat-structure in kernel 2.5/2.6. This must be done
+ *	due to a not exported symbol. Instead of evaluating the
+ *	SystemLoad directly, the nbr of interrupts is used as
+ *	a rough basis for the load.
+ *	
+ *
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage the dynamic interrupt moderation on both   
+ * GEnesis and Yukon adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skdim.c,v 1.2 2003/08/21 12:35:05 mlindner Exp $ (C) SysKonnect.";
+#endif
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Includes
+**
+*******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#include "h/skdrv1st.h"
+#endif
+
+#ifndef __INC_SKDRV2ND_H
+#include "h/skdrv2nd.h"
+#endif
+
+#include	<linux/kernel_stat.h>
+
+/*******************************************************************************
+**
+** Defines
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Typedefs
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local function prototypes 
+**
+*******************************************************************************/
+
+static unsigned int GetCurrentSystemLoad(SK_AC *pAC);
+static SK_U64       GetIsrCalls(SK_AC *pAC);
+static SK_BOOL      IsIntModEnabled(SK_AC *pAC);
+static void         SetCurrIntCtr(SK_AC *pAC);
+static void         EnableIntMod(SK_AC *pAC); 
+static void         DisableIntMod(SK_AC *pAC);
+static void         ResizeDimTimerDuration(SK_AC *pAC);
+static void         DisplaySelectedModerationType(SK_AC *pAC);
+static void         DisplaySelectedModerationMask(SK_AC *pAC);
+static void         DisplayDescrRatio(SK_AC *pAC);
+
+/*******************************************************************************
+**
+** Global variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Global functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : SkDimModerate
+** Description  : Called in every ISR to check if moderation is to be applied
+**                or not for the current number of interrupts
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimModerate(SK_AC *pAC) {
+    unsigned int CurrSysLoad    = 0;  /* expressed in percent */
+    unsigned int LoadIncrease   = 0;  /* expressed in percent */
+    SK_U64       ThresholdInts  = 0;
+    SK_U64       IsrCallsPerSec = 0;
+
+#define M_DIMINFO pAC->DynIrqModInfo
+
+    if (!IsIntModEnabled(pAC)) {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            CurrSysLoad = GetCurrentSystemLoad(pAC);
+            if (CurrSysLoad > 75) {
+                    /* 
+                    ** More than 75% total system load! Enable the moderation 
+                    ** to shield the system against too many interrupts.
+                    */
+                    EnableIntMod(pAC);
+            } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) {
+                LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad);
+                if (LoadIncrease > ((M_DIMINFO.PrevSysLoad *
+                                         C_INT_MOD_ENABLE_PERCENTAGE) / 100)) {
+                    if (CurrSysLoad > 10) {
+                        /* 
+                        ** More than 50% increase with respect to the 
+                        ** previous load of the system. Most likely this 
+                        ** is due to our ISR-proc...
+                        */
+                        EnableIntMod(pAC);
+                    }
+                }
+            } else {
+                /*
+                ** Neither too much system load at all nor too much increase
+                ** with respect to the previous system load. Hence, we can leave
+                ** the ISR-handling like it is without enabling moderation.
+                */
+            }
+            M_DIMINFO.PrevSysLoad = CurrSysLoad;
+        }   
+    } else {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            ThresholdInts  = ((M_DIMINFO.MaxModIntsPerSec *
+                                   C_INT_MOD_DISABLE_PERCENTAGE) / 100);
+            IsrCallsPerSec = GetIsrCalls(pAC);
+            if (IsrCallsPerSec <= ThresholdInts) {
+                /* 
+                ** The number of interrupts within the last second is 
+                ** lower than the disable_percentage of the desried 
+                ** maxrate. Therefore we can disable the moderation.
+                */
+                DisableIntMod(pAC);
+                M_DIMINFO.MaxModIntsPerSec = 
+                   (M_DIMINFO.MaxModIntsPerSecUpperLimit +
+                    M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2;
+            } else {
+                /*
+                ** The number of interrupts per sec is the same as expected.
+                ** Evalulate the descriptor-ratio. If it has changed, a resize 
+                ** in the moderation timer might be usefull
+                */
+                if (M_DIMINFO.AutoSizing) {
+                    ResizeDimTimerDuration(pAC);
+                }
+            }
+        }
+    }
+
+    /*
+    ** Some information to the log...
+    */
+    if (M_DIMINFO.DisplayStats) {
+        DisplaySelectedModerationType(pAC);
+        DisplaySelectedModerationMask(pAC);
+        DisplayDescrRatio(pAC);
+    }
+
+    M_DIMINFO.NbrProcessedDescr = 0; 
+    SetCurrIntCtr(pAC);
+}
+
+/*******************************************************************************
+** Function     : SkDimStartModerationTimer
+** Description  : Starts the audit-timer for the dynamic interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimStartModerationTimer(SK_AC *pAC) {
+    SK_EVPARA    EventParam;   /* Event struct for timer event */
+ 
+    SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+    EventParam.Para32[0] = SK_DRV_MODERATION_TIMER;
+    SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer,
+                 SK_DRV_MODERATION_TIMER_LENGTH,
+                 SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*******************************************************************************
+** Function     : SkDimEnableModerationIfNeeded
+** Description  : Either enables or disables moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : This function is called when a particular adapter is opened
+**                There is no Disable function, because when all interrupts 
+**                might be disable, the moderation timer has no meaning at all
+******************************************************************************/
+
+void
+SkDimEnableModerationIfNeeded(SK_AC *pAC) {
+
+    if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) {
+        EnableIntMod(pAC);   /* notification print in this function */
+    } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+        SkDimStartModerationTimer(pAC);
+        if (M_DIMINFO.DisplayStats) {
+            printk("Dynamic moderation has been enabled\n");
+        }
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("No moderation has been enabled\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : SkDimDisplayModerationSettings
+** Description  : Displays the current settings regaring interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimDisplayModerationSettings(SK_AC *pAC) {
+    DisplaySelectedModerationType(pAC);
+    DisplaySelectedModerationMask(pAC);
+}
+
+/*******************************************************************************
+**
+** Local functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : GetCurrentSystemLoad
+** Description  : Retrieves the current system load of the system. This load
+**                is evaluated for all processors within the system.
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : unsigned int: load expressed in percentage
+** Notes        : The possible range being returned is from 0 up to 100.
+**                Whereas 0 means 'no load at all' and 100 'system fully loaded'
+**                It is impossible to determine what actually causes the system
+**                to be in 100%, but maybe that is due to too much interrupts.
+*******************************************************************************/
+
+static unsigned int
+GetCurrentSystemLoad(SK_AC *pAC) {
+	unsigned long jif         = jiffies;
+	unsigned int  UserTime    = 0;
+	unsigned int  SystemTime  = 0;
+	unsigned int  NiceTime    = 0;
+	unsigned int  IdleTime    = 0;
+	unsigned int  TotalTime   = 0;
+	unsigned int  UsedTime    = 0;
+	unsigned int  SystemLoad  = 0;
+#ifdef CONFIG_SMP
+	unsigned int  SKNumCpus   = smp_num_cpus;
+#else
+	unsigned int  SKNumCpus   = 1;
+#endif
+
+	unsigned int  NbrCpu      = 0;
+
+    for (NbrCpu = 0; NbrCpu < SKNumCpus; NbrCpu++) {
+        UserTime   = UserTime   + kstat.per_cpu_user[NbrCpu];
+        NiceTime   = NiceTime   + kstat.per_cpu_nice[NbrCpu];
+        SystemTime = SystemTime + kstat.per_cpu_system[NbrCpu];
+    }
+
+	UsedTime  = UserTime + NiceTime + SystemTime;
+
+	IdleTime  = jif * SKNumCpus - UsedTime;
+	TotalTime = UsedTime + IdleTime;
+
+	SystemLoad = ( 100 * (UsedTime  - M_DIMINFO.PrevUsedTime) ) /
+						(TotalTime - M_DIMINFO.PrevTotalTime);
+
+	if (M_DIMINFO.DisplayStats) {
+		printk("Current system load is: %u\n", SystemLoad);
+	}
+
+	M_DIMINFO.PrevTotalTime = TotalTime;
+	M_DIMINFO.PrevUsedTime  = UsedTime;
+
+	return (SystemLoad);
+}
+
+/*******************************************************************************
+** Function     : GetIsrCalls
+** Description  : Depending on the selected moderation mask, this function will
+**                return the number of interrupts handled in the previous time-
+**                frame. This evaluated number is based on the current number 
+**                of interrupts stored in PNMI-context and the previous stored 
+**                interrupts.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : int:   the number of interrupts being executed in the last
+**                       timeframe
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetIsrCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+    SK_U64   TxPort0IntDiff = 0;
+    SK_U64   TxPort1IntDiff = 0;
+
+    if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        }
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+        }
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+    } else {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        } 
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    }
+
+    return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : GetRxCalls
+** Description  : This function will return the number of times a receive inter-
+**                rupt was processed. This is needed to evaluate any resizing 
+**                factor.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_U64: the number of RX-ints being processed
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetRxCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+
+    if (pAC->GIni.GIMacsFound == 2) {
+        RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+    }
+    RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                     pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+
+    return (RxPort0IntDiff + RxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : SetCurrIntCtr
+** Description  : Will store the current number orf occured interrupts in the 
+**                adapter context. This is needed to evaluated the number of 
+**                interrupts within a current timeframe.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+static void
+SetCurrIntCtr(SK_AC *pAC) {
+    if (pAC->GIni.GIMacsFound == 2) {
+        pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts;
+        pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts;
+    } 
+    pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts;
+    pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts;
+}
+
+/*******************************************************************************
+** Function     : IsIntModEnabled()
+** Description  : Retrieves the current value of the interrupts moderation
+**                command register. Its content determines whether any 
+**                moderation is running or not.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_TRUE  : if mod timer running
+**                SK_FALSE : if no moderation is being performed
+** Notes        : -
+*******************************************************************************/
+
+static SK_BOOL
+IsIntModEnabled(SK_AC *pAC) {
+    unsigned long CtrCmd;
+
+    SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd);
+    if ((CtrCmd & TIM_START) == TIM_START) {
+       return SK_TRUE;
+    } else {
+       return SK_FALSE;
+    }
+}
+
+/*******************************************************************************
+** Function     : EnableIntMod()
+** Description  : Enables the interrupt moderation using the values stored in
+**                in the pAC->DynIntMod data structure
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void
+EnableIntMod(SK_AC *pAC) {
+    unsigned long ModBase;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+       ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+       ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI,  ModBase);
+    SK_OUT32(pAC->IoBase, B2_IRQM_MSK,  pAC->DynIrqModInfo.MaskIrqModeration);
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Enabled interrupt moderation (%i ints/sec)\n",
+               M_DIMINFO.MaxModIntsPerSec);
+    }
+}
+
+/*******************************************************************************
+** Function     : DisableIntMod()
+** Description  : Disbles the interrupt moderation independent of what inter-
+**                rupts are running or not
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void 
+DisableIntMod(SK_AC *pAC) {
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Disabled interrupt moderation\n");
+    }
+} 
+
+/*******************************************************************************
+** Function     : ResizeDimTimerDuration();
+** Description  : Checks the current used descriptor ratio and resizes the 
+**                duration timer (longer/smaller) if possible. 
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : There are both maximum and minimum timer duration value. 
+**                This function assumes that interrupt moderation is already
+**                enabled!
+*******************************************************************************/
+
+static void 
+ResizeDimTimerDuration(SK_AC *pAC) {
+    SK_BOOL IncreaseTimerDuration;
+    int     TotalMaxNbrDescr;
+    int     UsedDescrRatio;
+    int     RatioDiffAbs;
+    int     RatioDiffRel;
+    int     NewMaxModIntsPerSec;
+    int     ModAdjValue;
+    long    ModBase;
+
+    /*
+    ** Check first if we are allowed to perform any modification
+    */
+    if (IsIntModEnabled(pAC)) { 
+        if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) {
+            return; 
+        } else {
+            if (M_DIMINFO.ModJustEnabled) {
+                M_DIMINFO.ModJustEnabled = SK_FALSE;
+                return;
+            }
+        }
+    }
+
+    /*
+    ** If we got until here, we have to evaluate the amount of the
+    ** descriptor ratio change...
+    */
+    TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+    UsedDescrRatio   = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr;
+
+    if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_FALSE;  /* in other words: DECREASE */
+    } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    } else {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    }
+
+    /*
+    ** Now we can determine the change in percent
+    */
+    if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    }
+
+    if (IncreaseTimerDuration) {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec +
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    } else {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec -
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    }
+
+    /* 
+    ** Check if we exceed boundaries...
+    */
+    if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) ||
+         (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Cannot change ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+        return;
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Resized ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+    }
+
+    M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+        ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+        ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    /* 
+    ** We do not need to touch any other registers
+    */
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+} 
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationType()
+** Description  : Displays what type of moderation we have
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationType(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) {
+             printk("Static int moderation runs with %i INTS/sec\n",
+                    pAC->DynIrqModInfo.MaxModIntsPerSec);
+        } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+             if (IsIntModEnabled(pAC)) {
+                printk("Dynamic int moderation runs with %i INTS/sec\n",
+                       pAC->DynIrqModInfo.MaxModIntsPerSec);
+             } else {
+                printk("Dynamic int moderation currently not applied\n");
+             }
+        } else {
+             printk("No interrupt moderation selected!\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationMask()
+** Description  : Displays what interrupts are moderated
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationMask(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) {
+            switch (pAC->DynIrqModInfo.MaskIrqModeration) {
+                case IRQ_MASK_TX_ONLY: 
+                   printk("Only Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_ONLY: 
+                   printk("Only Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_ONLY: 
+                   printk("Only special-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_TX_RX: 
+                   printk("Tx- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_RX: 
+                   printk("Special- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_TX: 
+                   printk("Special- and Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_TX_SP:
+                   printk("All Rx-, Tx and special-interrupts are moderated\n");
+                   break;
+                default:
+                   printk("Don't know what is moderated\n");
+                   break;
+            }
+        } else {
+            printk("No specific interrupts masked for moderation\n");
+        }
+    } 
+}
+
+/*******************************************************************************
+** Function     : DisplayDescrRatio
+** Description  : Like the name states...
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplayDescrRatio(SK_AC *pAC) {
+    int TotalMaxNbrDescr = 0;
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+        printk("Ratio descriptors: %i/%i\n",
+               M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr);
+    }
+}
+
+/*******************************************************************************
+**
+** End of file
+**
+*******************************************************************************/

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)