| Stephen Hemminger | 5ad887f | 2007-09-15 19:35:14 -0400 | [diff] [blame] | 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 | *******************************************************************************/ |