/****************************************************************************** * * Name: skdim.c * Project: GEnesis, PCI Gigabit Ethernet Adapter * Version: $Revision: 1.5 $ * Date: $Date: 2004/07/17 13:28:43 $ * Purpose: All functions regardig interrupt moderation * ******************************************************************************/ /****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. * (C)Copyright 2002-2004 Marvell. * * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet * Server Adapters. * * Author: Ralph Roesler (rroesler@syskonnect.de) * Mirko Lindner (mlindner@syskonnect.de) * * Address all question to: linux@syskonnect.de * * The technical manual for the adapters is available from SysKonnect's * web pages: www.syskonnect.com * * 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. * *****************************************************************************/ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" /****************************************************************************** * * Local Function Prototypes * *****************************************************************************/ 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); #define M_DIMINFO pAC->DynIrqModInfo /****************************************************************************** * * Global Functions * *****************************************************************************/ /***************************************************************************** * * SkDimModerate - Moderates the IRQs depending on the current needs * * Description: * Moderation of IRQs depends on the number of occurred IRQs with * respect to the previous moderation cycle. * * Returns: N/A * */ void SkDimModerate( SK_AC *pAC) /* pointer to adapter control context */ { SK_U64 IsrCalls = getIsrCalls(pAC); SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==> SkDimModerate\n")); if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { if (isIntModEnabled(pAC)) { if (IsrCalls < M_DIMINFO.MaxModIntsPerSecLowerLimit) { disableIntMod(pAC); } } else { if (IsrCalls > M_DIMINFO.MaxModIntsPerSecUpperLimit) { enableIntMod(pAC); } } } setCurrIntCtr(pAC); SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("<== SkDimModerate\n")); } /***************************************************************************** * * SkDimStartModerationTimer - Starts the moderation timer * * Description: * Dynamic interrupt moderation is regularly checked using the * so-called moderation timer. This timer is started with this function. * * Returns: N/A */ void SkDimStartModerationTimer( SK_AC *pAC) /* pointer to adapter control context */ { SK_EVPARA EventParam; /* Event struct for timer event */ SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("==> SkDimStartModerationTimer\n")); if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) { SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam)); EventParam.Para32[0] = SK_DRV_MODERATION_TIMER; SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer, pAC->DynIrqModInfo.DynIrqModSampleInterval * 1000000, SKGE_DRV, SK_DRV_TIMER, EventParam); } SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== SkDimStartModerationTimer\n")); } /***************************************************************************** * * SkDimEnableModerationIfNeeded - Enables or disables any moderationtype * * Description: * This function effectively initializes the IRQ moderation of a network * adapter. Depending on the configuration, this might be either static * or dynamic. If no moderation is configured, this function will do * nothing. * * Returns: N/A */ void SkDimEnableModerationIfNeeded( SK_AC *pAC) /* pointer to adapter control context */ { SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("==> SkDimEnableModerationIfNeeded\n")); if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_NONE) { if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) { enableIntMod(pAC); } else { /* must be C_INT_MOD_DYNAMIC */ SkDimStartModerationTimer(pAC); } } SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== SkDimEnableModerationIfNeeded\n")); } /***************************************************************************** * * SkDimDisableModeration - disables moderation if it is enabled * * Description: * Disabling of the moderation requires that is enabled already. * * Returns: N/A */ void SkDimDisableModeration( SK_AC *pAC, /* pointer to adapter control context */ int CurrentModeration) /* type of current moderation */ { SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("==> SkDimDisableModeration\n")); if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_NONE) { if (CurrentModeration == C_INT_MOD_STATIC) { disableIntMod(pAC); } else { /* must be C_INT_MOD_DYNAMIC */ SkTimerStop(pAC, pAC->IoBase, &M_DIMINFO.ModTimer); disableIntMod(pAC); } } SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== SkDimDisableModeration\n")); } /****************************************************************************** * * Local Functions * *****************************************************************************/ /***************************************************************************** * * getIsrCalls - evaluate the number of IRQs handled in mod interval * * Description: * Depending on the selected moderation mask, this function will return * the number of interrupts handled in the previous moderation interval. * This evaluated number is based on the current number of interrupts * stored in PNMI-context and the previous stored interrupts. * * Returns: * the number of IRQs handled */ static SK_U64 getIsrCalls( SK_AC *pAC) /* pointer to adapter control context */ { SK_U64 RxPort0IntDiff = 0, RxPort1IntDiff = 0; SK_U64 TxPort0IntDiff = 0, TxPort1IntDiff = 0; SK_U64 StatusPort0IntDiff = 0, StatusPort1IntDiff = 0; SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==>getIsrCalls\n")); if (!CHIP_ID_YUKON_2(pAC)) { if ((M_DIMINFO.MaskIrqModeration == IRQ_MASK_TX_ONLY) || (M_DIMINFO.MaskIrqModeration == IRQ_MASK_SP_TX)) { if (pAC->GIni.GIMacsFound == 2) { TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - M_DIMINFO.PrevPort1TxIntrCts; } TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - M_DIMINFO.PrevPort0TxIntrCts; } else if ((M_DIMINFO.MaskIrqModeration == IRQ_MASK_RX_ONLY) || (M_DIMINFO.MaskIrqModeration == IRQ_MASK_SP_RX)) { if (pAC->GIni.GIMacsFound == 2) { RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - M_DIMINFO.PrevPort1RxIntrCts; } RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - M_DIMINFO.PrevPort0RxIntrCts; } else { if (pAC->GIni.GIMacsFound == 2) { RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - M_DIMINFO.PrevPort1RxIntrCts; TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - M_DIMINFO.PrevPort1TxIntrCts; } RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - M_DIMINFO.PrevPort0RxIntrCts; TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - M_DIMINFO.PrevPort0TxIntrCts; } SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("==>getIsrCalls (!CHIP_ID_YUKON_2)\n")); return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff); } /* ** We have a Yukon2 compliant chipset if we come up to here ** if (pAC->GIni.GIMacsFound == 2) { StatusPort1IntDiff = pAC->Pnmi.Port[1].StatusLeIntrCts - M_DIMINFO.PrevPort1StatusIntrCts; } StatusPort0IntDiff = pAC->Pnmi.Port[0].StatusLeIntrCts - M_DIMINFO.PrevPort0StatusIntrCts; */ SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("==>getIsrCalls (CHIP_ID_YUKON_2)\n")); return (StatusPort0IntDiff + StatusPort1IntDiff); } /***************************************************************************** * * setCurrIntCtr - stores the current number of interrupts * * Description: * Stores the current number of occurred interrupts in the adapter * context. This is needed to evaluate the umber of interrupts within * the moderation interval. * * Returns: N/A * */ static void setCurrIntCtr( SK_AC *pAC) /* pointer to adapter control context */ { SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==>setCurrIntCtr\n")); if (!CHIP_ID_YUKON_2(pAC)) { if (pAC->GIni.GIMacsFound == 2) { M_DIMINFO.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts; M_DIMINFO.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts; } M_DIMINFO.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts; M_DIMINFO.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts; SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== setCurrIntCtr (!CHIP_ID_YUKON_2)\n")); return; } /* ** We have a Yukon2 compliant chipset if we come up to here ** if (pAC->GIni.GIMacsFound == 2) { M_DIMINFO.PrevPort1StatusIntrCts = pAC->Pnmi.Port[1].StatusLeIntrCts; } M_DIMINFO.PrevPort0StatusIntrCts = pAC->Pnmi.Port[0].StatusLeIntrCts; */ SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== setCurrIntCtr (CHIP_ID_YUKON_2)\n")); } /***************************************************************************** * * isIntModEnabled - returns the current state of interrupt moderation * * Description: * This function retrieves the current value of the interrupt moderation * command register. Its content determines whether any moderation is * running or not. * * Returns: * SK_TRUE : IRQ moderation is currently active * SK_FALSE: No IRQ moderation is active */ static SK_BOOL isIntModEnabled( SK_AC *pAC) /* pointer to adapter control context */ { unsigned long CtrCmd; SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==>isIntModEnabled\n")); SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd); if ((CtrCmd & TIM_START) == TIM_START) { SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== isIntModEnabled (SK_TRUE)\n")); return SK_TRUE; } SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG, ("<== isIntModEnabled (SK_FALSE)\n")); return SK_FALSE; } /***************************************************************************** * * enableIntMod - enables the interrupt moderation * * Description: * Enabling the interrupt moderation is done by putting the desired * moderation interval in the B2_IRQM_INI register, specifying the * desired maks in the B2_IRQM_MSK register and finally starting the * IRQ moderation timer using the B2_IRQM_CTRL register. * * Returns: N/A * */ static void enableIntMod( SK_AC *pAC) /* pointer to adapter control context */ { unsigned long ModBase; SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==> enableIntMod\n")); if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) { ModBase = C_CLK_FREQ_GENESIS / M_DIMINFO.MaxModIntsPerSec; } else if (pAC->GIni.GIChipId == CHIP_ID_YUKON_EC) { ModBase = C_CLK_FREQ_YUKON_EC / M_DIMINFO.MaxModIntsPerSec; } else { ModBase = C_CLK_FREQ_YUKON / M_DIMINFO.MaxModIntsPerSec; } SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase); SK_OUT32(pAC->IoBase, B2_IRQM_MSK, M_DIMINFO.MaskIrqModeration); SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START); SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("<== enableIntMod\n")); } /***************************************************************************** * * disableIntMod - disables the interrupt moderation * * Description: * Disabling the interrupt moderation is done by stopping the * IRQ moderation timer using the B2_IRQM_CTRL register. * * Returns: N/A * */ static void disableIntMod( SK_AC *pAC) /* pointer to adapter control context */ { SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("==> disableIntMod\n")); SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP); SK_DBG_MSG(pAC,SK_DBGMOD_DRV,SK_DBGCAT_DRV_MSG,("<== disableIntMod\n")); } /******************************************************************************* * * End of file * ******************************************************************************/