| /****************************************************************************** |
| * |
| * Name: skdim.c |
| * Project: GEnesis, PCI Gigabit Ethernet Adapter |
| * Version: $Revision: 1.5.2.2 $ |
| * Date: $Date: 2005/05/23 13:47:33 $ |
| * Purpose: All functions regardig interrupt moderation |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * (C)Copyright 1998-2002 SysKonnect GmbH. |
| * (C)Copyright 2002-2005 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 |
| * |
| * 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 <config.h> |
| |
| #ifdef CONFIG_SK98 |
| |
| #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 |
| * |
| ******************************************************************************/ |
| |
| #endif |