📄 skgesirq.c
字号:
/****************************************************************************** * * Name: skgesirq.c * Project: Gigabit Ethernet Adapters, Common Modules * Version: $Revision: 2.42 $ * Date: $Date: 2008/03/26 15:37:23 $ * Purpose: Special IRQ module * ******************************************************************************//****************************************************************************** * * LICENSE: * (C)Copyright 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. * /LICENSE * ******************************************************************************//* * Special Interrupt handler * * The following abstract should show how this module is included * in the driver path: * * In the ISR of the driver the bits for frame transmission complete and * for receive complete are checked and handled by the driver itself. * The bits of the slow path mask are checked after that and then the * entry into the so-called "slow path" is prepared. It is an implementors * decision whether this is executed directly or just scheduled by * disabling the mask. In the interrupt service routine some events may be * generated, so it would be a good idea to call the EventDispatcher * right after this ISR. * * The Interrupt source register of the adapter is NOT read by this module. * SO if the drivers implementor needs a while loop around the * slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for * each loop entered. * * However, the MAC Interrupt status registers are read in a while loop. * */#include "h/skdrv1st.h" /* Driver Specific Definitions */#ifndef SK_SLIM#include "h/skgepnmi.h" /* PNMI Definitions */#include "h/skrlmt.h" /* RLMT Definitions */#endif#include "h/skdrv2nd.h" /* Adapter Control and Driver specific Def. *//* local variables ************************************************************/#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))static const char SysKonnectFileId[] = "@(#) $Id: skgesirq.c,v 2.42 2008/03/26 15:37:23 rschmidt Exp $ (C) Marvell.";#endif/* local function prototypes */static int SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL);static void SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);#ifdef __C2MAN__/* * Special IRQ function * * General Description: * */intro(){}#endif#ifndef SK_SLIM/****************************************************************************** * * SkHWInitDefSense() - Default Autosensing mode initialization * * Description: sets the PLinkMode for HWInit * * Returns: N/A */static void SkHWInitDefSense(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O context */int Port) /* Port Index (MAC_1 + n) */{ SK_GEPORT *pPrt; /* GIni Port struct pointer */ pPrt = &pAC->GIni.GP[Port]; pPrt->PAutoNegTimeOut = 0; if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) { pPrt->PLinkMode = pPrt->PLinkModeConf; return; } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("AutoSensing: First mode %d on Port %d\n", (int)SK_LMODE_AUTOFULL, Port)); pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL; return;} /* SkHWInitDefSense */#endif/****************************************************************************** * * SkHWLinkDown() - Link Down handling * * Description: handles the hardware link down signal * * Returns: N/A */void SkHWLinkDown(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O context */int Port) /* Port Index (MAC_1 + n) */{ SK_GEPORT *pPrt; /* GIni Port struct pointer */ pPrt = &pAC->GIni.GP[Port]; /* Disable all MAC interrupts */ SkMacIrqDisable(pAC, IoC, Port); /* Disable Receiver and Transmitter */ SkMacRxTxDisable(pAC, IoC, Port);#ifndef SK_SLIM /* Init default sense mode */ SkHWInitDefSense(pAC, IoC, Port);#endif if (!pPrt->PHWLinkUp) { return; } SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Link down Port %d\n", Port)); /* Set Link to DOWN */ pPrt->PHWLinkUp = SK_FALSE;#ifndef SK_SLIM /* Reset Port stati */ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE; pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED;#endif /* !SK_SLIM */ /* Re-init PHY especially when the AutoSense default is set now */ SkMacInitPhy(pAC, IoC, Port, SK_FALSE); /* GP0: used for workaround of Rev. C Errata 2 */ /* Do NOT signal to RLMT */ /* Do NOT start the timer here */} /* SkHWLinkDown *//****************************************************************************** * * SkHWLinkUp() - Link Up handling * * Description: handles the hardware link up signal * * Returns: N/A */void SkHWLinkUp(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O context */int Port) /* Port Index (MAC_1 + n) */{ SK_GEPORT *pPrt; /* GIni Port struct pointer */ pPrt = &pAC->GIni.GP[Port]; if (pPrt->PHWLinkUp) { /* We do NOT need to proceed on active link */ return; } pPrt->PHWLinkUp = SK_TRUE;#ifndef SK_SLIM pPrt->PAutoNegFail = SK_FALSE; pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN; if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF && pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL && pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) { /* Link is up and no Auto-negotiation should be done */ /* Link speed should be the configured one */ switch (pPrt->PLinkSpeed) { case SK_LSPEED_AUTO: /* default is 1000 Mbps */ case SK_LSPEED_1000MBPS: pPrt->PLinkSpeedUsed = (SK_U8) ((pPrt->PLinkSpeedCap & SK_LSPEED_CAP_1000MBPS) != 0) ? SK_LSPEED_STAT_1000MBPS : SK_LSPEED_STAT_100MBPS; break; case SK_LSPEED_100MBPS: pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS; break; case SK_LSPEED_10MBPS: pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS; break; } /* Set Link Mode Status */ pPrt->PLinkModeStatus = (SK_U8)((pPrt->PLinkMode == SK_LMODE_FULL) ? SK_LMODE_STAT_FULL : SK_LMODE_STAT_HALF); /* No flow control without auto-negotiation */ pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;#endif /* !SK_SLIM */ /* enable Rx/Tx */ (void)SkMacRxTxEnable(pAC, IoC, Port);#ifndef SK_SLIM }#endif /* !SK_SLIM */} /* SkHWLinkUp *//****************************************************************************** * * SkMacParity() - MAC parity workaround * * Description: handles MAC parity errors correctly * * Returns: N/A */static void SkMacParity(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O context */int Port) /* Port Index (MAC_1 + n) */{ SK_EVPARA Para; SK_GEPORT *pPrt; /* GIni Port struct pointer */ SK_U32 TxMax; /* Tx Max Size Counter */ TxMax = 0; pPrt = &pAC->GIni.GP[Port]; /* clear IRQ Tx Parity Error */ /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE)); if (pPrt->PCheckPar) { if (Port == MAC_1) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG); } Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = Port; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); return; } /* Check whether frames with a size of 1k were sent */ (void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax); if (TxMax > 0) { /* From now on check the parity */ pPrt->PCheckPar = SK_TRUE; }} /* SkMacParity */#ifndef DISABLE_YUKON_I/****************************************************************************** * * SkGeYuHwErr() - Hardware Error service routine (Genesis and Yukon) * * Description: handles all HW Error interrupts * * Returns: N/A */static void SkGeYuHwErr(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O context */SK_U32 HwStatus) /* Interrupt status word */{ SK_EVPARA Para; SK_U16 Word; SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("HW-Error Status: 0x%08lX\n", HwStatus)); if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) { /* PCI Errors occurred */ if ((HwStatus & IS_IRQ_STAT) != 0) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG); } /* Reset all bits in the PCI STATUS register */ SK_IN16(IoC, PCI_C(pAC, PCI_STATUS), &Word); SK_TST_MODE_ON(IoC); SK_OUT16(IoC, PCI_C(pAC, PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS)); SK_TST_MODE_OFF(IoC); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } /* This is necessary only for Rx timing measurements */ if ((HwStatus & IS_IRQ_TIST_OV) != 0) { /* increment Time Stamp Timer counter (high) */#ifndef SK_SLIM pAC->GIni.GITimeStampCnt++;#endif /* clear Time Stamp Timer IRQ */ SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ); } if ((HwStatus & IS_IRQ_SENSOR) != 0) { /* no sensors on 32-bit Yukon */ if (pAC->GIni.GIYukon32Bit) { /* disable HW Error IRQ */ pAC->GIni.GIValIrqMask &= ~IS_HW_ERR; } } if ((HwStatus & IS_RAM_RD_PAR) != 0) { SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR); SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } if ((HwStatus & IS_RAM_WR_PAR) != 0) { SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR); SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } if ((HwStatus & IS_M1_PAR_ERR) != 0) { SkMacParity(pAC, IoC, MAC_1); } if ((HwStatus & IS_M2_PAR_ERR) != 0) { SkMacParity(pAC, IoC, MAC_2); } if ((HwStatus & IS_R1_PAR_ERR) != 0) { /* Clear IRQ */ SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P); SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG); Para.Para64 = MAC_1; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); } if ((HwStatus & IS_R2_PAR_ERR) != 0) { /* Clear IRQ */ SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P); SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG); Para.Para64 = MAC_2; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_2; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); }} /* SkGeYuHwErr */#endif /* !DISABLE_YUKON_I */#ifdef YUK2/****************************************************************************** * * SkYuk2HwPortErr() - Service HW Errors for specified port (Yukon-2 only) * * Description: handles the HW Error interrupts for a specific port. * * Returns: N/A */static void SkYuk2HwPortErr(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O Context */SK_U32 HwStatus, /* Interrupt status word */int Port) /* Port Index (MAC_1 + n) */{ SK_EVPARA Para; int Queue; if (Port == MAC_2) { HwStatus >>= 8; } if ((HwStatus & Y2_HWE_L1_MASK) == 0) { return; } if ((HwStatus & Y2_IS_PAR_RD1) != 0) { /* Clear IRQ */ SK_OUT16(IoC, SELECT_RAM_BUFFER(Port, B3_RI_CTRL), RI_CLR_RD_PERR); if (Port == MAC_1) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E028, SKERR_SIRQ_E028MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E030, SKERR_SIRQ_E030MSG); } } if ((HwStatus & Y2_IS_PAR_WR1) != 0) { /* Clear IRQ */ SK_OUT16(IoC, SELECT_RAM_BUFFER(Port, B3_RI_CTRL), RI_CLR_WR_PERR); if (Port == MAC_1) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E029, SKERR_SIRQ_E029MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E031, SKERR_SIRQ_E031MSG); } } if ((HwStatus & Y2_IS_PAR_MAC1) != 0) { /* Clear IRQ */ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), GMF_CLI_TX_PE); if (Port == MAC_1) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG); } } if ((HwStatus & Y2_IS_PAR_RX1) != 0) { if (Port == MAC_1) { Queue = Q_R1; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG); } else { Queue = Q_R2; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG); } /* Clear IRQ */ SK_OUT32(IoC, Q_ADDR(Queue, Q_CSR), BMU_CLR_IRQ_PAR); } if ((HwStatus & Y2_IS_TCP_TXS1) != 0) { if (Port == MAC_1) { Queue = Q_XS1; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E033, SKERR_SIRQ_E033MSG); } else { Queue = Q_XS2; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E035, SKERR_SIRQ_E035MSG); } /* Clear IRQ */ SK_OUT32(IoC, Q_ADDR(Queue, Q_CSR), BMU_CLR_IRQ_TCP); } if ((HwStatus & Y2_IS_TCP_TXA1) != 0) { if (Port == MAC_1) { Queue = Q_XA1; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E032, SKERR_SIRQ_E032MSG); } else { Queue = Q_XA2; SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E034, SKERR_SIRQ_E034MSG); } /* Clear IRQ */ SK_OUT32(IoC, Q_ADDR(Queue, Q_CSR), BMU_CLR_IRQ_TCP); } Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = Port; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);} /* SkYuk2HwPortErr *//****************************************************************************** * * SkYuk2HwErr() - Hardware Error service routine (Yukon-2 only) * * Description: handles all HW Error interrupts * * Returns: N/A */static void SkYuk2HwErr(SK_AC *pAC, /* Adapter Context */SK_IOC IoC, /* I/O Context */SK_U32 HwStatus) /* Interrupt status word */{ SK_EVPARA Para; SK_U16 Word; SK_U32 DWord; SK_U32 TlpHead[4]; int i; SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("HW-Error Status: 0x%08lX\n", HwStatus)); /* This is necessary only for Rx timing measurements */ if ((HwStatus & Y2_IS_TIST_OV) != 0) {#ifndef SK_SLIM /* increment Time Stamp Timer counter (high) */ pAC->GIni.GITimeStampCnt++;#endif /* clear Time Stamp Timer IRQ */ SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ); } /* Evaluate Y2_IS_PCI_NEXP before Y2_IS_MST_ERR or Y2_IS_IRQ_STAT */ if ((HwStatus & Y2_IS_PCI_NEXP) != 0) { /* * This error is also mapped either to Master Abort (Y2_IS_MST_ERR) * or Target Abort (Y2_IS_IRQ_STAT) bit and can only be cleared there. * Therefore handle this event just by printing an error log entry. */ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E027, SKERR_SIRQ_E027MSG); } if ((HwStatus & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) != 0) { /* PCI Errors occurred */ if ((HwStatus & Y2_IS_IRQ_STAT) != 0) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG); } /* Reset all bits in the PCI STATUS register */ SK_IN16(IoC, PCI_C(pAC, PCI_STATUS), &Word); SK_TST_MODE_ON(IoC); SK_OUT16(IoC, PCI_C(pAC, PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS)); SK_TST_MODE_OFF(IoC); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } /* check for PCI-Express Uncorrectable Error*/ if ((HwStatus & Y2_IS_PCI_EXP) != 0) { /* * On PCI-Express bus bridges are called root complexes (RC). * PCI-Express errors are recognized by the root complex too, * which requests the system to handle the problem. After error * occurence it may be that no access to the adapter may be performed * any longer. */ /* Get uncorrectable error status */ SK_IN32(IoC, PCI_C(pAC, PEX_UNC_ERR_STAT), &DWord); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("PEX Uncorr.Error Status: 0x%08lX\n", DWord)); if (DWord != PEX_UNSUP_REQ) { /* ignore Unsupported Request Errors */ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E026, SKERR_SIRQ_E026MSG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -