2005-04-16 22:20:36 +00:00
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Name: skdim.c
|
|
|
|
* Project: GEnesis, PCI Gigabit Ethernet Adapter
|
|
|
|
* Version: $Revision: 1.5 $
|
|
|
|
* Date: $Date: 2003/11/28 12:55:40 $
|
|
|
|
* Purpose: All functions to maintain interrupt moderation
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* (C)Copyright 1998-2002 SysKonnect GmbH.
|
|
|
|
* (C)Copyright 2002-2003 Marvell.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* 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.5 2003/11/28 12:55:40 rroesler 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
|
2006-01-09 23:08:17 +00:00
|
|
|
** in the moderation timer might be useful
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* unsigned int NbrCpu = 0; */
|
|
|
|
|
|
|
|
/*
|
|
|
|
** The following lines have been commented out, because
|
|
|
|
** from kernel 2.5.44 onwards, the kernel-owned structure
|
|
|
|
**
|
|
|
|
** struct kernel_stat kstat
|
|
|
|
**
|
|
|
|
** is not marked as an exported symbol in the file
|
|
|
|
**
|
|
|
|
** kernel/ksyms.c
|
|
|
|
**
|
|
|
|
** As a consequence, using this driver as KLM is not possible
|
|
|
|
** and any access of the structure kernel_stat via the
|
|
|
|
** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided.
|
|
|
|
**
|
|
|
|
** The kstat-information might be added again in future
|
|
|
|
** versions of the 2.5.xx kernel, but for the time being,
|
|
|
|
** number of interrupts will serve as indication how much
|
|
|
|
** load we currently have...
|
|
|
|
**
|
|
|
|
** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) {
|
|
|
|
** UserTime = UserTime + kstat_cpu(NbrCpu).cpustat.user;
|
|
|
|
** NiceTime = NiceTime + kstat_cpu(NbrCpu).cpustat.nice;
|
|
|
|
** SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system;
|
|
|
|
** }
|
|
|
|
*/
|
|
|
|
SK_U64 ThresholdInts = 0;
|
|
|
|
SK_U64 IsrCallsPerSec = 0;
|
|
|
|
|
|
|
|
ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec *
|
|
|
|
C_INT_MOD_ENABLE_PERCENTAGE) + 100);
|
|
|
|
IsrCallsPerSec = GetIsrCalls(pAC);
|
|
|
|
if (IsrCallsPerSec >= ThresholdInts) {
|
|
|
|
/*
|
|
|
|
** We do not know how much the real CPU-load is!
|
|
|
|
** Return 80% as a default in order to activate DIM
|
|
|
|
*/
|
|
|
|
SystemLoad = 80;
|
|
|
|
return (SystemLoad);
|
|
|
|
}
|
|
|
|
|
|
|
|
UsedTime = UserTime + NiceTime + SystemTime;
|
|
|
|
|
|
|
|
IdleTime = jif * num_online_cpus() - 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
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|